How to send a SMS using SMSmanager in Dual SIM mobile?
Asked Answered
K

4

25

Am using SMS manager to send SMS.For single SIM its works perfectly to send the SMS.but in dual SIM the SMS will not send.Is it possible to send the SMS from dual SIM,if possible means how can i select the Which SIM to send SMS.Can any one know help me to solve this issue.

Single SIM working Code

SmsManager smsManager = SmsManager.getDefault();
smsManager.sendTextMessage(ph_number, null, body, null,null);
Keldon answered 8/12, 2014 at 5:29 Comment(9)
this maybe the thing you are looking for #24008385Templar
May be you will find the solution here. #14276828Xavler
@MurtazaHussain i want to do all thing in my coding itself.Is it possible.Keldon
yeah it is. find the number scAddress and pass it to your code.Xavler
@MurtazaHussain but in that answer they said. Apparently there doesn't seem to be a way to programmatically get the numberKeldon
well, there is no official documentation by Android on dual sim support, devices which do support this feature are manufactured dependent. You need to contact the device manufacturer for specific APIXavler
you can do this by using intent. but it's not send sms in background.Stun
@KrunalIndrodiya to open and send it in default SMS application.Keldon
@Keldon ya it's perfect idea, so user can select no which, no to send sms. Hope you got the point.Stun
S
53

I use this way to manage which sim to use for sending SMS even long message .. Its working on my dual sim phone Lenovo A319 (4.4.3), no need for root. its built on reflection.

import android.app.PendingIntent;
import android.content.Context;
import android.os.Build;
import android.os.IBinder;
import android.util.Log;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

/**
 * Created by Apipas on 6/4/15.
 */
public class SimUtil {

    public static boolean sendSMS(Context ctx, int simID, String toNum, String centerNum, String smsText, PendingIntent sentIntent, PendingIntent deliveryIntent) {
        String name;

        try {
            if (simID == 0) {
                name = "isms";
                // for model : "Philips T939" name = "isms0"
            } else if (simID == 1) {
                name = "isms2";
            } else {
                throw new Exception("can not get service which for sim '" + simID + "', only 0,1 accepted as values");
            }
            Method method = Class.forName("android.os.ServiceManager").getDeclaredMethod("getService", String.class);
            method.setAccessible(true);
            Object param = method.invoke(null, name);

            method = Class.forName("com.android.internal.telephony.ISms$Stub").getDeclaredMethod("asInterface", IBinder.class);
            method.setAccessible(true);
            Object stubObj = method.invoke(null, param);
            if (Build.VERSION.SDK_INT < 18) {
                method = stubObj.getClass().getMethod("sendText", String.class, String.class, String.class, PendingIntent.class, PendingIntent.class);
                method.invoke(stubObj, toNum, centerNum, smsText, sentIntent, deliveryIntent);
            } else {
                method = stubObj.getClass().getMethod("sendText", String.class, String.class, String.class, String.class, PendingIntent.class, PendingIntent.class);
                method.invoke(stubObj, ctx.getPackageName(), toNum, centerNum, smsText, sentIntent, deliveryIntent);
            }

            return true;
        } catch (ClassNotFoundException e) {
            Log.e("apipas", "ClassNotFoundException:" + e.getMessage());
        } catch (NoSuchMethodException e) {
            Log.e("apipas", "NoSuchMethodException:" + e.getMessage());
        } catch (InvocationTargetException e) {
            Log.e("apipas", "InvocationTargetException:" + e.getMessage());
        } catch (IllegalAccessException e) {
            Log.e("apipas", "IllegalAccessException:" + e.getMessage());
        } catch (Exception e) {
            Log.e("apipas", "Exception:" + e.getMessage());
        }
        return false;
    }


