Android: проверьте, поддерживает ли телефон две SIM-карты
После большого количества исследований на форумах, теперь я знаю, что невозможно найти серийный номер IMSI или SIM-карты для обеих SIM-карт в телефоне с двумя SIM-картами (кроме как связаться с производителем). Теперь мой измененный вопрос: можем ли мы вообще обнаружить, что в телефоне две SIM-карты? Я считаю, что это может быть обнаружено с некоторым интеллектом. Я могу придумать лишь несколько способов:
Набирая код USSD и отслеживая журналы для номера IMEI (я попробовал это с *139# в Индии. Это сработало.) Это даст мне номер IMEI для SIM-карты, с которой я набрал код USSD. (Предполагается, что телефон следует указаниям Android и имеет два номера IMEI.)
Сохранение серийного номера SIM-карты и / или IMSI для SIM-карты. И после обнаружения любого другого IMSI / серийного номера, даже если телефон не был перезагружен (т. Е. SIM-карта была переключена) путем отслеживания некоторых журналов или какой-либо обработки широковещательных событий.
Набрав *06#, вы увидите оба номера IMEI. Каким-то образом получить эти два числа. (Что-то вроде захвата экрана и анализа текста для текста.)
Если кто-то может придумать какие-то другие способы, они очень приветствуются. Я был бы очень признателен за любую помощь по этому поводу. Кроме того, если у кого-либо есть какая-либо информация о каких-либо API-интерфейсах производителей или ссылки для связи с ними, пожалуйста, поделитесь с людьми сообщества.
9 ответов
Обновление 23 марта'15:
Официальный 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();
}
}
РЕДАКТИРОВАТЬ:
Как Seetha указала в своем комментарии:
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 и других телефонов этого производителя (Credit Maher Abuthraa):
telephonyInfo.imeiSIM1 = getDeviceIdBySlot(context, "getSimSerialNumberGemini", 0);
telephonyInfo.imeiSIM2 = getDeviceIdBySlot(context, "getSimSerialNumberGemini", 1);
У меня есть устройство Samsung Duos с Android 4.4.4, и метод, предложенный Seetha в принятом ответе (т.е. вызов 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;
}
Таким образом, если для какого-либо устройства предлагается новое имя метода, вы можете просто добавить его в массив, и оно должно работать.
Есть несколько нативных решений, которые я нашел, когда искал способ проверить оператора сети.
Для 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:
- https://en.wikipedia.org/wiki/Mobile_country_code (общая информация).
- https://clients.txtnation.com/hc/en-us/articles/218719768-MCCMNC-mobile-country-code-and-mobile-network-code-list- (довольно полный и довольно свежий список операторов).
Для 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. Чтобы просто проверить, является ли телефон двойной / тройной / много сим:
TelephonyManager manager = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
if (manager.getPhoneCount() == 2) {
// Dual sim
}
Я могу читать оба 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));
}
Я просматривал журналы вызовов и заметил, что помимо обычных полей в содержимом 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;
}
Я не нашел эту колонку ни в одном телефоне SIM (я проверял на Xperia L).
Поэтому, хотя я не думаю, что это надежный способ проверить наличие двух SIM-карт, я публикую его здесь, потому что он может быть кому-то полезен.
Я нашел эти системные свойства на 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, и он работает
Подсказки:
Вы можете попробовать использовать
ctx.getSystemService("phone_msim")
вместо
ctx.getSystemService(Context.TELEPHONY_SERVICE)
Если вы уже попробовали ответ Вайбхава и telephony.getClass().getMethod()
выше, это то, что работает для моего мобильного Qualcomm.
для SDK API 26+ (Build.VERSION_CODES.O):
val telephony = context.getSystemService(Service.TELEPHONY_SERVICE) as? TelephonyManager
// check telephony on null
val simCount = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
telephony.activeModemCount
} else {
telephony.phoneCount
}
Commonsware говорит, что это невозможно. Пожалуйста, смотрите следующее:
Обнаружение двойной SIM-карты с помощью Android SDK невозможно.
Вот дальнейший диалог на эту тему: