Android: verifique se o telefone é dual SIM

113

Depois de muita pesquisa em fóruns, agora eu sei que não há como encontrar o número de série IMSI ou SIM para ambos os cartões SIM em um telefone dual SIM (exceto para entrar em contato com o fabricante). Agora, minha nova pergunta é: podemos detectar que o telefone tem dois SIMs? Eu acredito que pode ser detectado com alguma inteligência. Algumas maneiras que consigo pensar são:

  1. Discando um código USSD e rastreando os logs do número IMEI (tentei fazer isso com * 139 # na Índia. Funcionou.) Isso me dará o número IMEI do SIM do qual disquei o código USSD. (Presume-se que o telefone segue as diretrizes do Android e tem dois números IMEI.)

  2. Armazenar o número de série do SIM e / ou IMSI para o SIM. E após a detecção de qualquer outro número IMSI / Serial, mesmo que o telefone não tenha sido reinicializado (ou seja, o SIM foi alterado), rastreando alguns logs ou por algum tratamento de evento de transmissão.

  3. Discando * 06 # você verá os dois números IMEI. De alguma forma, obtenha esses dois números. (Algo como captura de tela e análise de imagem para texto.)

Se alguém puder pensar em outras maneiras, será muito bem-vindo. Eu realmente apreciaria qualquer tipo de ajuda em relação a isso. Além disso, se alguém tiver qualquer informação sobre APIs de qualquer fabricante ou links para contatá-lo, compartilhe com o pessoal da comunidade.

Rajkiran
fonte
Oi, Rajkiran, Finalmente encontrei a solução e está funcionando bem para mim. Espero que seja útil para todos que desejam lidar com Duel SIM em aplicativos móveis. A API de identificador duelo SIM não está documentada. Verifique se minha resposta está funcionando bem para mim. stackoverflow.com/questions/17618651/…
Jebasuthan
1
Obrigado .. mas sua resposta não responde à minha pergunta. Quero todos os detalhes sobre o segundo SIM e IMEI. A resposta de @Pied Piper me ajuda a conseguir tudo.
Rajkiran
A resposta de @Rajkiran Pied Piper realmente ajudou você? Eu verifiquei o código dele em m samsung galaxy y duos, mas não está funcionando. Você me ajudou a encontrar os IMEI nos do dual sim phone?
Nitish Patel de
@nitishpatel: Sim, definitivamente ajudou. Infelizmente não tenho Y Duos para verificar. Mas acredito que a Samsung usa um mecanismo diferente para o manuseio de SIM duplo no Android versão 4.0 em diante. A resposta do Pied Pipers ajuda em dispositivos 4.0 em diante. Para o resto, você precisará cavar um pouco mais usando reflexão.
Rajkiran
Olá, encontrei uma solução ... verifique o código stackoverflow.com/a/32304799/3131373. Ele foi testado em vários telefones
user3131373

Respostas:

184

Atualização 23 de março de 2015:

A API oficial de vários SIMs está disponível agora do Android 5.1

Outra opção possível:

Você pode usar o reflexo Java para obter os dois números IMEI.

Usando esses números IMEI, você pode verificar se o telefone é um SIM DUAL ou não.

Experimente a seguinte atividade:

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");
    }
}

E aqui 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:

Obter acesso a métodos como "getDeviceIdGemini" para detalhes de outro slot SIM prevê a existência de método.

Se o nome desse método não corresponder ao nome fornecido pelo fabricante do dispositivo, ele não funcionará. Você deve encontrar o nome do método correspondente para esses dispositivos.

Encontrar nomes de métodos para outros fabricantes pode ser feito usando reflexão Java da seguinte maneira:

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 apontou em seu comentário:

telephonyInfo.imeiSIM1 = getDeviceIdBySlot(context, "getDeviceIdDs", 0);
telephonyInfo.imeiSIM2 = getDeviceIdBySlot(context, "getDeviceIdDs", 1); 

Está funcionando para ela. Ela teve sucesso em obter dois números IMEI tanto para o SIM no dispositivo Samsung Duos.

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

EDIT 2:

O método usado para recuperar dados é para Lenovo A319 e outros telefones desse fabricante (Crédito Maher Abuthraa ):

telephonyInfo.imeiSIM1 = getDeviceIdBySlot(context, "getSimSerialNumberGemini", 0); 
telephonyInfo.imeiSIM2 = getDeviceIdBySlot(context, "getSimSerialNumberGemini", 1); 
Vaibhav Jani
fonte
4
Legal! Isso funcionou para mim com "getDeviceId" em Karbonn. Irá pesquisar métodos Samsung e atualizará aqui quando o tiver comigo. Obrigado cara. Kudos.
Rajkiran
1
Sim. Até eu fiz isso. Descobriu que a Samsung usa com.android.internal.telephony.RILConstants$SimCardIDinternamente. Até tentei criar essa classe com a mesma assinatura de métodos e os mesmos nomes de variáveis. Mas sem sorte. Tentará obter o código-fonte e tentará verificar. Obrigado.
Rajkiran
4
Eu uso telephonyInfo.imeiSIM1 = getDeviceIdBySlot (context, "getDeviceIdDs", 0); telephonyInfo.imeiSIM2 = getDeviceIdBySlot (contexto, "getDeviceIdDs", 1); Está funcionando para mim. Tive sucesso em obter dois números IMEI para ambos os SIM.
Seetha
1
Como posso obter o número de telefone do SIM2? Estou recebendo o número SIM1 usando o método telephony.getLine1Number (), na lista de métodos não consigo encontrar um método como getLine2Number () ou getLine1Number (int)
DCoder
4
deviceId é IMEI e não IMSI, não é?
falko
5

