Android: sprawdź, czy telefon obsługuje dwie karty SIM

113

Po wielu poszukiwaniach na forach wiem, że nie ma sposobu, aby znaleźć numer seryjny IMSI lub SIM dla obu kart SIM w telefonie dual SIM (poza kontaktem z producentem). Teraz moje zmienione pytanie brzmi: czy w ogóle możemy wykryć, że telefon ma dwie karty SIM? Uważam, że można to wykryć za pomocą pewnej inteligencji. Kilka sposobów, które przychodzą mi do głowy, to:

  1. Wybieranie kodu USSD i śledzenie dzienników dla numeru IMEI (próbowałem tego z * 139 # w Indiach. Udało się.) To da mi numer IMEI dla karty SIM, z której wybrałem kod USSD. (Zakłada się, że telefon jest zgodny z wytycznymi Androida i ma dwa numery IMEI).

  2. Przechowywanie numeru seryjnego karty SIM i / lub IMSI dla karty SIM. I po wykryciu dowolnego innego numeru IMSI / seryjnego, nawet jeśli telefon nie został ponownie uruchomiony (tj. Została przełączona karta SIM), przez śledzenie niektórych dzienników lub obsługę zdarzenia transmisji.

  3. Wybierając * 06 # zobaczysz oba numery IMEI. W jakiś sposób zdobądź te dwie liczby. (Coś w rodzaju przechwytywania ekranu i analizowania obrazu pod kątem tekstu).

Jeśli ktoś może wymyślić inne sposoby, jest mile widziany. Byłbym naprawdę wdzięczny za jakąkolwiek pomoc w tej sprawie. Ponadto, jeśli ktoś ma jakiekolwiek informacje na temat interfejsów API producentów lub łącza umożliwiające skontaktowanie się z nimi, prosimy o udostępnienie ich społeczności.

Rajkiran
źródło
Cześć Rajkiran, Wreszcie mam rozwiązanie, które działa dobrze dla mnie. Mam nadzieję, że powinno to pomóc każdemu, kto chce poradzić sobie z Duel SIM w aplikacjach mobilnych. Interfejs API pojedynczej rączki SIM nie jest udokumentowany. Proszę sprawdzić moją odpowiedź, że dla mnie działa dobrze. stackoverflow.com/questions/17618651/…
Jebasuthan
1
Dzięki… ale twoja odpowiedź nie odpowiada na moje pytanie. Chcę poznać wszystkie szczegóły dotyczące drugiej karty SIM i IMEI. Odpowiedź @ Pied Piper pomaga mi wszystko.
Rajkiran
Odpowiedź @Rajkiran Pied Piper naprawdę ci pomogła? Sprawdziłem jego kod w m samsung galaxy y duos, ale nie działa. Pomogliście mi znaleźć numery IMEI telefonu z dwiema kartami SIM?
Nitish Patel,
@nitishpatel: Tak, zdecydowanie pomogło. Niestety nie mam Y Duos do sprawdzenia. Uważam jednak, że Samsung używa innego mechanizmu obsługi dwóch kart SIM w systemie Android w wersji 4.0 i nowszych. Odpowiedź Pied Pipers pomaga w urządzeniach 4.0 i nowszych. Co do reszty, musisz trochę więcej kopać, używając odbicia.
Rajkiran
Cześć, znajduję rozwiązanie ... sprawdź kod stackoverflow.com/a/32304799/3131373 Jest to testowane na różnych telefonach
user3131373

Odpowiedzi:

184

Aktualizacja 23 marca 2015:

Oficjalny interfejs API wielu kart SIM jest już dostępny od Androida 5.1

Inna możliwa opcja:

Możesz użyć odbicia Java, aby uzyskać oba numery IMEI.

Korzystając z tych numerów IMEI możesz sprawdzić, czy telefon to DUAL SIM, czy nie.

Spróbuj wykonać następujące czynności:

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

A oto 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);
        }
    }
}

Edytować :

Uzyskanie dostępu do metod takich jak „getDeviceIdGemini” dla szczegółów innego gniazda SIM zakłada, że ​​metoda istnieje.

