[转载]Android 双卡双待识别 – banketree – 博客频道 – CSDN.NET.
简介
Android双卡双待已经越来越普及了,解决双卡双待管理是广大手机开发人员必须得面对的问题,为实现Android平台的双卡双待操作,笔者研究了Android 应用层操作双卡双待的机制。
机制
获取基于ITelephony接口实现phone应用中的“phone服务”,通过TelephonyManager接口获取不同的卡(GSMPhone /CDMAPhone)进行不同的操作(拨号、接通、挂断、保持通话等)。
Android 平台是一个多样型的平台,不同的手机获取ITelephony接口不同,用一种方法实现双卡双待管理是不可取的。那怎么办呢?只有针对不同的手机分析出一 套管理的方案,该方案实现难度大,因为需要各个厂家的SDK的资料。为了实现该功能,笔者做了大量工作,整合各个厂家的SDK的资料。
实现
为了更好的管理双卡双待的问题,新建一个双卡双待模块静态库,其它项目引用便是,项目如图:
AbsSim是抽象类,负责实现手机操作的类。不同的厂家继承该类实现各自的接口。AbsSim信息如下:
public abstract class AbsSim implements IDualDetector { //抽象基类 protected final String TAG = getClass().getSimpleName(); protected ArrayList mSimSlots = new ArrayList(); protected boolean mIsDualSimPhone = false ; protected String mCallLogExtraField = "" ; public abstract String getSimPhoneNumber( int paramInt); // 返回手机号码 public abstract int getDataState( int paramInt); // 返回数据状态 public abstract String getIMSI( int paramInt); // 返回手机标识 public abstract String getIMSI( int paramInt, Context paramContext); // 返回手机标识 public abstract int getPhoneState( int paramInt); // 返回手机状态 public abstract boolean isServiceAvaliable( int paramInt); // 服务是否可用 public abstract boolean isSimStateIsReady( int paramInt); // 卡是否在使用 public abstract int getSimOperator( int paramInt); // 服务商(电信、移动、联通) protected abstract Object getITelephonyMSim( int paramInt); // 获取操作接口 protected abstract Object getMSimTelephonyManager( int paramInt); // 获取操作接口 @Override public AbsSim detect() { // 根据手机信息匹配 if ((getITelephonyMSim( 0 ) != null ) && (getITelephonyMSim( 1 ) != null ) // && (getmMSimSmsManager(0) != null) // && (getmMSimSmsManager(1) != null) // && (detectSms(paramContext, paramBoolean)) // && (detectCallLog(paramContext, paramBoolean)) ) return this ; return null ; } public boolean directCall(String paramString, int paramInt) { // 拨打电话(根据不同卡拨打电话) Intent localIntent = new Intent( "android.intent.action.CALL" , Uri.fromParts( "tel" , paramString, null )); localIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); try { getContext().startActivity(localIntent); return true ; } catch (Throwable localThrowable) { localThrowable.printStackTrace(); } return false ; } protected boolean detectCallLog() { // 通过通话记录信息匹配 return false ; } protected boolean detectSms() { // 通过短信记录信息匹配 return false ; } protected Context getContext() { // 返回句柄 return SimManager.getInstance().getContext(); } protected int getSimSlotNum() { // 返回插槽个数(默认2) return 2 ; } public void init() { // 初始化 for ( int i = 0 ; i < getSimSlotNum(); i++) { try { String imsi = getIMSI(i); boolean isUsing = isSimStateIsReady(i); if (imsi != null || isUsing) { if (imsi == null || hasSimSlotByIMSI(imsi)) continue ; SimSlot simSlot = new SimSlot(); mSimSlots.add(simSlot); simSlot.setUsing(isUsing); simSlot.setIMSI(imsi); simSlot.setSimOperator(getSimOperator(i)); } } catch (Exception e) { e.printStackTrace(); } } } public boolean hasSimPhone() { // 是否有sd卡在使用 if (mSimSlots.isEmpty()) return false ; for (SimSlot simslot : mSimSlots) { if (simslot.isUsing()) return true ; } return false ; } public boolean isDualSimPhone() { // 是否为双卡 if (getSimSlots().isEmpty() || getSimSlots().size() < 2 ) return false ; for (SimSlot simSlot : getSimSlots()) { if (!simSlot.isUsing()) return false ; } return true ; } public ArrayList getSimSlots() { // 返回已确认的卡 return mSimSlots; } protected boolean delSimSlotByIMSI(String imsi) { // 删除相同的卡的信息 for (SimSlot simSlot : getSimSlots()) { if (simSlot.getIMSI() != null && simSlot.getIMSI().equals(imsi)) { getSimSlots().remove(simSlot); } } return false ; } protected boolean hasSimSlotByIMSI(String imsi) { for (SimSlot simSlot : getSimSlots()) { if (simSlot.getIMSI() != null && simSlot.getIMSI().equals(imsi)) { return true ; } } return false ; } } |
现在列举一款实现MTK方案:
public class MTKDualSim extends AbsSim { // 采用MTK方案的类(根据厂家SDK实现不同的接口) private Object mMSimTelephonyManager = null ; private Object mTelephonyMSim = null ; public MTKDualSim() { mCallLogExtraField = "simid" ; String str1 = SimManager.getModel(); String str2 = SimManager.getManufaturer(); if ((str1 != null ) && (str2 != null )) { String str3 = str1.toLowerCase(); String str4 = str2.toLowerCase(); if ((str4.indexOf( "huawei" ) > - 1 ) && (str3.indexOf( "h30-t00" ) > - 1 )) mCallLogExtraField = "subscription" ; if ((str4.indexOf( "hisense" ) > - 1 ) && (str3.indexOf( "hs-u970" ) > - 1 )) { mCallLogExtraField = "subtype" ; } } } @Override public boolean directCall(String paramString, int paramInt) { if (SimManager.isSDKVersionMore4_1()) { Intent localIntent1 = new Intent( "android.intent.action.CALL" , Uri.fromParts( "tel" , paramString, null )); localIntent1.putExtra( "simId" , paramInt); localIntent1.putExtra( "com.android.phone.extra.slot" , paramInt); localIntent1.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); try { getContext().startActivity(localIntent1); return true ; } catch (Throwable localThrowable1) { localThrowable1.printStackTrace(); } } else if (SimManager.isSDKVersionMore4_0()) { Intent localIntent2 = new Intent( "com.android.phone.OutgoingCallReceiver" ); localIntent2.putExtra( "com.android.phone.extra.slot" , paramInt); localIntent2.putExtra( "simId" , paramInt); localIntent2.putExtra( "com.android.phone.force.slot" , true ); localIntent2.setClassName( "com.android.phone" , "com.android.phone.OutgoingCallReceiver" ); localIntent2.setData(Uri.fromParts( "tel" , paramString, null )); try { getContext().sendBroadcast(localIntent2); return true ; } catch (Throwable localThrowable2) { localThrowable2.printStackTrace(); } } try { Intent localIntent3 = new Intent(); localIntent3.setAction( "out_going_call_to_phone_app" ); localIntent3.putExtra( "number" , paramString); localIntent3.putExtra( "simId" , paramInt); localIntent3.putExtra( "com.android.phone.extra.slot" , paramInt); localIntent3.putExtra( "launch_from_dialer" , 1 ); localIntent3.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); getContext().sendBroadcast(localIntent3); return true ; } catch (Throwable localThrowable3) { localThrowable3.printStackTrace(); } return false ; } @Override public AbsSim detect() { String imsi = getIMSI( 0 ); if (imsi != null && !TextUtils.isEmpty(imsi)) { return this ; } return super .detect(); } @Override public String getSimPhoneNumber( int paramInt) { Object[] arrayOfObject2 = new Object[ 1 ]; try { Object localObject = getMSimTelephonyManager(paramInt); arrayOfObject2[ 0 ] = Integer.valueOf(paramInt); String result = (String) ReflecterHelper.invokeMethod(localObject, "getLine1NumberGemini" , arrayOfObject2); arrayOfObject2 = null ; return result; } catch (Throwable localThrowable) { localThrowable.printStackTrace(); } return "" ; } @Override public int getDataState( int paramInt) { Object[] arrayOfObject2 = new Object[ 1 ]; try { Object localObject = getMSimTelephonyManager(paramInt); arrayOfObject2[ 0 ] = Integer.valueOf(paramInt); int result = ((Integer) ReflecterHelper.invokeMethod(localObject, "getDataStateGemini" , arrayOfObject2)).intValue(); arrayOfObject2 = null ; return result; } catch (Throwable localThrowable) { localThrowable.printStackTrace(); } arrayOfObject2 = null ; return - 1 ; } @Override public String getIMSI( int paramInt) { return getIMSI(paramInt, null ); } @Override public String getIMSI( int paramInt, Context paramContext) { Object localObject = getMSimTelephonyManager(paramInt); Object[] arrayOfObject2 = new Object[ 1 ]; try { arrayOfObject2[ 0 ] = Integer.valueOf(paramInt); String result = (String) ReflecterHelper.invokeMethod(localObject, "getSubscriberIdGemini" , arrayOfObject2); arrayOfObject2 = null ; return result; } catch (Throwable localThrowable) { localThrowable.printStackTrace(); } arrayOfObject2 = null ; return null ; } @Override public int getPhoneState( int paramInt) { Object localObject = getMSimTelephonyManager(paramInt); Object[] arrayOfObject2 = new Object[ 1 ]; try { arrayOfObject2[ 0 ] = Integer.valueOf(paramInt); int result = ((Integer) ReflecterHelper.invokeMethod(localObject, "getCallStateGemini" , arrayOfObject2)).intValue(); arrayOfObject2 = null ; return result; } catch (Throwable localThrowable) { localThrowable.printStackTrace(); } arrayOfObject2 = null ; return 0 ; } @Override public boolean isServiceAvaliable( int paramInt) { Object localObject = getITelephonyMSim(paramInt); if (localObject == null ) return false ; Object[] arrayOfObject2 = new Object[ 1 ]; try { arrayOfObject2[ 0 ] = Integer.valueOf(paramInt); boolean result = ((Boolean) ReflecterHelper.invokeMethod( localObject, "isRadioOnGemini" , arrayOfObject2)) .booleanValue(); arrayOfObject2 = null ; return result; } catch (Throwable localThrowable) { localThrowable.printStackTrace(); } arrayOfObject2 = null ; return false ; } @Override public boolean isSimStateIsReady( int paramInt) { Object localObject = getMSimTelephonyManager(paramInt); if (localObject != null ) { Object[] arrayOfObject2 = new Object[ 1 ]; try { arrayOfObject2[ 0 ] = Integer.valueOf(paramInt); int result = ((Integer) ReflecterHelper.invokeMethod( localObject, "getSimStateGemini" , arrayOfObject2)) .intValue(); arrayOfObject2 = null ; return result == 5 ; } catch (Throwable localThrowable) { localThrowable.printStackTrace(); } arrayOfObject2 = null ; } return false ; } @Override public int getSimOperator( int paramInt) { // 注意 Object localObject = getMSimTelephonyManager(paramInt); Object[] arrayOfObject2 = new Object[ 1 ]; try { arrayOfObject2[ 0 ] = Integer.valueOf(paramInt); String result = ((String) ReflecterHelper.invokeMethod(localObject, "getSimOperatorGemini" , arrayOfObject2)); arrayOfObject2 = null ; return Integer.valueOf(result); } catch (Throwable localThrowable) { localThrowable.printStackTrace(); } arrayOfObject2 = null ; return 0 ; } @Override protected Object getITelephonyMSim( int paramInt) { if (mTelephonyMSim == null ) mTelephonyMSim = ITelephony.Stub.asInterface(ServiceManager .getService( "phone" )); return mTelephonyMSim; } @Override protected Object getMSimTelephonyManager( int paramInt) { if (mMSimTelephonyManager != null ) return mMSimTelephonyManager; Object[] arrayOfObject3 = new Object[ 1 ]; try { mMSimTelephonyManager = SimManager.getInstance() .getTelephonyManagerByPhone(); try { Object localObject = mMSimTelephonyManager; arrayOfObject3[ 0 ] = Integer.valueOf( 0 ); ReflecterHelper.invokeMethod(localObject, "getSubscriberIdGemini" , arrayOfObject3); arrayOfObject3 = null ; return mMSimTelephonyManager; } catch (Throwable localThrowable2) { localThrowable2.printStackTrace(); } } catch (Throwable localThrowable1) { localThrowable1.printStackTrace(); } arrayOfObject3 = null ; return null ; } } |
再列举一款单卡的方案:
public class SingleSim extends AbsSim implements IDualDetector { // 单卡方案 private final String TAG = getClass().getSimpleName(); private HashMap<String, Byte> mCallLogExtraFields = new SingleSim$ 1 ( this ); @Override public boolean hasSimPhone() { return false ; } @Override public AbsSim detect() { // 根据某些字段判是否为双卡(有可能误判) if (mIsDualSimPhone) return null ; Cursor localSafeCursor = null ; String[] arrayOfString; try { localSafeCursor = SimManager .getInstance() .getContext() .getContentResolver() .query(CallLog.Calls.CONTENT_URI, null , null , null , "_id limit 0,1" ); if (localSafeCursor != null && localSafeCursor.moveToFirst()) { arrayOfString = localSafeCursor.getColumnNames(); for ( int i = 0 ; i < arrayOfString.length; i++) { String str = arrayOfString[i]; if (mCallLogExtraFields.containsKey(str.toLowerCase())) { mIsDualSimPhone = true ; mCallLogExtraField = str; } } } } catch (Exception e) { e.printStackTrace(); } return this ; } @Override public boolean isDualSimPhone() { return mIsDualSimPhone; } @Override public int getSimSlotNum() { return 1 ; } @Override public String getSimPhoneNumber( int paramInt) { return ((TelephonyManager) getMSimTelephonyManager( 0 )).getLine1Number(); } @Override public int getDataState( int paramInt) { return ((TelephonyManager) getMSimTelephonyManager( 0 )).getDataState(); } @Override public String getIMSI( int paramInt) { return ((TelephonyManager) getMSimTelephonyManager( 0 )).getDeviceId(); } @Override public String getIMSI( int paramInt, Context paramContext) { return ((TelephonyManager) getMSimTelephonyManager( 0 )) .getSubscriberId(); } @Override public int getPhoneState( int paramInt) { return ((TelephonyManager) getMSimTelephonyManager( 0 )).getCallState(); } @Override public boolean isServiceAvaliable( int paramInt) { ITelephony localITelephony = (ITelephony) getITelephonyMSim( 0 ); if (localITelephony == null ) return false ; try { boolean bool = localITelephony.isRadioOn(); return bool; } catch (Throwable localThrowable) { localThrowable.printStackTrace(); } return false ; } @Override public boolean isSimStateIsReady( int paramInt) { return ((TelephonyManager) getMSimTelephonyManager( 0 )).getSimState() == 5 ; } @Override public int getSimOperator( int paramInt) { TelephonyManager localTelephonyManager = (TelephonyManager) getMSimTelephonyManager(paramInt); return Integer.parseInt(localTelephonyManager.getSimOperator()); } @Override protected Object getITelephonyMSim( int paramInt) { return SimManager.getInstance().getITelephonyByPhone(); } @Override protected Object getMSimTelephonyManager( int paramInt) { return SimManager.getInstance().getTelephonyManagerByPhone(); } } |
总结
利用java 反射机制操作Android隐藏的类,很好的解决了双卡双待的问题。
Java反射是 Java被视为动态(或准动态)语言的一个关键性质。这个机制允许程序在运行时透过Reflection APIs取得任何一个已知名称的class的内部信息,包括其modifiers(诸如public, static 等)、superclass(例如Object)、实现之interfaces(例如Cloneable),也包括fields和methods的所有信 息,并可于运行时改变fields内容或唤起methods。