解決 Android 雙卡雙待識別
Android開發的問題 其實很好狠。今天看到一篇解決android 機型 雙卡 管理的問題。看到一篇比較好的文章就轉載過來了 = =
轉載:http://blog.csdn.net/banketree/article/details/24306493

獲取基於ITelephony介面實現phone應用中的“phone服務”,通過TelephonyManager介面獲取不同的卡(GSMPhone /CDMAPhone)進行不同的操作(撥號、接通、結束通話、保持通話等)。

Android平臺是一個多樣型的平臺,不同的手機獲取ITelephony介面不同,用一種方法實現雙卡雙待管理是不可取的。那怎麼辦呢?只有針對不同的手機分析出一套管理的方案,該方案實現難度大,因為需要各個廠家的SDK的資料。為了實現該功能,筆者做了大量工作,整合各個廠家的SDK的資料。

實現

為了更好的管理雙卡雙待的問題,新建一個雙卡雙待模組靜態庫,其它專案引用便是,專案如圖:

效果如圖:

小米手機 測試效果

華為手機測試效果

AbsSim是抽象類,負責實現手機操作的類。不同的廠家繼承該類實現各自的介面。AbsSim資訊如下:

  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方案:

  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. }  

再列舉一款單卡的方案:

  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。

專案下載