    public static boolean sendMultipartTextSMS(Context ctx, int simID, String toNum, String centerNum, ArrayList<String> smsTextlist, ArrayList<PendingIntent> sentIntentList, ArrayList<PendingIntent> deliveryIntentList) {
        String name;
        try {
            if (simID == 0) {
                name = "isms";
                // for model : "Philips T939" name = "isms0"
            } else if (simID == 1) {
                name = "isms2";
            } else {
                throw new Exception("can not get service which for sim '" + simID + "', only 0,1 accepted as values");
            }
            Method method = Class.forName("android.os.ServiceManager").getDeclaredMethod("getService", String.class);
            method.setAccessible(true);
            Object param = method.invoke(null, name);

            method = Class.forName("com.android.internal.telephony.ISms$Stub").getDeclaredMethod("asInterface", IBinder.class);
            method.setAccessible(true);
            Object stubObj = method.invoke(null, param);
            if (Build.VERSION.SDK_INT < 18) {
                method = stubObj.getClass().getMethod("sendMultipartText", String.class, String.class, List.class, List.class, List.class);
                method.invoke(stubObj, toNum, centerNum, smsTextlist, sentIntentList, deliveryIntentList);
            } else {
                method = stubObj.getClass().getMethod("sendMultipartText", String.class, String.class, String.class, List.class, List.class, List.class);
                method.invoke(stubObj, ctx.getPackageName(), toNum, centerNum, smsTextlist, sentIntentList, deliveryIntentList);
            }
            return true;
        } catch (ClassNotFoundException e) {
            Log.e("apipas", "ClassNotFoundException:" + e.getMessage());
        } catch (NoSuchMethodException e) {
            Log.e("apipas", "NoSuchMethodException:" + e.getMessage());
        } catch (InvocationTargetException e) {
            Log.e("apipas", "InvocationTargetException:" + e.getMessage());
        } catch (IllegalAccessException e) {
            Log.e("apipas", "IllegalAccessException:" + e.getMessage());
        } catch (Exception e) {
            Log.e("apipas", "Exception:" + e.getMessage());
        }
        return false;
    }


}

Add permission:

<uses-permission android:name="android.permission.SEND_SMS"/>

then just call that (bloody) static method like this :)

To use SIM1:

SimUtil.sendSMS(this,0,"00970XXXXXXXXX",null,"Hi Stackoverflow! its me Maher. Sent by sim1",null,null);

To use SIM2:

SimUtil.sendSMS(this,1,"00970XXXXXXXXX",null,"Hi Stackoverflow! its me Maher. Sent by sim2",null,null);

But wait...that won't work if message is longer than 160 characters.. so better way:

String textSMS;
//short <160
//    textSMS = "Hi Stackoverflow! its me Maher.";


//long >160
textSMS = "Hi Jerusalem, hi Cairo, Hi Prague, hi Baghdad, hi Riyadh, hi Jeddah, hi Dammam, hi Aleppo, hi Casablanca, hi Damascus, hi Alexandria, hi Algiers, hi Mosul, hi Basra, hi Arabia, hi Tripoli, hi Amman, hi Kuwait, hi Beirut, hi Abu Dhabi";

int simID = 0;//0:sim_1,   1:sim_2

ArrayList<String> messageList = SmsManager.getDefault().divideMessage(textSMS);
if (messageList.size() > 1) {
    SimUtil.sendMultipartTextSMS(this, simID, "00972XXXXXXXXX", null, messageList, null, null);
} else {
    SimUtil.sendSMS(this, simID, "00972XXXXXXXXX", null, textSMS, null, null);
}

so you can safely pass message body without worrying about length.

------------UPDATE 09.10.2016----------

To use PendingIntent/DeliveryIntent in MultipartMessage.. just create ArrayList with same content and pass it. Here is an implementation of creating List of PendingIntent:

final static String sSMSManagerIntentSENT = "package.DeliveryReport.SMS_SENT";
int numParts = parts.size();
ArrayList<PendingIntent> pendingIntents = new ArrayList<PendingIntent>();

for (int i = 0; i < numParts; i++) {

    Intent pendingIntent = new Intent(sSMSManagerIntentSENT); 
    //optional if you want to keep info about what action has been done for feedback or analysis later when message is sent
    pendingIntent.putExtra("package.DeliveryReport.phoneNumber", phoneNo); // receiver phoneNo
    pendingIntent.putExtra("package.DeliveryReport.textSMS", msg);// msg body
    pendingIntent.putExtra("SIM", simID); // which sim is sending this message

    pendingIntents.add(PendingIntent.getBroadcast(getActivity(), 0, pendingIntent,PendingIntent.FLAG_ONE_SHOT));
}

For deliver,just use the same approach.

------------------ Extra ------------------