Jeśli nazwa tej metody nie zgadza się z nazwą podaną przez producenta urządzenia, to nie zadziała. Musisz znaleźć odpowiednią nazwę metody dla tych urządzeń.

Znajdowanie nazw metod dla innych producentów można wykonać za pomocą refleksji w języku Java w następujący sposób:

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

EDYTOWAĆ :

Jak zauważyła Seetha w swoim komentarzu:

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

To dla niej działa. Udało jej się uzyskać dwa numery IMEI dla obu kart SIM w urządzeniu Samsung Duos.

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

EDYCJA 2:

Metoda pobierania danych dotyczy telefonów Lenovo A319 i innych telefonów tego producenta (Credit Maher Abuthraa ):

telephonyInfo.imeiSIM1 = getDeviceIdBySlot(context, "getSimSerialNumberGemini", 0); 
telephonyInfo.imeiSIM2 = getDeviceIdBySlot(context, "getSimSerialNumberGemini", 1); 
Vaibhav Jani
źródło
4
Chłodny! To zadziałało dla mnie z „getDeviceId” na Karbonn. Wyszuka metody Samsunga i zaktualizuje się tutaj, gdy będę miał ją przy sobie. Dzięki. Sława.
Rajkiran
1
Tak. Nawet ja to zrobiłem. Okazało się, że Samsung używa com.android.internal.telephony.RILConstants$SimCardIDwewnętrznie. Próbowałem nawet stworzyć tę klasę z tą samą sygnaturą metod i tymi samymi nazwami zmiennych. Ale bez szczęścia. Spróbuje uzyskać kod źródłowy i spróbuje sprawdzić. Dzięki.
Rajkiran,
4
Używam telephonyInfo.imeiSIM1 = getDeviceIdBySlot (kontekst, "getDeviceIdDs", 0); telephonyInfo.imeiSIM2 = getDeviceIdBySlot (kontekst, "getDeviceIdDs", 1); To działa dla mnie. Udało mi się uzyskać dwa numery IMEI dla obu kart SIM.
Seetha
1
Jak mogę uzyskać numer telefonu SIM2? Otrzymuję numer SIM1 za pomocą metody telephony.getLine1Number (), na liście metod nie mogę znaleźć metody takiej jak getLine2Number () lub getLine1Number (int)
DCoder
4
deviceId to IMEI, a nie IMSI, prawda?
falko
5

Mam urządzenie Samsung Duos z Androidem 4.4.4 i metoda zasugerowana przez Seethę w zaakceptowanej odpowiedzi (np. Wywołanie getDeviceIdDs) u mnie nie działa, ponieważ metoda nie istnieje. Udało mi się odzyskać wszystkie potrzebne informacje, wywołując metodę „getDefault (int slotID)”, jak pokazano poniżej:

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

Ponadto przepisałem kod, który iteracyjnie testuje metody odzyskiwania tych informacji, tak aby używał tablicy nazw metod zamiast sekwencji try / catch. Na przykład, aby ustalić, czy mamy dwie aktywne karty SIM, możemy zrobić:

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

W ten sposób, jeśli dla jakiegoś urządzenia jest sugerowana nowa nazwa metody, możesz po prostu dodać ją do tablicy i powinno działać.

Eduardo Javier Huerta Yero
źródło
4

Istnieje kilka rozwiązań natywnych, które znalazłem, szukając sposobu na sprawdzenie operatora sieci.

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

W AndroidManifest dodaj uprawnienia:

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

Aby uzyskać operatora sieci, możesz sprawdzić kody mcc i mnc:

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

Dla API> = 23. Aby tylko sprawdzić, czy telefon jest podwójny / potrójny / wiele kart SIM:

TelephonyManager manager = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
if (manager.getPhoneCount() == 2) {
    // Dual sim
}
oksydowane
źródło
4

Jestem w stanie odczytać oba IMEI z telefonu 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));
            }
Swapnil Godambe
źródło
Dobrze, że działa na One Plus. Ale poproś o opublikowanie odpowiedzi, które działają na wszystkich telefonach i wszystkich wersjach Androida (prawdopodobnie)
Rajkiran
1
To jest oficjalny pakiet SDK. Powinien działać na wszystkich telefonach. Przetestowałem to na OnePlus 2
Swapnil Godambe
Więc zaakceptowana odpowiedź od @Swapnil mówi to samo, prawda?
Rajkiran,
2

