android学习笔记---双卡双待

简介

Android双卡双待已经越来越普及了,解决双卡双待管理是广大手机开发人员必须得面对的问题,为实现Android平台的双卡双待操作,笔者研究了Android 应用层操作双卡双待的机制。


机制

获取基于ITelephony接口实现phone应用中的“phone服务”,通过TelephonyManager接口获取不同的卡(GSMPhone /CDMAPhone)进行不同的操作(拨号、接通、挂断、保持通话等)。

Android平台是一个多样型的平台,不同的手机获取ITelephony接口不同,用一种方法实现双卡双待管理是不可取的。那怎么办呢?只有针对不同的手机分析出一套管理的方案,该方案实现难度大,因为需要各个厂家的SDK的资料。为了实现该功能,笔者做了大量工作,整合各个厂家的SDK的资料。


实现

为了更好的管理双卡双待的问题,新建一个双卡双待模块静态库,其它项目引用便是,项目如图:



AbsSim是抽象类,负责实现手机操作的类。不同的厂家继承该类实现各自的接口。AbsSim信息如下:

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. public abstract class AbsSim implements IDualDetector { //抽象基类  
  2.     protected final String TAG = getClass().getSimpleName();  
  3.     protected ArrayList<SimSlot> mSimSlots = new ArrayList<SimSlot>();  
  4.     protected boolean mIsDualSimPhone = false;  
  5.     protected String mCallLogExtraField = "";  
  6.   
  7.     public abstract String getSimPhoneNumber(int paramInt); // 返回手机号码  
  8.   
  9.     public abstract int getDataState(int paramInt);// 返回数据状态  
  10.   
  11.     public abstract String getIMSI(int paramInt);// 返回手机标识  
  12.   
  13.     public abstract String getIMSI(int paramInt, Context paramContext);// 返回手机标识  
  14.   
  15.     public abstract int getPhoneState(int paramInt);// 返回手机状态  
  16.   
  17.     public abstract boolean isServiceAvaliable(int paramInt);// 服务是否可用  
  18.   
  19.     public abstract boolean isSimStateIsReady(int paramInt);// 卡是否在使用  
  20.   
  21.     public abstract int getSimOperator(int paramInt);// 服务商(电信、移动、联通)  
  22.   
  23.     protected abstract Object getITelephonyMSim(int paramInt);// 获取操作接口  
  24.   
  25.     protected abstract Object getMSimTelephonyManager(int paramInt);// 获取操作接口  
  26.   
  27.     @Override  
  28.     public AbsSim detect() { // 根据手机信息匹配  
  29.         if ((getITelephonyMSim(0) != null) && (getITelephonyMSim(1) != null)  
  30.         // && (getmMSimSmsManager(0) != null)  
  31.         // && (getmMSimSmsManager(1) != null)  
  32.         // && (detectSms(paramContext, paramBoolean))  
  33.         // && (detectCallLog(paramContext, paramBoolean))  
  34.         )  
  35.             return this;  
  36.         return null;  
  37.     }  
  38.   
  39.     public boolean directCall(String paramString, int paramInt) { // 拨打电话(根据不同卡拨打电话)  
  40.         Intent localIntent = new Intent("android.intent.action.CALL",  
  41.                 Uri.fromParts("tel", paramString, null));  
  42.         localIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);  
  43.         try {  
  44.             getContext().startActivity(localIntent);  
  45.             return true;  
  46.         } catch (Throwable localThrowable) {  
  47.             localThrowable.printStackTrace();  
  48.         }  
  49.         return false;  
  50.     }  
  51.   
  52.     protected boolean detectCallLog() { // 通过通话记录信息匹配  
  53.         return false;  
  54.     }  
  55.   
  56.     protected boolean detectSms() {// 通过短信记录信息匹配  
  57.         return false;  
  58.     }  
  59.   
  60.     protected Context getContext() { // 返回句柄  
  61.         return SimManager.getInstance().getContext();  
  62.     }  
  63.   
  64.     protected int getSimSlotNum() { // 返回插槽个数(默认2)  
  65.         return 2;  
  66.     }  
  67.   
  68.     public void init() { // 初始化  
  69.         for (int i = 0; i < getSimSlotNum(); i++) {  
  70.             try {  
  71.                 String imsi = getIMSI(i);  
  72.                 boolean isUsing = isSimStateIsReady(i);  
  73.                 if (imsi != null || isUsing) {  
  74.                     if (imsi == null || hasSimSlotByIMSI(imsi))  
  75.                         continue;  
  76.   
  77.                     SimSlot simSlot = new SimSlot();  
  78.                     mSimSlots.add(simSlot);  
  79.                     simSlot.setUsing(isUsing);  
  80.                     simSlot.setIMSI(imsi);  
  81.                     simSlot.setSimOperator(getSimOperator(i));  
  82.                 }  
  83.             } catch (Exception e) {  
  84.                 e.printStackTrace();  
  85.             }  
  86.         }  
  87.     }  
  88.   
  89.     public boolean hasSimPhone() {// 是否有sd卡在使用  
  90.         if (mSimSlots.isEmpty())  
  91.             return false;  
  92.   
  93.         for (SimSlot simslot : mSimSlots) {  
  94.             if (simslot.isUsing())  
  95.                 return true;  
  96.         }  
  97.   
  98.         return false;  
  99.     }  
  100.   
  101.     public boolean isDualSimPhone() {// 是否为双卡  
  102.         if (getSimSlots().isEmpty() || getSimSlots().size() < 2)  
  103.             return false;  
  104.   
  105.         for (SimSlot simSlot : getSimSlots()) {  
  106.             if (!simSlot.isUsing())  
  107.                 return false;  
  108.         }  
  109.   
  110.         return true;  
  111.     }  
  112.   
  113.     public ArrayList<SimSlot> getSimSlots() { // 返回已确认的卡  
  114.         return mSimSlots;  
  115.     }  
  116.   
  117.     protected boolean delSimSlotByIMSI(String imsi) { // 删除相同的卡的信息  
  118.         for (SimSlot simSlot : getSimSlots()) {  
  119.             if (simSlot.getIMSI() != null && simSlot.getIMSI().equals(imsi)) {  
  120.                 getSimSlots().remove(simSlot);  
  121.             }  
  122.         }  
  123.   
  124.         return false;  
  125.     }  
  126.   
  127.     protected boolean hasSimSlotByIMSI(String imsi) {  
  128.         for (SimSlot simSlot : getSimSlots()) {  
  129.             if (simSlot.getIMSI() != null && simSlot.getIMSI().equals(imsi)) {  
  130.                 return true;  
  131.             }  
  132.         }  
  133.   
  134.         return false;  
  135.     }  
  136. }  

