Last active
September 11, 2017 12:16
-
-
Save falkolab/2eb217822a1b9931d34c to your computer and use it in GitHub Desktop.
Titanium android module proxy to check whether the phone is dual SIM
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// http://stackoverflow.com/a/17499889/506724 | |
package com.falkolab.drunkmode.platform; | |
import java.io.BufferedReader; | |
import java.io.IOException; | |
import java.io.InputStreamReader; | |
import java.lang.reflect.Method; | |
import java.util.ArrayList; | |
import org.appcelerator.kroll.KrollProxy; | |
import org.appcelerator.kroll.annotations.Kroll; | |
import org.appcelerator.kroll.common.Log; | |
import org.appcelerator.titanium.TiApplication; | |
import android.content.Context; | |
import android.telephony.TelephonyManager; | |
@Kroll.proxy | |
public class TelephonyInfoProxy extends KrollProxy { | |
private static final String TAG = TelephonyInfoProxy.class.getSimpleName(); | |
private static TelephonyInfoProxy info; | |
private String imeiSIM1; | |
private String imeiSIM2; | |
private String imsiSIM1; | |
private String imsiSIM2; | |
private boolean isSIM1Ready; | |
private boolean isSIM2Ready; | |
private String[] getDeviceIdMethods = { "getDeviceId", "getDeviceIdGemini", | |
"getDeviceIdDs" }; | |
private String[] getSimStateBySlotMethods = { "getSimStateGemini", | |
"getSimState", "getSimStateDs" }; | |
private String[] getSubscriberIdMethods = { "getSubscriberId", | |
"getSubscriberIdGemini" }; | |
private String getDeviceIdMethodName = null; | |
private String getSimStateBySlotMethodName = null; | |
private String getSubscriberIdMethodName = null; | |
public TelephonyInfoProxy() { | |
super(); | |
} | |
@Kroll.method | |
@Kroll.getProperty | |
public String getImeiSIM1() { | |
return imeiSIM1; | |
} | |
@Kroll.method | |
@Kroll.getProperty | |
public String getImeiSIM2() { | |
return imeiSIM2; | |
} | |
@Kroll.method | |
@Kroll.getProperty | |
public String getImsiSIM1() { | |
return imsiSIM1; | |
} | |
@Kroll.method | |
@Kroll.getProperty | |
public String getImsiSIM2() { | |
return imsiSIM2; | |
} | |
@Kroll.method | |
@Kroll.getProperty(name = "isSIM1Ready") | |
public boolean isSIM1Ready() { | |
return isSIM1Ready; | |
} | |
@Kroll.method | |
@Kroll.getProperty(name = "isSIM2Ready") | |
public boolean isSIM2Ready() { | |
return isSIM2Ready; | |
} | |
@Kroll.method | |
@Kroll.getProperty(name = "isDualSIM") | |
public boolean isDualSIM() { | |
return imeiSIM2 != null; | |
} | |
private void detectManufacturerMethods() { | |
TiApplication tiApp = TiApplication.getInstance(); | |
if (getDeviceIdMethodName != null | |
&& getSimStateBySlotMethodName != null) { | |
return; | |
} | |
TelephonyManager telephony = (TelephonyManager) tiApp | |
.getSystemService(Context.TELEPHONY_SERVICE); | |
Class<?> telephonyClass; | |
try { | |
telephonyClass = Class.forName(telephony.getClass().getName()); | |
} catch (ClassNotFoundException e) { | |
return; | |
} | |
String currentMethodName = null; | |
try { | |
if (getDeviceIdMethodName == null) { | |
for (String methodName : getDeviceIdMethods) { | |
currentMethodName = methodName; | |
Class<?>[] parameter = new Class[1]; | |
parameter[0] = int.class; | |
String dmsg = "Test for method:" + methodName + "(simId)"; | |
try { | |
telephonyClass.getMethod(methodName, parameter); | |
Log.d(TAG, dmsg + "- ok"); | |
getDeviceIdMethodName = methodName; | |
break; | |
} catch (NoSuchMethodException e) { | |
Log.d(TAG, dmsg + "- not found"); | |
} | |
} | |
} | |
if (getSubscriberIdMethodName == null) { | |
for (String methodName : getSubscriberIdMethods) { | |
currentMethodName = methodName; | |
Class<?>[] parameter = new Class[1]; | |
parameter[0] = int.class; | |
String dmsg = "Test for method:" + methodName + "(simId)"; | |
try { | |
telephonyClass.getMethod(methodName, parameter); | |
Log.d(TAG, dmsg + "- ok"); | |
getSubscriberIdMethodName = methodName; | |
break; | |
} catch (NoSuchMethodException e) { | |
Log.d(TAG, dmsg + "- not found"); | |
} | |
} | |
} | |
if (getSimStateBySlotMethodName == null) { | |
for (String methodName : getSimStateBySlotMethods) { | |
currentMethodName = methodName; | |
Class<?>[] parameter = new Class[1]; | |
parameter[0] = int.class; | |
String dmsg = "Test for method:" + methodName + "(simId)"; | |
try { | |
telephonyClass.getMethod(methodName, parameter); | |
Log.d(TAG, dmsg + "- ok"); | |
getSimStateBySlotMethodName = methodName; | |
break; | |
} catch (NoSuchMethodException e) { | |
Log.d(TAG, dmsg + "- not found"); | |
} | |
} | |
} | |
} catch (SecurityException e) { | |
Log.e(TAG, "Can't get method '" + currentMethodName | |
+ "' accordance with security restriction"); | |
} | |
} | |
public static TelephonyInfoProxy getInstance() { | |
if (info == null) { | |
TiApplication tiApp = TiApplication.getInstance(); | |
Context context = (Context) tiApp; | |
info = new TelephonyInfoProxy(); | |
info.detectManufacturerMethods(); | |
TelephonyManager telephonyManager = ((TelephonyManager) context | |
.getSystemService(Context.TELEPHONY_SERVICE)); | |
info.imeiSIM1 = telephonyManager.getDeviceId(); | |
info.imeiSIM2 = null; | |
if (info.getDeviceIdMethodName != null) { | |
info.imeiSIM1 = getStringValueBySlot(context, | |
info.getDeviceIdMethodName, 0); | |
info.imeiSIM2 = getStringValueBySlot(context, | |
info.getDeviceIdMethodName, 1); | |
Log.d(TAG, "Was used method: " + info.getDeviceIdMethodName); | |
} | |
if (info.getSubscriberIdMethodName != null) { | |
info.imsiSIM1 = getStringValueBySlot(context, | |
info.getSubscriberIdMethodName, 0); | |
info.imsiSIM2 = getStringValueBySlot(context, | |
info.getSubscriberIdMethodName, 1); | |
Log.d(TAG, "Was used method: " + info.getSubscriberIdMethodName); | |
} else { | |
try { | |
// http://stackoverflow.com/a/30647918/2267723 | |
String imsiParcel = runCommand("service call iphonesubinfo 3"); | |
info.imsiSIM1 = getNumberFromParcel(imsiParcel); | |
imsiParcel = runCommand("service call iphonesubinfo2 3"); | |
info.imsiSIM2 = getNumberFromParcel(imsiParcel); | |
Log.d(TAG, "Was used method: service call iphonesubinfo"); | |
} catch (Exception e) { | |
Log.d(TAG, "Couldn't get multi SIM IMSI info"); | |
} | |
} | |
info.isSIM1Ready = telephonyManager.getSimState() == TelephonyManager.SIM_STATE_READY; | |
info.isSIM2Ready = false; | |
if (info.getSimStateBySlotMethodName != null) { | |
info.isSIM1Ready = getSIMStateBySlot(context, | |
info.getSimStateBySlotMethodName, 0); | |
info.isSIM2Ready = getSIMStateBySlot(context, | |
info.getSimStateBySlotMethodName, 1); | |
Log.d(TAG, "Was used method: " | |
+ info.getSimStateBySlotMethodName); | |
} | |
} | |
return info; | |
} | |
private static Object invokePredictedMethod(Context context, | |
String predictedMethodName, int slotID) throws SecurityException, | |
NoSuchMethodException { | |
TelephonyManager telephony = (TelephonyManager) context | |
.getSystemService(Context.TELEPHONY_SERVICE); | |
Class<?> telephonyClass; | |
try { | |
telephonyClass = Class.forName(telephony.getClass().getName()); | |
} catch (ClassNotFoundException e1) { | |
return null; | |
} | |
Class<?>[] parameter = new Class[1]; | |
parameter[0] = int.class; | |
Method m = telephonyClass.getMethod(predictedMethodName, parameter); | |
Object[] obParameter = new Object[1]; | |
obParameter[0] = slotID; | |
try { | |
return m.invoke(telephony, obParameter); | |
} catch (Exception e) { | |
Log.e(TAG, "Can't invokation to method: " + predictedMethodName); | |
return null; | |
} | |
} | |
private static String getStringValueBySlot(Context context, | |
String predictedMethodName, int slotID) { | |
Object ob; | |
try { | |
ob = invokePredictedMethod(context, predictedMethodName, slotID); | |
return ob != null ? ob.toString() : null; | |
} catch (SecurityException e) { | |
e.printStackTrace(); | |
return null; | |
} catch (NoSuchMethodException e) { | |
e.printStackTrace(); | |
return null; | |
} | |
} | |
private static boolean getSIMStateBySlot(Context context, | |
String predictedMethodName, int slotID) { | |
Object ob_phone; | |
try { | |
ob_phone = invokePredictedMethod(context, predictedMethodName, | |
slotID); | |
if (ob_phone != null | |
&& Integer.parseInt(ob_phone.toString()) == TelephonyManager.SIM_STATE_READY) { | |
return true; | |
} else { | |
return false; | |
} | |
} catch (SecurityException e) { | |
e.printStackTrace(); | |
return false; | |
} catch (NoSuchMethodException e) { | |
e.printStackTrace(); | |
return false; | |
} | |
} | |
public static String runCommand(String src) { | |
try { | |
Process process = Runtime.getRuntime().exec(src); | |
BufferedReader reader = new BufferedReader(new InputStreamReader( | |
process.getInputStream())); | |
int read; | |
char[] buffer = new char[2048]; | |
StringBuffer output = new StringBuffer(); | |
while ((read = reader.read(buffer)) > 0) { | |
output.append(buffer, 0, read); | |
} | |
reader.close(); | |
// Waits for the command to finish. | |
process.waitFor(); | |
return output.toString(); | |
} catch (IOException e) { | |
Log.e(TAG, "IOException:" + e.getMessage()); | |
return null; | |
} catch (InterruptedException e) { | |
Log.e(TAG, "InterruptedException:" + e.getMessage()); | |
return null; | |
} | |
} | |
public static String getNumberFromParcel(String str) { | |
String res = ""; | |
if (str != null && str.length() > 0) { | |
String lines[] = str.split("\n"); | |
for (String line : lines) { | |
if (line == null || line.length() == 0) | |
continue; | |
String content[] = line.split("'"); | |
if (content.length > 1) { | |
res += content[1].replace(".", ""); | |
} | |
} | |
} else | |
return "NA"; | |
return res; | |
} | |
@Kroll.method | |
public String[] listAvailableMethods() { | |
TiApplication tiApp = TiApplication.getInstance(); | |
TelephonyManager telephony = (TelephonyManager) tiApp | |
.getSystemService(Context.TELEPHONY_SERVICE); | |
Class<?> telephonyClass; | |
ArrayList<String> methodsInfo = new ArrayList<String>(); | |
try { | |
telephonyClass = Class.forName(telephony.getClass().getName()); | |
Method[] methods = telephonyClass.getMethods(); | |
for (int idx = 0; idx < methods.length; idx++) { | |
methodsInfo.add(methods[idx] + " declared by " | |
+ methods[idx].getDeclaringClass()); | |
} | |
} catch (ClassNotFoundException e) { | |
e.printStackTrace(); | |
} | |
String[] result = new String[methodsInfo.size()]; | |
return (String[]) methodsInfo.toArray(result); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@Kroll.module(name="Telephony", id="...") | |
public class TelephonyModule extends KrollModule | |
{ | |
public TelephonyModule() | |
{ | |
super(); | |
} | |
@Kroll.method(name = "createTelephonyInfo") | |
public TelephonyInfoProxy createTelephonyInfoProxy() | |
{ | |
return TelephonyInfoProxy.getInstance(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment