Android: comprueba si el teléfono tiene doble SIM
Después de mucha investigación en foros, ahora sé que no hay forma de encontrar el número de serie IMSI o SIM para ambas tarjetas SIM en un teléfono con doble SIM (excepto contactar al fabricante). Ahora mi pregunta modificada es: ¿podemos detectar que el teléfono tiene dos tarjetas SIM? Creo que se puede detectar con algo de inteligencia. Pocas formas en las que puedo pensar son:
Marcar un código USSD y rastrear los registros para el número IMEI (probé esto con *139# en India. Funcionó). Esto me dará el número IMEI para la SIM desde la cual marqué el código USSD. (Se supone que el teléfono sigue las pautas de Android y tiene dos números IMEI).
Almacenamiento del número de serie de la SIM y/o IMSI de la SIM. Y después de la detección de cualquier otro número IMSI/serie, incluso si el teléfono no se reinició (es decir, se cambió la SIM) mediante el seguimiento de algunos registros o mediante algún manejo de eventos de transmisión.
Al marcar *06# podrás ver ambos números IMEI. De alguna manera, consigue esos dos números. (Algo así como captura de pantalla y análisis de imágenes para texto).
Si alguien puede pensar en otras formas, será bienvenido. Realmente agradecería cualquier tipo de ayuda con respecto a esto. Además, si alguien tiene alguna información sobre las API de algún fabricante o enlaces para contactarlos, compártala con la gente de la comunidad.
Actualización 23 de marzo'15:
La API oficial de múltiples SIM ya está disponible desde Android 5.1 en adelante
Otra opción posible:
Puede utilizar la reflexión de Java para obtener ambos números IMEI.
Usando estos números IMEI puedes comprobar si el teléfono es DUAL SIM o no.
Pruebe la siguiente actividad:
import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TelephonyInfo telephonyInfo = TelephonyInfo.getInstance(this);
String imeiSIM1 = telephonyInfo.getImsiSIM1();
String imeiSIM2 = telephonyInfo.getImsiSIM2();
boolean isSIM1Ready = telephonyInfo.isSIM1Ready();
boolean isSIM2Ready = telephonyInfo.isSIM2Ready();
boolean isDualSIM = telephonyInfo.isDualSIM();
TextView tv = (TextView) findViewById(R.id.tv);
tv.setText(" IME1 : " + imeiSIM1 + "\n" +
" IME2 : " + imeiSIM2 + "\n" +
" IS DUAL SIM : " + isDualSIM + "\n" +
" IS SIM1 READY : " + isSIM1Ready + "\n" +
" IS SIM2 READY : " + isSIM2Ready + "\n");
}
}
Y aquí está TelephonyInfo.java
:
import java.lang.reflect.Method;
import android.content.Context;
import android.telephony.TelephonyManager;
public final class TelephonyInfo {
private static TelephonyInfo telephonyInfo;
private String imeiSIM1;
private String imeiSIM2;
private boolean isSIM1Ready;
private boolean isSIM2Ready;
public String getImsiSIM1() {
return imeiSIM1;
}
/*public static void setImsiSIM1(String imeiSIM1) {
TelephonyInfo.imeiSIM1 = imeiSIM1;
}*/
public String getImsiSIM2() {
return imeiSIM2;
}
/*public static void setImsiSIM2(String imeiSIM2) {
TelephonyInfo.imeiSIM2 = imeiSIM2;
}*/
public boolean isSIM1Ready() {
return isSIM1Ready;
}
/*public static void setSIM1Ready(boolean isSIM1Ready) {
TelephonyInfo.isSIM1Ready = isSIM1Ready;
}*/
public boolean isSIM2Ready() {
return isSIM2Ready;
}
/*public static void setSIM2Ready(boolean isSIM2Ready) {
TelephonyInfo.isSIM2Ready = isSIM2Ready;
}*/
public boolean isDualSIM() {
return imeiSIM2 != null;
}
private TelephonyInfo() {
}
public static TelephonyInfo getInstance(Context context){
if(telephonyInfo == null) {
telephonyInfo = new TelephonyInfo();
TelephonyManager telephonyManager = ((TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE));
telephonyInfo.imeiSIM1 = telephonyManager.getDeviceId();;
telephonyInfo.imeiSIM2 = null;
try {
telephonyInfo.imeiSIM1 = getDeviceIdBySlot(context, "getDeviceIdGemini", 0);
telephonyInfo.imeiSIM2 = getDeviceIdBySlot(context, "getDeviceIdGemini", 1);
} catch (GeminiMethodNotFoundException e) {
e.printStackTrace();
try {
telephonyInfo.imeiSIM1 = getDeviceIdBySlot(context, "getDeviceId", 0);
telephonyInfo.imeiSIM2 = getDeviceIdBySlot(context, "getDeviceId", 1);
} catch (GeminiMethodNotFoundException e1) {
//Call here for next manufacturer's predicted method name if you wish
e1.printStackTrace();
}
}
telephonyInfo.isSIM1Ready = telephonyManager.getSimState() == TelephonyManager.SIM_STATE_READY;
telephonyInfo.isSIM2Ready = false;
try {
telephonyInfo.isSIM1Ready = getSIMStateBySlot(context, "getSimStateGemini", 0);
telephonyInfo.isSIM2Ready = getSIMStateBySlot(context, "getSimStateGemini", 1);
} catch (GeminiMethodNotFoundException e) {
e.printStackTrace();
try {
telephonyInfo.isSIM1Ready = getSIMStateBySlot(context, "getSimState", 0);
telephonyInfo.isSIM2Ready = getSIMStateBySlot(context, "getSimState", 1);
} catch (GeminiMethodNotFoundException e1) {
//Call here for next manufacturer's predicted method name if you wish
e1.printStackTrace();
}
}
}
return telephonyInfo;
}
private static String getDeviceIdBySlot(Context context, String predictedMethodName, int slotID) throws GeminiMethodNotFoundException {
String imei = null;
TelephonyManager telephony = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
try{
Class<?> telephonyClass = Class.forName(telephony.getClass().getName());
Class<?>[] parameter = new Class[1];
parameter[0] = int.class;
Method getSimID = telephonyClass.getMethod(predictedMethodName, parameter);
Object[] obParameter = new Object[1];
obParameter[0] = slotID;
Object ob_phone = getSimID.invoke(telephony, obParameter);
if(ob_phone != null){
imei = ob_phone.toString();
}
} catch (Exception e) {
e.printStackTrace();
throw new GeminiMethodNotFoundException(predictedMethodName);
}
return imei;
}
private static boolean getSIMStateBySlot(Context context, String predictedMethodName, int slotID) throws GeminiMethodNotFoundException {
boolean isReady = false;
TelephonyManager telephony = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
try{
Class<?> telephonyClass = Class.forName(telephony.getClass().getName());
Class<?>[] parameter = new Class[1];
parameter[0] = int.class;
Method getSimStateGemini = telephonyClass.getMethod(predictedMethodName, parameter);
Object[] obParameter = new Object[1];
obParameter[0] = slotID;
Object ob_phone = getSimStateGemini.invoke(telephony, obParameter);
if(ob_phone != null){
int simState = Integer.parseInt(ob_phone.toString());
if(simState == TelephonyManager.SIM_STATE_READY){
isReady = true;
}
}
} catch (Exception e) {
e.printStackTrace();
throw new GeminiMethodNotFoundException(predictedMethodName);
}
return isReady;
}
private static class GeminiMethodNotFoundException extends Exception {
private static final long serialVersionUID = -996812356902545308L;
public GeminiMethodNotFoundException(String info) {
super(info);
}
}
}
Editar :
Obtener acceso a métodos como "getDeviceIdGemini" para obtener detalles de otras ranuras SIM predice que ese método existe.
Si el nombre de ese método no coincide con el proporcionado por el fabricante del dispositivo, no funcionará. Debe encontrar el nombre del método correspondiente para esos dispositivos.
Se pueden encontrar nombres de métodos para otros fabricantes utilizando la reflexión de Java de la siguiente manera:
public static void printTelephonyManagerMethodNamesForThisDevice(Context context) {
TelephonyManager telephony = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
Class<?> telephonyClass;
try {
telephonyClass = Class.forName(telephony.getClass().getName());
Method[] methods = telephonyClass.getMethods();
for (int idx = 0; idx < methods.length; idx++) {
System.out.println("\n" + methods[idx] + " declared by " + methods[idx].getDeclaringClass());
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
EDITAR :
Como Seetha señaló en su comentario:
telephonyInfo.imeiSIM1 = getDeviceIdBySlot(context, "getDeviceIdDs", 0);
telephonyInfo.imeiSIM2 = getDeviceIdBySlot(context, "getDeviceIdDs", 1);
Está funcionando para ella. Logró obtener dos números IMEI para ambas SIM en el dispositivo Samsung Duos.
Agregar<uses-permission android:name="android.permission.READ_PHONE_STATE" />
EDITAR 2:
El método utilizado para recuperar datos es para Lenovo A319 y otros teléfonos de ese fabricante (Crédito Maher Abuthraa ):
telephonyInfo.imeiSIM1 = getDeviceIdBySlot(context, "getSimSerialNumberGemini", 0);
telephonyInfo.imeiSIM2 = getDeviceIdBySlot(context, "getSimSerialNumberGemini", 1);
Tengo un dispositivo Samsung Duos con Android 4.4.4 y el método sugerido por Seetha en la respuesta aceptada (es decir, llamar a getDeviceIdDs) no me funciona, ya que el método no existe. Pude recuperar toda la información que necesitaba llamando al método "getDefault(int slotID)", como se muestra a continuación:
public static void samsungTwoSims(Context context) {
TelephonyManager telephony = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
try{
Class<?> telephonyClass = Class.forName(telephony.getClass().getName());
Class<?>[] parameter = new Class[1];
parameter[0] = int.class;
Method getFirstMethod = telephonyClass.getMethod("getDefault", parameter);
Log.d(TAG, getFirstMethod.toString());
Object[] obParameter = new Object[1];
obParameter[0] = 0;
TelephonyManager first = (TelephonyManager) getFirstMethod.invoke(null, obParameter);
Log.d(TAG, "Device Id: " + first.getDeviceId() + ", device status: " + first.getSimState() + ", operator: " + first.getNetworkOperator() + "/" + first.getNetworkOperatorName());
obParameter[0] = 1;
TelephonyManager second = (TelephonyManager) getFirstMethod.invoke(null, obParameter);
Log.d(TAG, "Device Id: " + second.getDeviceId() + ", device status: " + second.getSimState()+ ", operator: " + second.getNetworkOperator() + "/" + second.getNetworkOperatorName());
} catch (Exception e) {
e.printStackTrace();
}
}
Además, reescribí el código que prueba iterativamente los métodos para recuperar esta información para que utilice una matriz de nombres de métodos en lugar de una secuencia de prueba/catch. Por ejemplo, para determinar si tenemos dos SIM activas podríamos hacer:
private static String[] simStatusMethodNames = {"getSimStateGemini", "getSimState"};
public static boolean hasTwoActiveSims(Context context) {
boolean first = false, second = false;
for (String methodName: simStatusMethodNames) {
// try with sim 0 first
try {
first = getSIMStateBySlot(context, methodName, 0);
// no exception thrown, means method exists
second = getSIMStateBySlot(context, methodName, 1);
return first && second;
} catch (GeminiMethodNotFoundException e) {
// method does not exist, nothing to do but test the next
}
}
return false;
}
De esta manera, si se sugiere un nuevo nombre de método para algún dispositivo, simplemente puede agregarlo a la matriz y debería funcionar.
Hay varias soluciones nativas que encontré mientras buscaba la forma de verificar el operador de red.
Para API >=17:
TelephonyManager manager = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
// Get information about all radio modules on device board
// and check what you need by calling #getCellIdentity.
final List<CellInfo> allCellInfo = manager.getAllCellInfo();
for (CellInfo cellInfo : allCellInfo) {
if (cellInfo instanceof CellInfoGsm) {
CellIdentityGsm cellIdentity = ((CellInfoGsm) cellInfo).getCellIdentity();
//TODO Use cellIdentity to check MCC/MNC code, for instance.
} else if (cellInfo instanceof CellInfoWcdma) {
CellIdentityWcdma cellIdentity = ((CellInfoWcdma) cellInfo).getCellIdentity();
} else if (cellInfo instanceof CellInfoLte) {
CellIdentityLte cellIdentity = ((CellInfoLte) cellInfo).getCellIdentity();
} else if (cellInfo instanceof CellInfoCdma) {
CellIdentityCdma cellIdentity = ((CellInfoCdma) cellInfo).getCellIdentity();
}
}
En AndroidManifest agregue permiso:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
</manifest>
Para obtener el operador de red, puede verificar los códigos mcc y mnc:
- https://en.wikipedia.org/wiki/Mobile_country_code (información general).
- https://clients.txtnation.com/hc/en-us/articles/218719768-MCCMNC-mobile-country-code-and-mobile-network-code-list- (lista de operadores bastante completa y bastante reciente).
Para API >=22:
final SubscriptionManager subscriptionManager = SubscriptionManager.from(context);
final List<SubscriptionInfo> activeSubscriptionInfoList = subscriptionManager.getActiveSubscriptionInfoList();
for (SubscriptionInfo subscriptionInfo : activeSubscriptionInfoList) {
final CharSequence carrierName = subscriptionInfo.getCarrierName();
final CharSequence displayName = subscriptionInfo.getDisplayName();
final int mcc = subscriptionInfo.getMcc();
final int mnc = subscriptionInfo.getMnc();
final String subscriptionInfoNumber = subscriptionInfo.getNumber();
}
Para API >=23. Para comprobar simplemente si el teléfono tiene doble/triple/muchas SIM:
TelephonyManager manager = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
if (manager.getPhoneCount() == 2) {
// Dual sim
}
Puedo leer ambos IMEI del teléfono OnePlus 2
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
TelephonyManager manager = (TelephonyManager) getActivity().getSystemService(Context.TELEPHONY_SERVICE);
Log.i(TAG, "Single or Dual Sim " + manager.getPhoneCount());
Log.i(TAG, "Default device ID " + manager.getDeviceId());
Log.i(TAG, "Single 1 " + manager.getDeviceId(0));
Log.i(TAG, "Single 2 " + manager.getDeviceId(1));
}