现在列举一款实现MTK方案:

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. public class MTKDualSim extends AbsSim {// 采用MTK方案的类(根据厂家SDK实现不同的接口)  
  2.     private Object mMSimTelephonyManager = null;  
  3.     private Object mTelephonyMSim = null;  
  4.   
  5.     public MTKDualSim() {  
  6.         mCallLogExtraField = "simid";  
  7.   
  8.         String str1 = SimManager.getModel();  
  9.         String str2 = SimManager.getManufaturer();  
  10.         if ((str1 != null) && (str2 != null)) {  
  11.             String str3 = str1.toLowerCase();  
  12.             String str4 = str2.toLowerCase();  
  13.             if ((str4.indexOf("huawei") > -1) && (str3.indexOf("h30-t00") > -1))  
  14.                 mCallLogExtraField = "subscription";  
  15.             if ((str4.indexOf("hisense") > -1)  
  16.                     && (str3.indexOf("hs-u970") > -1)) {  
  17.                 mCallLogExtraField = "subtype";  
  18.             }  
  19.         }  
  20.     }  
  21.   
  22.     @Override  
  23.     public boolean directCall(String paramString, int paramInt) {  
  24.         if (SimManager.isSDKVersionMore4_1()) {  
  25.             Intent localIntent1 = new Intent("android.intent.action.CALL",  
  26.                     Uri.fromParts("tel", paramString, null));  
  27.             localIntent1.putExtra("simId", paramInt);  
  28.             localIntent1.putExtra("com.android.phone.extra.slot", paramInt);  
  29.             localIntent1.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);  
  30.             try {  
  31.                 getContext().startActivity(localIntent1);  
  32.                 return true;  
  33.             } catch (Throwable localThrowable1) {  
  34.                 localThrowable1.printStackTrace();  
  35.             }  
  36.         } else if (SimManager.isSDKVersionMore4_0()) {  
  37.             Intent localIntent2 = new Intent(  
  38.                     "com.android.phone.OutgoingCallReceiver");  
  39.             localIntent2.putExtra("com.android.phone.extra.slot", paramInt);  
  40.             localIntent2.putExtra("simId", paramInt);  
  41.             localIntent2.putExtra("com.android.phone.force.slot"true);  
  42.             localIntent2.setClassName("com.android.phone",  
  43.                     "com.android.phone.OutgoingCallReceiver");  
  44.             localIntent2.setData(Uri.fromParts("tel", paramString, null));  
  45.             try {  
  46.                 getContext().sendBroadcast(localIntent2);  
  47.                 return true;  
  48.             } catch (Throwable localThrowable2) {  
  49.                 localThrowable2.printStackTrace();  
  50.             }  
  51.         }  
  52.   
  53.         try {  
  54.             Intent localIntent3 = new Intent();  
  55.             localIntent3.setAction("out_going_call_to_phone_app");  
  56.             localIntent3.putExtra("number", paramString);  
  57.             localIntent3.putExtra("simId", paramInt);  
  58.             localIntent3.putExtra("com.android.phone.extra.slot", paramInt);  
  59.             localIntent3.putExtra("launch_from_dialer", 1);  
  60.             localIntent3.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);  
  61.             getContext().sendBroadcast(localIntent3);  
  62.             return true;  
  63.         } catch (Throwable localThrowable3) {  
  64.             localThrowable3.printStackTrace();  
  65.         }  
  66.         return false;  
  67.     }  
  68.   
  69.     @Override  
  70.     public AbsSim detect() {  
  71.         String imsi = getIMSI(0);  
  72.         if (imsi != null && !TextUtils.isEmpty(imsi)) {  
  73.             return this;  
  74.         }  
  75.   
  76.         return super.detect();  
  77.     }  
  78.   
  79.     @Override  
  80.     public String getSimPhoneNumber(int paramInt) {  
  81.         Object[] arrayOfObject2 = new Object[1];  
  82.         try {  
  83.             Object localObject = getMSimTelephonyManager(paramInt);  
  84.             arrayOfObject2[0] = Integer.valueOf(paramInt);  
  85.             String result = (String) ReflecterHelper.invokeMethod(localObject,  
  86.                     "getLine1NumberGemini", arrayOfObject2);  
  87.             arrayOfObject2 = null;  
  88.             return result;  
  89.         } catch (Throwable localThrowable) {  
  90.             localThrowable.printStackTrace();  
  91.         }  
  92.         return "";  
  93.     }  
  94.   
  95.     @Override  
  96.     public int getDataState(int paramInt) {  
  97.         Object[] arrayOfObject2 = new Object[1];  
  98.         try {  
  99.             Object localObject = getMSimTelephonyManager(paramInt);  
  100.             arrayOfObject2[0] = Integer.valueOf(paramInt);  
  101.             int result = ((Integer) ReflecterHelper.invokeMethod(localObject,  
  102.                     "getDataStateGemini", arrayOfObject2)).intValue();  
  103.             arrayOfObject2 = null;  
  104.             return result;  
  105.         } catch (Throwable localThrowable) {  
  106.             localThrowable.printStackTrace();  
  107.         }  
  108.         arrayOfObject2 = null;  
  109.         return -1;  
  110.     }  
  111.   
  112.     @Override  
  113.     public String getIMSI(int paramInt) {  
  114.         return getIMSI(paramInt, null);  
  115.     }  
  116.   
  117.     @Override  
  118.     public String getIMSI(int paramInt, Context paramContext) {  
  119.         Object localObject = getMSimTelephonyManager(paramInt);  
  120.         Object[] arrayOfObject2 = new Object[1];  
  121.         try {  
  122.             arrayOfObject2[0] = Integer.valueOf(paramInt);  
  123.             String result = (String) ReflecterHelper.invokeMethod(localObject,  
  124.                     "getSubscriberIdGemini", arrayOfObject2);  
  125.             arrayOfObject2 = null;  
  126.             return result;  
  127.         } catch (Throwable localThrowable) {  
  128.             localThrowable.printStackTrace();  
  129.         }  
  130.         arrayOfObject2 = null;  
  131.         return null;  
  132.     }  
  133.   
  134.     @Override  
  135.     public int getPhoneState(int paramInt) {  
  136.         Object localObject = getMSimTelephonyManager(paramInt);  
  137.         Object[] arrayOfObject2 = new Object[1];  
  138.         try {  
  139.             arrayOfObject2[0] = Integer.valueOf(paramInt);  
  140.             int result = ((Integer) ReflecterHelper.invokeMethod(localObject,  
  141.                     "getCallStateGemini", arrayOfObject2)).intValue();  
  142.             arrayOfObject2 = null;  
  143.             return result;  
  144.         } catch (Throwable localThrowable) {  
  145.             localThrowable.printStackTrace();  
  146.         }  
  147.         arrayOfObject2 = null;  
  148.         return 0;  
  149.     }  
  150.   
  151.     @Override  
  152.     public boolean isServiceAvaliable(int paramInt) {  
  153.         Object localObject = getITelephonyMSim(paramInt);  
  154.         if (localObject == null)  
  155.             return false;  
  156.         Object[] arrayOfObject2 = new Object[1];  
  157.         try {  
  158.             arrayOfObject2[0] = Integer.valueOf(paramInt);  
  159.             boolean result = ((Boolean) ReflecterHelper.invokeMethod(  
  160.                     localObject, "isRadioOnGemini", arrayOfObject2))  
  161.                     .booleanValue();  
  162.             arrayOfObject2 = null;  
  163.             return result;  
  164.         } catch (Throwable localThrowable) {  
  165.             localThrowable.printStackTrace();  
  166.         }  
  167.         arrayOfObject2 = null;  
  168.         return false;  
  169.     }  
  170.   
  171.     @Override  
  172.     public boolean isSimStateIsReady(int paramInt) {  
  173.         Object localObject = getMSimTelephonyManager(paramInt);  
  174.         if (localObject != null) {  
  175.             Object[] arrayOfObject2 = new Object[1];  
  176.             try {  
  177.                 arrayOfObject2[0] = Integer.valueOf(paramInt);  
  178.                 int result = ((Integer) ReflecterHelper.invokeMethod(  
  179.                         localObject, "getSimStateGemini", arrayOfObject2))  
  180.                         .intValue();  
  181.                 arrayOfObject2 = null;  
  182.                 return result == 5;  
  183.             } catch (Throwable localThrowable) {  
  184.                 localThrowable.printStackTrace();  
  185.             }  
  186.             arrayOfObject2 = null;  
  187.         }  
  188.   
  189.         return false;  
  190.     }  
  191.   
  192.     @Override  
  193.     public int getSimOperator(int paramInt) { // 注意  
  194.         Object localObject = getMSimTelephonyManager(paramInt);  
  195.         Object[] arrayOfObject2 = new Object[1];  
  196.         try {  
  197.             arrayOfObject2[0] = Integer.valueOf(paramInt);  
  198.             String result = ((String) ReflecterHelper.invokeMethod(localObject,  
  199.                     "getSimOperatorGemini", arrayOfObject2));  
  200.             arrayOfObject2 = null;  
  201.             return Integer.valueOf(result);  
  202.         } catch (Throwable localThrowable) {  
  203.             localThrowable.printStackTrace();  
  204.         }  
  205.         arrayOfObject2 = null;  
  206.         return 0;  
  207.     }  
  208.   
  209.     @Override  
  210.     protected Object getITelephonyMSim(int paramInt) {  
  211.         if (mTelephonyMSim == null)  
  212.             mTelephonyMSim = ITelephony.Stub.asInterface(ServiceManager  
  213.                     .getService("phone"));  
  214.         return mTelephonyMSim;  
  215.     }  
  216.   
  217.     @Override  
  218.     protected Object getMSimTelephonyManager(int paramInt) {  
  219.         if (mMSimTelephonyManager != null)  
  220.             return mMSimTelephonyManager;  
  221.         Object[] arrayOfObject3 = new Object[1];  
  222.         try {  
  223.             mMSimTelephonyManager = SimManager.getInstance()  
  224.                     .getTelephonyManagerByPhone();  
  225.             try {  
  226.                 Object localObject = mMSimTelephonyManager;  
  227.                 arrayOfObject3[0] = Integer.valueOf(0);  
  228.                 ReflecterHelper.invokeMethod(localObject,  
  229.                         "getSubscriberIdGemini", arrayOfObject3);  
  230.                 arrayOfObject3 = null;  
  231.                 return mMSimTelephonyManager;  
  232.             } catch (Throwable localThrowable2) {  
  233.                 localThrowable2.printStackTrace();  
  234.             }  
  235.         } catch (Throwable localThrowable1) {  
  236.             localThrowable1.printStackTrace();  
  237.         }  
  238.         arrayOfObject3 = null;  
  239.         return null;  
  240.     }  
  241. }  