I have seen that Android 22 supports multi sim cards from Android 5.1 and here is how to use it .. unfortunately I don't have device with that version for testing, so please for feedback:

SmsManager.getSmsManagerForSubscriptionId(int subscriptionId).sendTextMessage(String destinationAddress, String scAddress, String text,PendingIntent sentIntent, PendingIntent deliveryIntent);

How to get subscriptionId? to review all available subscriptionID that belong to sim card:

SubscriptionManager subscriptionManager = SubscriptionManager.from(getApplicationContext());
        List<SubscriptionInfo> subscriptionInfoList = subscriptionManager.getActiveSubscriptionInfoList();
        for (SubscriptionInfo subscriptionInfo : subscriptionInfoList) {
            int subscriptionId = subscriptionInfo.getSubscriptionId();
            Log.d("apipas","subscriptionId:"+subscriptionId);
        }

** Please note that this code is working on 5.1. if you try to run it on older version you'd get an exception that method doesn't exist.

------------UPDATE 19.8.2015----------

Information on SIMs, are located in DB: telephony.db (by default: /data/data/com.android.providers.telephony/databases/telephony.db ) in table siminfo. See screenshot on table siminfo in DB on real device.

enter image description here

Fortunately there is a content provider for that:

"content://telephony/siminfo/"

So basically just query data from that table.Its important to mention that slot 0 represents SIM1, and 1 represents SIM2, and slot -1 from old/removed/replaced SIMs.

This applies on Lenovo A319 . I guess that may work on other devices. Here is the util method I use:

public static List<SimInfo> getSIMInfo(Context context) {
        List<SimInfo> simInfoList = new ArrayList<>();
        Uri URI_TELEPHONY = Uri.parse("content://telephony/siminfo/");
        Cursor c = context.getContentResolver().query(URI_TELEPHONY, null, null, null, null);
        if (c.moveToFirst()) {
            do {
                int id = c.getInt(c.getColumnIndex("_id"));
                int slot = c.getInt(c.getColumnIndex("slot"));
                String display_name = c.getString(c.getColumnIndex("display_name"));
                String icc_id = c.getString(c.getColumnIndex("icc_id"));
                SimInfo simInfo = new SimInfo(id, display_name, icc_id, slot);
                Log.d("apipas_sim_info", simInfo.toString());
                simInfoList.add(simInfo);
            } while (c.moveToNext());
        }
        c.close();

        return simInfoList;
    }

and here is the entity class SimInfo:

public class SimInfo {
    private int id_;
    private String display_name;
    private String icc_id;
    private int slot;

    public SimInfo(int id_, String display_name, String icc_id, int slot) {
        this.id_ = id_;
        this.display_name = display_name;
        this.icc_id = icc_id;
        this.slot = slot;
    }

    public int getId_() {
        return id_;
    }

    public String getDisplay_name() {
        return display_name;
    }

    public String getIcc_id() {
        return icc_id;
    }

    public int getSlot() {
        return slot;
    }

    @Override
    public String toString() {
        return "SimInfo{" +
                "id_=" + id_ +
                ", display_name='" + display_name + '\'' +
                ", icc_id='" + icc_id + '\'' +
                ", slot=" + slot +
                '}';
    }
}

Good luck,'.

Submediant answered 6/6, 2015 at 0:8 Comment(14)
Great but how can i get information about sim1 and sim2 ? I want to send text using specific operator only, lets say AT&T. do you have any idea how to find out information about each sim card?Marlin
Hi Alireza, see my updated answer. I included util I use for that purpose.Submediant
thank you very much i will definitely give it a try.Marlin
when i tried this one.. sms is sending only sim1 only.. can u give any overall working source code plsWichman
@harikrishnan, pass 1 as parameter for simID to be able to send message via Sim2, since 0:sim1, sim2:1 ... you have same source code I have .. there is no more code related to dual-sim sms-ingSubmediant
thanks for your nice answer! how can i have pending intent for multi part text message? could you help me please?Chingchinghai
@Chingchinghai I have updated my answer .. see update 09.10.2016Submediant
@maherAbuthraa. in android 6 marshmallow it gives me "NoSuchMethodException:sendText " . could you please help me what to do?Chingchinghai
Because in Android 22 and above it has own implementation of Dual .. and not using that reflection see my answer under EXTRA subtitle.Submediant
@MaherAbuthraa,i got NullpointerException for 'stubObj' in sendSMS() method.Paresh
@Paresh what API you are using ? this reflection code wont work with API-22 and aboveSubmediant
I m using API 23,i have no problem with API>=22(another code working properly),i want solution for the API<22,So Please help me.Paresh
it says "NoSuchMethodException:sendText " for android version 7.0. what should i do?Madness
not exist "slot" Column instead exist sim_id Column in "content://telephony/siminfo/"Wealthy
C
2

