Android: проверьте, поддерживает ли телефон две SIM-карты.

113

После большого количества исследований на форумах теперь я знаю, что нет способа найти серийный номер IMSI или SIM-карты для обеих SIM-карт в телефоне с двумя SIM-картами (за исключением обращения к производителю). Теперь мой измененный вопрос: можем ли мы вообще определить, что в телефоне две SIM-карты? Я считаю, что это можно обнаружить с помощью некоторого интеллекта. Я могу придумать несколько способов:

  1. Набор USSD-кода и отслеживание журналов для номера IMEI (я пробовал это с * 139 # в Индии. Это сработало.) Это даст мне номер IMEI для SIM-карты, с которой я набрал код USSD. (Предполагается, что телефон соответствует требованиям Android и имеет два номера IMEI.)

  2. Сохранение серийного номера SIM-карты и / или IMSI для SIM-карты. И после обнаружения любого другого IMSI / серийного номера, даже если телефон не был перезагружен (т.е. была переключена SIM-карта), путем отслеживания некоторых журналов или обработки некоторых широковещательных событий.

  3. Набрав * 06 #, вы увидите оба номера IMEI. Каким-то образом получить эти два числа. (Что-то вроде захвата экрана и анализа изображения для текста.)

Если кто-то может придумать другие способы, мы будем рады их приветствовать. Я был бы очень признателен за любую помощь в этом отношении. Кроме того, если у кого-то есть какая-либо информация о каких-либо API производителей или ссылки для связи с ними, пожалуйста, поделитесь с людьми из сообщества.

Rajkiran
источник
Привет, Rajkiran, наконец, я получил решение, которое отлично работает для меня. Надеюсь, это поможет всем, кто хочет использовать Duel SIM в мобильных приложениях. API ручки дуэльной SIM-карты не документирован. Пожалуйста, проверьте мой ответ, он работает нормально для меня. stackoverflow.com/questions/17618651/…
Джебасутан 01
1
Спасибо .. но ваш ответ не отвечает на мой вопрос. Мне нужны все подробности о второй SIM и IMEI. Ответ @Pied Piper помогает мне все получить.
Rajkiran 04
Ответ @Rajkiran Pied Piper тебе действительно помог? Я проверил его код в m samsung galaxy y duos, но он не работает. Вы помогли мне найти номера IMEI телефона с двумя sim-картами?
Нитиш Патель,
@nitishpatel: Да, определенно помогло. К сожалению, у меня нет Y Duos для проверки. Но я считаю, что Samsung использует другой механизм для работы с двумя SIM-картами на Android версии 4.0 и новее. Ответ Pied Pipers помогает в устройствах 4.0 и новее. В остальном вам нужно будет немного покопаться, используя отражение.
Rajkiran
Привет, я нашел решение ... проверьте код stackoverflow.com/a/32304799/3131373 Он протестирован на разных телефонах
user3131373

Ответы:

184

Обновление 23 марта 2015 г .:

Официальный API для работы с несколькими SIM-картами доступен начиная с Android 5.1.

Другой возможный вариант:

Вы можете использовать отражение Java, чтобы получить оба номера IMEI.

Используя эти номера IMEI, вы можете проверить, является ли телефон ДВОЙНОЙ SIM-картой или нет.

Попробуйте следующее действие:

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

А вот и 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);
        }
    }
}

Редактировать :

Получение доступа к методам, подобным "getDeviceIdGemini", к деталям другого слота SIM-карты предполагает, что метод существует.

Если имя этого метода не совпадает с именем, указанным производителем устройства, он не будет работать. Вы должны найти соответствующее имя метода для этих устройств.

Найти имена методов для других производителей можно с помощью отражения Java следующим образом:

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

РЕДАКТИРОВАТЬ :

Как отметила Сита в своем комментарии:

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

Это работает для нее. Ей удалось получить два номера IMEI для обеих SIM-карт в устройстве Samsung Duos.

Добавить <uses-permission android:name="android.permission.READ_PHONE_STATE" />

РЕДАКТИРОВАТЬ 2:

Метод, используемый для получения данных, предназначен для Lenovo A319 и других телефонов этого производителя (Кредит Махер Абутраа ):

telephonyInfo.imeiSIM1 = getDeviceIdBySlot(context, "getSimSerialNumberGemini", 0); 
telephonyInfo.imeiSIM2 = getDeviceIdBySlot(context, "getSimSerialNumberGemini", 1); 
Вайбхав Джани
источник
4
Прохладно! У меня это сработало с getDeviceId в Карбонне. Буду искать методы Samsung и обновлять здесь, когда он у меня будет. Спасибо чувак. Престижность.
Rajkiran 08
1
Да. Даже я сделал это. Обнаружил, что Самсунг использует com.android.internal.telephony.RILConstants$SimCardIDвнутренне. Даже пытался создать этот класс с той же сигнатурой методов и одинаковыми именами переменных. Но не повезло. Постараюсь получить исходный код и попробую проверить. Спасибо.
Rajkiran
4
Я использую telephonyInfo.imeiSIM1 = getDeviceIdBySlot (context, "getDeviceIdDs", 0); telephonyInfo.imeiSIM2 = getDeviceIdBySlot (context, "getDeviceIdDs", 1); У меня это работает. Мне удалось получить два номера IMEI для обеих SIM-карт.
Seetha
1
Как я могу получить номер телефона SIM2? Я получаю номер SIM1 с помощью метода telephony.getLine1Number (), в списке методов я не могу найти такие методы, как getLine2Number () или getLine1Number (int)
DCoder
4
deviceId - это IMEI, а не IMSI, не так ли?
falko
5

