Android : 전화가 듀얼 SIM인지 확인


113

포럼에 대한 많은 연구 끝에 듀얼 SIM 전화에서 두 SIM 카드의 IMSI 또는 SIM 일련 번호를 찾을 수있는 방법이 없다는 것을 알고 있습니다 (제조업체에 문의하는 경우 제외). 이제 변경된 질문은 휴대폰에 두 개의 SIM이 있음을 감지 할 수 있습니까? 나는 그것이 약간의 지능으로 탐지 될 수 있다고 믿는다. 내가 생각할 수있는 몇 가지 방법은 다음과 같습니다.

  1. USSD 코드를 다이얼링하고 IMEI 번호에 대한 로그를 추적합니다 (인도에서 * 139 #로 시도했습니다. 작동했습니다.) 그러면 USSD 코드를 다이얼 한 SIM의 IMEI 번호가 제공됩니다. (휴대 전화가 Android 가이드 라인을 따르고 IMEI 번호가 2 개인 것으로 추정됩니다.)

  2. SIM 일련 번호 및 / 또는 SIM 용 IMSI 저장. 그리고 일부 로그를 추적하거나 일부 브로드 캐스트 이벤트 처리를 통해 전화기가 재부팅되지 않았더라도 (예 : SIM이 전환 된 경우) 다른 IMSI / 일련 번호를 감지 한 후.

  3. * 06 #을 누르면 두 IMEI 번호를 모두 볼 수 있습니다. 어떤 식 으로든이 두 숫자를 얻으십시오. (텍스트에 대한 화면 캡처 및 이미지 구문 분석과 같은 것입니다.)

누군가 다른 방법을 생각할 수 있다면 가장 환영합니다. 나는 이것에 대해 어떤 종류의 도움을 정말 감사합니다. 또한 누구든지 제조업체 API에 대한 정보 나 연락 할 수있는 링크가 있으면 커뮤니티 사람들과 공유하십시오.


안녕 Rajkiran, 마침내 나는 나를 위해 잘 작동하는 해결책을 얻었다. 모바일 애플리케이션에서 듀얼 SIM을 처리하려는 모든 사람에게 도움이되기를 바랍니다. 결투 SIM 핸들 API는 문서화되지 않았습니다. 내 대답이 잘 작동하는지 확인하십시오. stackoverflow.com/questions/17618651/...
Jebasuthan

1
고마워 ..하지만 당신의 대답은 내 질문에 대답하지 않습니다. 두 번째 SIM 및 IMEI에 대한 모든 세부 정보를 원합니다. @ Pied Piper의 대답은 모든 것을 얻는 데 도움이됩니다.
Rajkiran 2014

@Rajkiran Pied Piper의 답변이 정말 도움이 되었습니까? m samsung galaxy y duos에서 그의 코드를 확인했지만 작동하지 않습니다.
Nitish Patel 2014

@nitishpatel : 네 확실히 도움이되었습니다. 유감스럽게도 확인할 Y Duos가 없습니다. 하지만 삼성은 안드로이드 버전 4.0 이상에서 듀얼 SIM 처리를 위해 다른 메커니즘을 사용한다고 생각합니다. Pied Pipers 답변은 4.0 이상 장치에서 도움이됩니다. 나머지는 반사를 사용하여 좀 더 파헤쳐 야합니다.
Rajkiran 2014

안녕하세요, 해결책을 찾았습니다 ... 코드를 확인하십시오. stackoverflow.com/a/32304799/3131373 다양한 전화에서 테스트되었습니다
user3131373

답변:


184

업데이트 23 March'15 :

이제 Android 5.1 이상에서 공식 다중 SIM API를 사용할 수 있습니다.

기타 가능한 옵션 :

Java 리플렉션 을 사용 하여 두 IMEI 번호를 모두 가져올 수 있습니다.

이 IMEI 번호를 사용하여 전화가 DUAL 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);
        }
    }
}

편집하다 :

다른 SIM 슬롯의 세부 사항에 대해 "getDeviceIdGemini"와 같은 메소드에 액세스하면 메소드가 존재한다는 예측이 있습니다.

해당 메서드의 이름이 장치 제조업체에서 지정한 이름과 일치하지 않으면 작동하지 않습니다. 해당 장치에 해당하는 메서드 이름을 찾아야합니다.

다음과 같이 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); 

그녀를 위해 일하고 있습니다. 그녀는 Samsung Duos 장치의 두 SIM에 대해 두 개의 IMEI 번호를 얻는 데 성공했습니다.

더하다 <uses-permission android:name="android.permission.READ_PHONE_STATE" />

편집 2 :

데이터를 검색하는 데 사용되는 방법은 Lenovo A319 및 해당 제조업체의 기타 휴대폰 용입니다 (Credit Maher Abuthraa ).

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

4
멋있는! Karbonn에서 "getDeviceId"로 저에게 효과적이었습니다. 삼성 방법을 검색하고 나와 함께 있으면 여기에서 업데이트합니다. 고마워요. 명성.
Rajkiran 2013

1
예. 나도 그렇게했습니다. 삼성이 com.android.internal.telephony.RILConstants$SimCardID내부적으로 사용하는 것으로 나타났습니다 . 동일한 메서드 시그니처와 동일한 변수 이름으로 해당 클래스를 만들려고 시도했습니다. 그러나 운이 없습니다. 소스 코드를 가져오고 확인을 시도합니다. 감사.
라즈 키 란