I tried Mahers Refletion method for sending sms in dual sim android phone(API 19 and below). The chipset in the smartphone was from Spreadtrum. I encountered exceptions with Maher's code, first it was Null Pointer exception, in the name = isms2. For me, sim1 was isms0 and sim2 was isms1, I retrieved this information in the dumpsys. With much debugging and some more searching following code worked for me:

public class SimUtil {

public static boolean sendSMS(Context ctx, int simID, String toNum, String centerNum, String smsText, PendingIntent sentIntent, PendingIntent deliveryIntent) {
    String name;

    try {
        if (simID == 0) {
            name = "isms0";
        } else if (simID == 1) {
            name = "isms1";
        } else {
            throw new Exception("can not get service which for sim '" + simID + "', only 0,1 accepted as values");
        }

        try
        {
            Method method = Class.forName("android.os.ServiceManager").getDeclaredMethod("getService", new Class[]{String.class});
            method.setAccessible(true);
            Object param = method.invoke(null, new Object[]{name});
            if (param == null)
            {
                throw new RuntimeException("can not get service which is named '" + name + "'");
            }
            method = Class.forName("com.android.internal.telephony.ISms$Stub").getDeclaredMethod("asInterface", new Class[]{IBinder.class});
            method.setAccessible(true);
            Object stubObj = method.invoke(null, new Object[]{param});
            method = stubObj.getClass().getMethod("sendText", String.class, String.class, String.class, String.class, PendingIntent.class, PendingIntent.class);
            method.invoke(stubObj, ctx.getPackageName(), toNum, centerNum, smsText, sentIntent, deliveryIntent);
        } catch (ClassNotFoundException e)
        {
            throw new RuntimeException(e);
        } catch (NoSuchMethodException e)
        {
            throw new RuntimeException(e);
        } catch (InvocationTargetException e)
        {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e)
        {
            throw new RuntimeException(e);
        }

        return true;
    } catch (ClassNotFoundException e) {
        Log.e("Exception", "ClassNotFoundException:" + e.getMessage());
    } catch (NoSuchMethodException e) {
        Log.e("Exception", "NoSuchMethodException:" + e.getMessage());
    } catch (InvocationTargetException e) {
        Log.e("Exception", "InvocationTargetException:" + e.getMessage());
    } catch (IllegalAccessException e) {
        Log.e("Exception", "IllegalAccessException:" + e.getMessage());
    } catch (Exception e) {
        Log.e("Exception", "Exception:" + e);
    }
    return false;
}

}

Following links maybe helpfull:

Coy answered 26/3, 2016 at 12:16 Comment(0)
I
2

Maher's solution is almost right.

I tried it on Motorola motog 5.1 android (single sim), but his solution with reading table content://telephony/siminfo had one slight bug:

on my motorola there was no field slot but sim_id

rest of this was fine and identical.

Influx answered 21/7, 2016 at 20:33 Comment(0)
V
2

with regard to @Vibhav solution, here is how I could successfully implement it

method = Class.forName("android.telephony.SubscriptionManager").getDeclaredMethod("getSubId", int.class);
method.setAccessible(true);
int simID = 1; //while simID is the slot number of your second simCard
param = (int[]) method.invoke(null, new Integer(simID));
int inst =  param[0];
smsMan = SmsManager.getSmsManagerForSubscriptionId(inst);
smsMan.sendTextMessage(toNum, null, smsText, null, null);

This solution worked fine with me, but I would highly recommend this much cleaner solution (no reflection needed, works for API level 22+) found here https://mcmap.net/q/89392/-option-to-send-sms-using-sim1-or-sim2-programmatically

Ventris answered 20/9, 2018 at 22:17 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.