У меня есть устройство Samsung Duos с Android 4.4.4, и метод, предложенный Ситой в принятом ответе (т.е. вызов getDeviceIdDs), не работает для меня, так как этот метод не существует. Мне удалось восстановить всю необходимую информацию, вызвав метод getDefault (int slotID), как показано ниже:

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

Кроме того, я переписал код, который итеративно проверяет методы для восстановления этой информации, чтобы он использовал массив имен методов вместо последовательности try / catch. Например, чтобы определить, есть ли у нас две активные SIM-карты, мы можем:

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

Таким образом, если для какого-либо устройства предлагается новое имя метода, вы можете просто добавить его в массив, и он должен работать.

Эдуардо Хавьер Уэрта Йеро
источник
4

Я нашел несколько нативных решений, когда искал способ проверить оператора сети.

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

В AndroidManifest добавьте разрешение:

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

Чтобы получить оператора сети, вы можете проверить коды mcc и mnc:

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

Для API> = 23. Чтобы просто проверить, является ли телефон двойной / тройной / много SIM-картой:

TelephonyManager manager = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
if (manager.getPhoneCount() == 2) {
    // Dual sim
}
окисленный
источник
4

Я могу читать оба IMEI телефона 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));
            }
Свапнил Годамбе
источник
Хорошо, что на One Plus работает. Но прошу вас публиковать ответы, которые работают для всех телефонов и всех версий Android (возможно)
Rajkiran
1
Это официальный SDK. Должно работать на весь телефон. Я тестировал его на OnePlus 2
Swapnil Godambe
Итак, принятый ответ от @Swapnil говорит о том же, верно?
Rajkiran
2

Я смотрел журналы вызовов и заметил, что помимо обычных полей в содержимом managedCursor, у нас есть столбец simid в телефонах с двумя SIM-картами (я проверял на Xolo A500s Lite), чтобы отмечать каждый звонок в журнале звонков с симкой. Это значение либо 1, либо 2, скорее всего, обозначает 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;
}

Ни в одном телефоне с одной симкой не нашел эту колонку (проверял на Xperia L).

Поэтому, хотя я не думаю, что это надежный способ проверки наличия двух SIM-карт, я публикую его здесь, потому что он может быть кому-то полезен.

zafar142003
источник
Какую БД вы читаете? Пожалуйста, поясните, что вы здесь делаете. (Где хранится
база данных
1

Подсказки:

Вы можете попробовать использовать

ctx.getSystemService("phone_msim")

вместо того

ctx.getSystemService(Context.TELEPHONY_SERVICE)

Если вы уже пробовали ответ Vaibhav и telephony.getClass().getMethod()не смогли , то это работает для моего мобильного телефона Qualcomm .

Брюс
источник
Пока ответ будет полным, вы можете размещать ссылки на веб-страницы на других языках для получения дополнительной информации. meta.stackoverflow.com/questions/271060/…
Mach
Это действительно была полезная ссылка , не нужно ее удалять.
not2qubit 01
0

Я нашел эти системные свойства на Samsung S8

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

Также согласно источнику: https://android.googlesource.com/platform/frameworks/base/+/master/telephony/java/com/android/internal/telephony/TelephonyProperties.java

getprop persist.radio.multisim.configвозвращает " dsds" или "dsda " на мульти-сим-карте.

Я тестировал это на Samsung S8, и он работает

kakopappa
источник
Неважно. В Android уже есть API для работы с двумя SIM-картами. developer.android.com/about/versions/android-5.1.html#multisim По поводу всего остального вы можете обратиться к вышеуказанному ответу @vaibhav
Rajkiran
-1

Commonsware говорит, что это невозможно. См. Следующее:

Обнаружение Dual SIM с помощью Android SDK невозможно.

Вот дальнейший диалог по этому поводу:

Парень из команды разработчиков Google говорит, что обнаружить Dual SIM с помощью Android SDK невозможно.

гонзобраны
источник
3
Да мужик. Я знаю это. Но именно поэтому я пытаюсь найти обходной путь. И они должны быть. Попробуйте приложение USSDDualWidget из Play Store. Фактически он может переключаться между двумя SIM-картами. Даже пытался перепроектировать код, но безуспешно.
Rajkiran
Работает ли он на всех устройствах или только на ограниченном подмножестве, которое предоставляет какой-то проприетарный интерфейс?
gonzobrains
2
Почему этот ответ отклонен? Это правильный ответ. ^
N Sharma
24
Часто Commonsware говорило, что это невозможно что стало возможным благодаря другим разработчикам. Так что это не то, что обычно говорит Commonsware :-)
Lalit Poptani
1
Возможно, вы правы, но я думаю, что он является довольно надежным ресурсом по всем вопросам Android. Что касается этой конкретной проблемы, конечно, я сделал то же самое и использовал отражение для получения данных с двумя сим-картами, но это было для моего конкретного устройства. По сей день я все еще не верю, что есть какой-то общий способ сделать это. Также обратите внимание, что я также процитировал разработчика Google, а не только Commonsware.
гонзобраны