Tenho um dispositivo Samsung Duos com Android 4.4.4 e o método sugerido por Seetha na resposta aceita (ou seja, chame getDeviceIdDs) não funciona para mim, pois o método não existe. Consegui recuperar todas as informações de que precisava chamando o método "getDefault (int slotID)", conforme mostrado abaixo:

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();
    }   
}

Além disso, reescrevi o código que testa iterativamente os métodos para recuperar essas informações para que ele use uma matriz de nomes de métodos em vez de uma sequência de try / catch. Por exemplo, para determinar se temos dois SIMs ativos, poderíamos fazer:

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;
}

Dessa forma, se um novo nome de método for sugerido para algum dispositivo, você pode simplesmente adicioná-lo ao array e ele deve funcionar.

Eduardo Javier Huerta Yero
fonte
4

Existem várias soluções nativas que encontrei enquanto procurava a maneira de verificar a operadora de rede.

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();
    } 
}

No AndroidManifest, adicione permissão:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
</manifest>

Para obter a operadora de rede, você pode verificar os códigos mcc e mnc:

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 verificar se o telefone é duplo / triplo / muitos sim:

TelephonyManager manager = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
if (manager.getPhoneCount() == 2) {
    // Dual sim
}
oxi
fonte
4

Consigo ler os IMEI's do OnePlus 2 Phone

 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));
            }
Swapnil Godambe
fonte
É bom que funcione no One Plus. Mas solicite que você poste respostas que funcionem para todos os telefones e todas as versões do Android (provavelmente)
Rajkiran
1
Este é um SDK oficial. Deve funcionar para todos os telefones. Eu testei no OnePlus 2
Swapnil Godambe
Portanto, a resposta aceita de @Swapnil diz a mesma coisa, certo?
Rajkiran
2

Estava dando uma olhada nos registros de chamadas e percebi que além dos campos usuais no conteúdo do managedCursor, temos uma coluna "simid" em telefones Dual SIM (verifiquei no Xolo A500s Lite), de modo a marcar cada chamada no registro de chamadas com um SIM. Este valor é 1 ou 2, provavelmente denotando SIM1 / SIM2.

managedCursor = context.getContentResolver().query(contacts, null, null, null, null);
managedCursor.moveToNext();        
for(int i=0;i<managedCursor.getColumnCount();i++)
{//for dual sim phones
    if(managedCursor.getColumnName(i).toLowerCase().equals("simid"))
        indexSIMID=i;
}

Não encontrei esta coluna em um único telefone SIM (verifiquei no Xperia L).

Portanto, embora eu não ache que essa seja uma maneira infalível de verificar a natureza do dual SIM, estou postando aqui porque pode ser útil para alguém.

zafar142003
fonte
Você está lendo um banco de dados, qual? Por favor, esclareça o que você está fazendo aqui. (Onde o banco de dados "contatos" está armazenado?
not2qubit
1

Dicas:

Você pode tentar usar

ctx.getSystemService("phone_msim")

ao invés de

ctx.getSystemService(Context.TELEPHONY_SERVICE)

Se você já tentou a resposta de Vaibhav e telephony.getClass().getMethod()não conseguiu, acima está o que funciona para meu celular Qualcomm .

Bruce
fonte
Desde que a resposta esteja completa, você pode postar links para páginas da web em outros idiomas para informações complementares. meta.stackoverflow.com/questions/271060/…
mach
Esse foi realmente um link útil , não há necessidade de removê-lo.
not2qubit
0

Encontrei essas propriedades do sistema no Samsung S8

SystemProperties.getInt("ro.multisim.simslotcount", 1) > 1

Além disso, de acordo com a fonte: https://android.googlesource.com/platform/frameworks/base/+/master/telephony/java/com/android/internal/telephony/TelephonyProperties.java

getprop persist.radio.multisim.configretorna " dsds" ou " dsda" no multi sim.

Eu testei isso no Samsung S8 e funciona

kakopappa
fonte
Deixa pra lá. O Android já tem APIs para dual SIM agora. developer.android.com/about/versions/android-5.1.html#multisim Para todo o resto, você pode consultar a resposta acima por @vaibhav
Rajkiran
-1

Commonsware diz que isso não é possível. Por favor, veja o seguinte:

Não é possível detectar Dual SIM usando Android SDK.

Aqui está mais um diálogo sobre o assunto:

O cara da equipe de desenvolvimento do Google diz que detectar Dual SIM usando Android SDK não é possível.

gonzobrains
fonte
3
Sim cara. Eu sei disso. Mas é por isso que estou tentando encontrar uma solução alternativa. E tem que haver algum. Experimente o aplicativo USSDDualWidget da Play Store. Na verdade, ele pode alternar entre os dois SIMs. Até tentei fazer a engenharia reversa do código, mas sem sorte.
Rajkiran
Funciona em todos os dispositivos ou apenas em um subconjunto limitado que expõe algum tipo de interface proprietária?
gonzobrains
2
Por que essa resposta votou negativamente? Esta é a resposta correta. ^
N Sharma
24
Muitas vezes o commonsware disse que não é possível, o que foi tornado possível por outros desenvolvedores. Então, não é assim que o commonsware diz estar sempre certo :-)
Lalit Poptani
1
Você pode estar correto, mas acho que ele é um recurso bastante confiável para todas as coisas do Android. Quanto a este problema específico, claro, eu fiz a mesma coisa e usei reflexão para obter dados dual sim, mas era para meu dispositivo específico. Até hoje, ainda não acredito que haja uma maneira genérica de fazer isso. Observe também que citei um desenvolvedor do Google e não apenas o Commonsware.
gonzobrains