再列举一款单卡的方案:

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. public class SingleSim extends AbsSim implements IDualDetector {// 单卡方案  
  2.     private final String TAG = getClass().getSimpleName();  
  3.     private HashMap<String, Byte> mCallLogExtraFields = new SingleSim$1(this);  
  4.   
  5.     @Override  
  6.     public boolean hasSimPhone() {  
  7.         return false;  
  8.     }  
  9.   
  10.     @Override  
  11.     public AbsSim detect() {// 根据某些字段判是否为双卡(有可能误判)  
  12.         if (mIsDualSimPhone)  
  13.             return null;  
  14.   
  15.         Cursor localSafeCursor = null;  
  16.         String[] arrayOfString;  
  17.         try {  
  18.             localSafeCursor = SimManager  
  19.                     .getInstance()  
  20.                     .getContext()  
  21.                     .getContentResolver()  
  22.                     .query(CallLog.Calls.CONTENT_URI, null, null, null,  
  23.                             "_id limit 0,1");  
  24.   
  25.             if (localSafeCursor != null && localSafeCursor.moveToFirst()) {  
  26.                 arrayOfString = localSafeCursor.getColumnNames();  
  27.   
  28.                 for (int i = 0; i < arrayOfString.length; i++) {  
  29.                     String str = arrayOfString[i];  
  30.                     if (mCallLogExtraFields.containsKey(str.toLowerCase())) {  
  31.                         mIsDualSimPhone = true;  
  32.                         mCallLogExtraField = str;  
  33.                     }  
  34.                 }  
  35.   
  36.             }  
  37.         } catch (Exception e) {  
  38.             e.printStackTrace();  
  39.         }  
  40.   
  41.         return this;  
  42.     }  
  43.   
  44.     @Override  
  45.     public boolean isDualSimPhone() {  
  46.         return mIsDualSimPhone;  
  47.     }  
  48.   
  49.     @Override  
  50.     public int getSimSlotNum() {  
  51.         return 1;  
  52.     }  
  53.   
  54.     @Override  
  55.     public String getSimPhoneNumber(int paramInt) {  
  56.         return ((TelephonyManager) getMSimTelephonyManager(0)).getLine1Number();  
  57.     }  
  58.   
  59.     @Override  
  60.     public int getDataState(int paramInt) {  
  61.         return ((TelephonyManager) getMSimTelephonyManager(0)).getDataState();  
  62.     }  
  63.   
  64.     @Override  
  65.     public String getIMSI(int paramInt) {  
  66.         return ((TelephonyManager) getMSimTelephonyManager(0)).getDeviceId();  
  67.     }  
  68.   
  69.     @Override  
  70.     public String getIMSI(int paramInt, Context paramContext) {  
  71.         return ((TelephonyManager) getMSimTelephonyManager(0))  
  72.                 .getSubscriberId();  
  73.     }  
  74.   
  75.     @Override  
  76.     public int getPhoneState(int paramInt) {  
  77.         return ((TelephonyManager) getMSimTelephonyManager(0)).getCallState();  
  78.     }  
  79.   
  80.     @Override  
  81.     public boolean isServiceAvaliable(int paramInt) {  
  82.         ITelephony localITelephony = (ITelephony) getITelephonyMSim(0);  
  83.         if (localITelephony == null)  
  84.             return false;  
  85.         try {  
  86.             boolean bool = localITelephony.isRadioOn();  
  87.             return bool;  
  88.         } catch (Throwable localThrowable) {  
  89.             localThrowable.printStackTrace();  
  90.         }  
  91.         return false;  
  92.     }  
  93.   
  94.     @Override  
  95.     public boolean isSimStateIsReady(int paramInt) {  
  96.         return ((TelephonyManager) getMSimTelephonyManager(0)).getSimState() == 5;  
  97.     }  
  98.   
  99.     @Override  
  100.     public int getSimOperator(int paramInt) {  
  101.         TelephonyManager localTelephonyManager = (TelephonyManager) getMSimTelephonyManager(paramInt);  
  102.         return Integer.parseInt(localTelephonyManager.getSimOperator());  
  103.     }  
  104.   
  105.     @Override  
  106.     protected Object getITelephonyMSim(int paramInt) {  
  107.         return SimManager.getInstance().getITelephonyByPhone();  
  108.     }  
  109.   
  110.     @Override  
  111.     protected Object getMSimTelephonyManager(int paramInt) {  
  112.         return SimManager.getInstance().getTelephonyManagerByPhone();  
  113.     }  
  114. }  

总结

利用java 反射机制操作Android隐藏的类,很好的解决了双卡双待的问题。
Java反射是Java被视为动态(或准动态)语言的一个关键性质。这个机制允许程序在运行时透过Reflection APIs取得任何一个已知名称的class的内部信息,包括其modifiers(诸如public, static 等)、superclass(例如Object)、实现之interfaces(例如Cloneable),也包括fields和methods的所有信息,并可于运行时改变fields内容或唤起methods。


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值