Przeglądałem dzienniki połączeń i zauważyłem, że poza zwykłymi polami w treści managedCursor, w telefonach Dual SIM mamy kolumnę "simid" (sprawdziłem na Xolo A500s Lite), żeby otagować każde połączenie w rejestrze połączeń za pomocą karty SIM. Ta wartość to 1 lub 2, najprawdopodobniej oznaczająca 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;
}

Nie znalazłem tej kolumny w jednym telefonie SIM (sprawdzałem na Xperii L).

Więc chociaż nie uważam, że jest to niezawodny sposób sprawdzenia natury podwójnej karty SIM, zamieszczam go tutaj, ponieważ może to być przydatne dla kogoś.

zafar142003
źródło
Czytasz DB, który? Wyjaśnij, co tutaj robisz. (Gdzie jest przechowywana
baza
1

Porady:

Możesz spróbować użyć

ctx.getSystemService("phone_msim")

zamiast

ctx.getSystemService(Context.TELEPHONY_SERVICE)

Jeśli już wypróbowałeś odpowiedź Vaibhav i się telephony.getClass().getMethod()nie udało , powyżej opisano, co działa na moim telefonie Qualcomm .

Bruce
źródło
Jeśli odpowiedź jest kompletna , możesz zamieścić linki do stron internetowych w innych językach, aby uzyskać dodatkowe informacje. meta.stackoverflow.com/questions/271060/ ...
mach
To był faktycznie przydatny link , nie trzeba go usuwać.
not2qubit
0

Znalazłem te właściwości systemu na Samsungu S8

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

Ponadto według źródła: https://android.googlesource.com/platform/frameworks/base/+/master/telephony/java/com/android/internal/telephony/TelephonyProperties.java

getprop persist.radio.multisim.configzwraca „ dsds” lub „ dsda” na wielu kartach SIM.

Przetestowałem to na Samsungu S8 i działa

kakopappa
źródło
Nieważne. Android ma już teraz interfejsy API dla dwóch kart SIM. developer.android.com/about/versions/android-5.1.html#multisim Jeśli chodzi o wszystko inne, możesz odwołać się do powyższej odpowiedzi, którą napisał @vaibhav
Rajkiran
-1

Commonsware twierdzi, że nie jest to możliwe. Zobacz następujące informacje:

Wykrywanie Dual SIM za pomocą Android SDK nie jest możliwe.

Oto dalszy dialog na ten temat:

Facet z zespołu programistów Google mówi, że wykrycie Dual SIM za pomocą Android SDK nie jest możliwe.

gonzobrains
źródło
3
Tak, ziom. Wiem to. Ale dlatego próbuję znaleźć obejście. I musi być trochę. Wypróbuj aplikację USSDDualWidget ze Sklepu Play. W rzeczywistości może przełączać się między dwiema kartami SIM. Próbowałem nawet odtworzyć kod, ale bez powodzenia.
Rajkiran
Czy działa na wszystkich urządzeniach, czy tylko na ograniczonym podzbiorze, który ujawnia jakiś zastrzeżony interfejs?
gonzobrains
2
Dlaczego ta odpowiedź została odrzucona? To jest poprawna odpowiedź. ^
N Sharma,
24
Commonsware wielokrotnie twierdził, że nie jest to możliwe, co stało się możliwe przez innych programistów. Więc to nie tak, że to, co mówi commonsware, jest zawsze słuszne :-)
Lalit Poptani,
1
Możesz mieć rację, ale myślę, że jest on dość wiarygodnym źródłem informacji o wszystkich sprawach związanych z Androidem. Jeśli chodzi o ten konkretny problem, oczywiście zrobiłem to samo i użyłem odbicia, aby uzyskać dane z dwóch kart SIM, ale dotyczyło to mojego konkretnego urządzenia. Do dziś nie wierzę, że istnieje jakiś ogólny sposób, aby to zrobić. Zwróć też uwagę, że zacytowałem również programistę Google, a nie tylko oprogramowanie Commons.
gonzobrains