4
나는 telephonyInfo.imeiSIM1 = getDeviceIdBySlot (context, "getDeviceIdDs", 0); telephonyInfo.imeiSIM2 = getDeviceIdBySlot (context, "getDeviceIdDs", 1); 그것은 나를 위해 일하고 있습니다. 두 SIM에 대해 두 개의 IMEI 번호를 얻는 데 성공했습니다.
Seetha 2014 년

1
SIM2의 전화 번호는 어떻게 알 수 있습니까? telephony.getLine1Number () 메서드를 사용하여 SIM1 번호를 받고 있습니다. 메서드 목록에서 getLine2Number () 또는 getLine1Number (int)
DCoder

4
deviceId는 IMSI가 아닌 IMEI입니까?
falko 2015-07-26

5

Android 4.4.4가 설치된 Samsung Duos 장치가 있으며 해당 방법이 존재하지 않기 때문에 허용 된 답변 (즉, getDeviceIdDs 호출)에서 Seetha가 제안한 방법이 작동하지 않습니다. 아래와 같이 "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

OnePlus 2 Phone에서 IMEI를 모두 읽을 수 있습니다.

 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에서 작동하는 것이 좋습니다. 그러나 (아마도) 모든 전화와 모든 안드로이드 버전의 작동 후 답변하여 주시기 바랍니다
라즈 키 란

1
이것은 공식 SDK입니다. 모든 전화에서 작동합니다. 나는 원 플러스 2를 테스트 한
Swapnil Godambe에게

그래서 @Swapnil의 대답은 똑같은 것을 말합니다.
라즈 키 란

2

통화 기록을 살펴 보았는데 managedCursor 콘텐츠의 일반적인 필드와 별도로 듀얼 SIM 전화 (Xolo A500s Lite에서 확인)에 "simid"열이있어 각 통화에 태그를 지정했습니다. SIM으로 통화 기록에. 이 값은 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;
}

단일 SIM 전화에서이 열을 찾지 못했습니다 (Xperia L에서 확인했습니다).

따라서 이것이 듀얼 SIM 특성을 확인하는 완벽한 방법이라고 생각하지 않지만 누군가에게 유용 할 수 있기 때문에 여기에 게시하고 있습니다.


어떤 DB를 읽고 있습니까? 여기서 무엇을하고 있는지 명확히하십시오. (어디에 저장되어있는 "연락처"dB인가?
not2qubit

1

팁 :

사용할 수 있습니다

ctx.getSystemService("phone_msim")

대신에

ctx.getSystemService(Context.TELEPHONY_SERVICE)

이미 Vaibhav의 대답을 시도했지만 telephony.getClass().getMethod()실패한 경우 위의 Qualcomm 모바일에서 작동하는 것 입니다.


답변이 완료되면 추가 정보를 위해 다른 언어로 된 웹 페이지 링크를 게시 할 수 있습니다. meta.stackoverflow.com/questions/271060/…
mach

실제로 유용한 링크 였으므로 제거 할 필요가 없습니다.
not2qubit

0

삼성 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에서 테스트했으며 작동합니다.


신경 쓰지 마. Android에는 이미 듀얼 SIM 용 API가 있습니다. developer.android.com/about/versions/android-5.1.html#multisim 당신이 @vaibhav 이상 대답을 참조 할 수 있습니다, 다른 모든 경우
라즈 키 란

-1

Commonsware는 이것이 불가능하다고 말합니다. 다음을 참조하십시오.

Android SDK를 사용하여 듀얼 SIM을 감지 할 수 없습니다.

주제에 대한 추가 대화는 다음과 같습니다.

Google 개발자 팀원은 Android SDK를 사용하여 듀얼 SIM을 감지 할 수 없다고 말합니다.


3
물론 이죠. 알아요. 그러나 이것이 제가 해결 방법을 찾으려고하는 이유입니다. 그리고 일부가 있어야합니다. Play 스토어에서 USSDDualWidget 앱을 사용해보세요. 실제로 두 SIM간에 전환 할 수 있습니다. 코드를 리버스 엔지니어링하려고 시도했지만 운이 없었습니다.
라즈 키 란

모든 장치에서 작동합니까 아니면 일종의 독점 인터페이스를 노출하는 제한된 하위 집합에서만 작동합니까?
gonzobrains 2013

2
이 답변이 반대 투표 한 이유는 무엇입니까? 정답입니다. ^
N Sharma 2014

24
여러 번의 커먼즈웨어는 다른 개발자가 가능하게 만든 것이 불가능 하다고 말했습니다 . 그래서, 그것의하지 그런 식으로 어떤 commonsware 말하는 것은 항상 옳다 :-)입니다
더 그랜드 Poptani

1
당신이 맞을지 모르지만 나는 그가 안드로이드의 모든 것에 대해 상당히 신뢰할만한 자원이라고 생각합니다. 이 특정 문제에 관해서는 확실히 동일한 작업을 수행하고 리플렉션을 사용하여 듀얼 시뮬레이션 데이터를 얻었지만 특정 장치를위한 것이 었습니다. 오늘날까지 나는 이것을 수행하는 일반적인 방법이 없다고 믿습니다. 또한 Commonsware뿐만 아니라 Google 개발자도 인용했습니다.
gonzobrains 2014-06-12
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.