A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 陈君 金牌黑马   /  2014-9-17 18:21  /  4924 人查看  /  8 人回复  /   2 人收藏 转载请遵从CC协议 禁止商业使用本文

简介

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



机制

获取基于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. public abstract String getSimPhoneNumber(int paramInt); // 返回手机号码

  7. public abstract int getDataState(int paramInt);// 返回数据状态

  8. public abstract String getIMSI(int paramInt);// 返回手机标识

  9. public abstract String getIMSI(int paramInt, Context paramContext);// 返回手机标识

  10. public abstract int getPhoneState(int paramInt);// 返回手机状态

  11. public abstract boolean isServiceAvaliable(int paramInt);// 服务是否可用

  12. public abstract boolean isSimStateIsReady(int paramInt);// 卡是否在使用

  13. public abstract int getSimOperator(int paramInt);// 服务商(电信、移动、联通)

  14. protected abstract Object getITelephonyMSim(int paramInt);// 获取操作接口

  15. protected abstract Object getMSimTelephonyManager(int paramInt);// 获取操作接口

  16. @Override
  17. public AbsSim detect() { // 根据手机信息匹配
  18. if ((getITelephonyMSim(0) != null) && (getITelephonyMSim(1) != null)
  19. // && (getmMSimSmsManager(0) != null)
  20. // && (getmMSimSmsManager(1) != null)
  21. // && (detectSms(paramContext, paramBoolean))
  22. // && (detectCallLog(paramContext, paramBoolean))
  23. )
  24. return this;
  25. return null;
  26. }

  27. public boolean directCall(String paramString, int paramInt) { // 拨打电话(根据不同卡拨打电话)
  28. Intent localIntent = new Intent("android.intent.action.CALL",
  29. Uri.fromParts("tel", paramString, null));
  30. localIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
  31. try {
  32. getContext().startActivity(localIntent);
  33. return true;
  34. } catch (Throwable localThrowable) {
  35. localThrowable.printStackTrace();
  36. }
  37. return false;
  38. }

  39. protected boolean detectCallLog() { // 通过通话记录信息匹配
  40. return false;
  41. }

  42. protected boolean detectSms() {// 通过短信记录信息匹配
  43. return false;
  44. }

  45. protected Context getContext() { // 返回句柄
  46. return SimManager.getInstance().getContext();
  47. }

  48. protected int getSimSlotNum() { // 返回插槽个数(默认2)
  49. return 2;
  50. }

  51. public void init() { // 初始化
  52. for (int i = 0; i < getSimSlotNum(); i++) {
  53. try {
  54. String imsi = getIMSI(i);
  55. boolean isUsing = isSimStateIsReady(i);
  56. if (imsi != null || isUsing) {
  57. if (imsi == null || hasSimSlotByIMSI(imsi))
  58. continue;

  59. SimSlot simSlot = new SimSlot();
  60. mSimSlots.add(simSlot);
  61. simSlot.setUsing(isUsing);
  62. simSlot.setIMSI(imsi);
  63. simSlot.setSimOperator(getSimOperator(i));
  64. }
  65. } catch (Exception e) {
  66. e.printStackTrace();
  67. }
  68. }
  69. }

  70. public boolean hasSimPhone() {// 是否有sd卡在使用
  71. if (mSimSlots.isEmpty())
  72. return false;

  73. for (SimSlot simslot : mSimSlots) {
  74. if (simslot.isUsing())
  75. return true;
  76. }

  77. return false;
  78. }

  79. public boolean isDualSimPhone() {// 是否为双卡
  80. if (getSimSlots().isEmpty() || getSimSlots().size() < 2)
  81. return false;

  82. for (SimSlot simSlot : getSimSlots()) {
  83. if (!simSlot.isUsing())
  84. return false;
  85. }

  86. return true;
  87. }

  88. public ArrayList<SimSlot> getSimSlots() { // 返回已确认的卡
  89. return mSimSlots;
  90. }

  91. protected boolean delSimSlotByIMSI(String imsi) { // 删除相同的卡的信息
  92. for (SimSlot simSlot : getSimSlots()) {
  93. if (simSlot.getIMSI() != null && simSlot.getIMSI().equals(imsi)) {
  94. getSimSlots().remove(simSlot);
  95. }
  96. }

  97. return false;
  98. }

  99. protected boolean hasSimSlotByIMSI(String imsi) {
  100. for (SimSlot simSlot : getSimSlots()) {
  101. if (simSlot.getIMSI() != null && simSlot.getIMSI().equals(imsi)) {
  102. return true;
  103. }
  104. }

  105. return false;
  106. }
  107. }
复制代码

现在列举一款实现MTK方案:
  1. public class MTKDualSim extends AbsSim {// 采用MTK方案的类(根据厂家SDK实现不同的接口)
  2. private Object mMSimTelephonyManager = null;
  3. private Object mTelephonyMSim = null;

  4. public MTKDualSim() {
  5. mCallLogExtraField = "simid";

  6. String str1 = SimManager.getModel();
  7. String str2 = SimManager.getManufaturer();
  8. if ((str1 != null) && (str2 != null)) {
  9. String str3 = str1.toLowerCase();
  10. String str4 = str2.toLowerCase();
  11. if ((str4.indexOf("huawei") > -1) && (str3.indexOf("h30-t00") > -1))
  12. mCallLogExtraField = "subscription";
  13. if ((str4.indexOf("hisense") > -1)
  14. && (str3.indexOf("hs-u970") > -1)) {
  15. mCallLogExtraField = "subtype";
  16. }
  17. }
  18. }

  19. @Override
  20. public boolean directCall(String paramString, int paramInt) {
  21. if (SimManager.isSDKVersionMore4_1()) {
  22. Intent localIntent1 = new Intent("android.intent.action.CALL",
  23. Uri.fromParts("tel", paramString, null));
  24. localIntent1.putExtra("simId", paramInt);
  25. localIntent1.putExtra("com.android.phone.extra.slot", paramInt);
  26. localIntent1.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
  27. try {
  28. getContext().startActivity(localIntent1);
  29. return true;
  30. } catch (Throwable localThrowable1) {
  31. localThrowable1.printStackTrace();
  32. }
  33. } else if (SimManager.isSDKVersionMore4_0()) {
  34. Intent localIntent2 = new Intent(
  35. "com.android.phone.OutgoingCallReceiver");
  36. localIntent2.putExtra("com.android.phone.extra.slot", paramInt);
  37. localIntent2.putExtra("simId", paramInt);
  38. localIntent2.putExtra("com.android.phone.force.slot", true);
  39. localIntent2.setClassName("com.android.phone",
  40. "com.android.phone.OutgoingCallReceiver");
  41. localIntent2.setData(Uri.fromParts("tel", paramString, null));
  42. try {
  43. getContext().sendBroadcast(localIntent2);
  44. return true;
  45. } catch (Throwable localThrowable2) {
  46. localThrowable2.printStackTrace();
  47. }
  48. }

  49. try {
  50. Intent localIntent3 = new Intent();
  51. localIntent3.setAction("out_going_call_to_phone_app");
  52. localIntent3.putExtra("number", paramString);
  53. localIntent3.putExtra("simId", paramInt);
  54. localIntent3.putExtra("com.android.phone.extra.slot", paramInt);
  55. localIntent3.putExtra("launch_from_dialer", 1);
  56. localIntent3.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
  57. getContext().sendBroadcast(localIntent3);
  58. return true;
  59. } catch (Throwable localThrowable3) {
  60. localThrowable3.printStackTrace();
  61. }
  62. return false;
  63. }

  64. @Override
  65. public AbsSim detect() {
  66. String imsi = getIMSI(0);
  67. if (imsi != null && !TextUtils.isEmpty(imsi)) {
  68. return this;
  69. }

  70. return super.detect();
  71. }

  72. @Override
  73. public String getSimPhoneNumber(int paramInt) {
  74. Object[] arrayOfObject2 = new Object[1];
  75. try {
  76. Object localObject = getMSimTelephonyManager(paramInt);
  77. arrayOfObject2[0] = Integer.valueOf(paramInt);
  78. String result = (String) ReflecterHelper.invokeMethod(localObject,
  79. "getLine1NumberGemini", arrayOfObject2);
  80. arrayOfObject2 = null;
  81. return result;
  82. } catch (Throwable localThrowable) {
  83. localThrowable.printStackTrace();
  84. }
  85. return "";
  86. }

  87. @Override
  88. public int getDataState(int paramInt) {
  89. Object[] arrayOfObject2 = new Object[1];
  90. try {
  91. Object localObject = getMSimTelephonyManager(paramInt);
  92. arrayOfObject2[0] = Integer.valueOf(paramInt);
  93. int result = ((Integer) ReflecterHelper.invokeMethod(localObject,
  94. "getDataStateGemini", arrayOfObject2)).intValue();
  95. arrayOfObject2 = null;
  96. return result;
  97. } catch (Throwable localThrowable) {
  98. localThrowable.printStackTrace();
  99. }
  100. arrayOfObject2 = null;
  101. return -1;
  102. }

  103. @Override
  104. public String getIMSI(int paramInt) {
  105. return getIMSI(paramInt, null);
  106. }

  107. @Override
  108. public String getIMSI(int paramInt, Context paramContext) {
  109. Object localObject = getMSimTelephonyManager(paramInt);
  110. Object[] arrayOfObject2 = new Object[1];
  111. try {
  112. arrayOfObject2[0] = Integer.valueOf(paramInt);
  113. String result = (String) ReflecterHelper.invokeMethod(localObject,
  114. "getSubscriberIdGemini", arrayOfObject2);
  115. arrayOfObject2 = null;
  116. return result;
  117. } catch (Throwable localThrowable) {
  118. localThrowable.printStackTrace();
  119. }
  120. arrayOfObject2 = null;
  121. return null;
  122. }

  123. @Override
  124. public int getPhoneState(int paramInt) {
  125. Object localObject = getMSimTelephonyManager(paramInt);
  126. Object[] arrayOfObject2 = new Object[1];
  127. try {
  128. arrayOfObject2[0] = Integer.valueOf(paramInt);
  129. int result = ((Integer) ReflecterHelper.invokeMethod(localObject,
  130. "getCallStateGemini", arrayOfObject2)).intValue();
  131. arrayOfObject2 = null;
  132. return result;
  133. } catch (Throwable localThrowable) {
  134. localThrowable.printStackTrace();
  135. }
  136. arrayOfObject2 = null;
  137. return 0;
  138. }

  139. @Override
  140. public boolean isServiceAvaliable(int paramInt) {
  141. Object localObject = getITelephonyMSim(paramInt);
  142. if (localObject == null)
  143. return false;
  144. Object[] arrayOfObject2 = new Object[1];
  145. try {
  146. arrayOfObject2[0] = Integer.valueOf(paramInt);
  147. boolean result = ((Boolean) ReflecterHelper.invokeMethod(
  148. localObject, "isRadioOnGemini", arrayOfObject2))
  149. .booleanValue();
  150. arrayOfObject2 = null;
  151. return result;
  152. } catch (Throwable localThrowable) {
  153. localThrowable.printStackTrace();
  154. }
  155. arrayOfObject2 = null;
  156. return false;
  157. }

  158. @Override
  159. public boolean isSimStateIsReady(int paramInt) {
  160. Object localObject = getMSimTelephonyManager(paramInt);
  161. if (localObject != null) {
  162. Object[] arrayOfObject2 = new Object[1];
  163. try {
  164. arrayOfObject2[0] = Integer.valueOf(paramInt);
  165. int result = ((Integer) ReflecterHelper.invokeMethod(
  166. localObject, "getSimStateGemini", arrayOfObject2))
  167. .intValue();
  168. arrayOfObject2 = null;
  169. return result == 5;
  170. } catch (Throwable localThrowable) {
  171. localThrowable.printStackTrace();
  172. }
  173. arrayOfObject2 = null;
  174. }

  175. return false;
  176. }

  177. @Override
  178. public int getSimOperator(int paramInt) { // 注意
  179. Object localObject = getMSimTelephonyManager(paramInt);
  180. Object[] arrayOfObject2 = new Object[1];
  181. try {
  182. arrayOfObject2[0] = Integer.valueOf(paramInt);
  183. String result = ((String) ReflecterHelper.invokeMethod(localObject,
  184. "getSimOperatorGemini", arrayOfObject2));
  185. arrayOfObject2 = null;
  186. return Integer.valueOf(result);
  187. } catch (Throwable localThrowable) {
  188. localThrowable.printStackTrace();
  189. }
  190. arrayOfObject2 = null;
  191. return 0;
  192. }

  193. @Override
  194. protected Object getITelephonyMSim(int paramInt) {
  195. if (mTelephonyMSim == null)
  196. mTelephonyMSim = ITelephony.Stub.asInterface(ServiceManager
  197. .getService("phone"));
  198. return mTelephonyMSim;
  199. }

  200. @Override
  201. protected Object getMSimTelephonyManager(int paramInt) {
  202. if (mMSimTelephonyManager != null)
  203. return mMSimTelephonyManager;
  204. Object[] arrayOfObject3 = new Object[1];
  205. try {
  206. mMSimTelephonyManager = SimManager.getInstance()
  207. .getTelephonyManagerByPhone();
  208. try {
  209. Object localObject = mMSimTelephonyManager;
  210. arrayOfObject3[0] = Integer.valueOf(0);
  211. ReflecterHelper.invokeMethod(localObject,
  212. "getSubscriberIdGemini", arrayOfObject3);
  213. arrayOfObject3 = null;
  214. return mMSimTelephonyManager;
  215. } catch (Throwable localThrowable2) {
  216. localThrowable2.printStackTrace();
  217. }
  218. } catch (Throwable localThrowable1) {
  219. localThrowable1.printStackTrace();
  220. }
  221. arrayOfObject3 = null;
  222. return null;
  223. }
  224. }
复制代码

再列举一款单卡的方案:
  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. @Override
  5. public boolean hasSimPhone() {
  6. return false;
  7. }

  8. @Override
  9. public AbsSim detect() {// 根据某些字段判是否为双卡(有可能误判)
  10. if (mIsDualSimPhone)
  11. return null;

  12. Cursor localSafeCursor = null;
  13. String[] arrayOfString;
  14. try {
  15. localSafeCursor = SimManager
  16. .getInstance()
  17. .getContext()
  18. .getContentResolver()
  19. .query(CallLog.Calls.CONTENT_URI, null, null, null,
  20. "_id limit 0,1");

  21. if (localSafeCursor != null && localSafeCursor.moveToFirst()) {
  22. arrayOfString = localSafeCursor.getColumnNames();

  23. for (int i = 0; i < arrayOfString.length; i++) {
  24. String str = arrayOfString[i];
  25. if (mCallLogExtraFields.containsKey(str.toLowerCase())) {
  26. mIsDualSimPhone = true;
  27. mCallLogExtraField = str;
  28. }
  29. }

  30. }
  31. } catch (Exception e) {
  32. e.printStackTrace();
  33. }

  34. return this;
  35. }

  36. @Override
  37. public boolean isDualSimPhone() {
  38. return mIsDualSimPhone;
  39. }

  40. @Override
  41. public int getSimSlotNum() {
  42. return 1;
  43. }

  44. @Override
  45. public String getSimPhoneNumber(int paramInt) {
  46. return ((TelephonyManager) getMSimTelephonyManager(0)).getLine1Number();
  47. }

  48. @Override
  49. public int getDataState(int paramInt) {
  50. return ((TelephonyManager) getMSimTelephonyManager(0)).getDataState();
  51. }

  52. @Override
  53. public String getIMSI(int paramInt) {
  54. return ((TelephonyManager) getMSimTelephonyManager(0)).getDeviceId();
  55. }

  56. @Override
  57. public String getIMSI(int paramInt, Context paramContext) {
  58. return ((TelephonyManager) getMSimTelephonyManager(0))
  59. .getSubscriberId();
  60. }

  61. @Override
  62. public int getPhoneState(int paramInt) {
  63. return ((TelephonyManager) getMSimTelephonyManager(0)).getCallState();
  64. }

  65. @Override
  66. public boolean isServiceAvaliable(int paramInt) {
  67. ITelephony localITelephony = (ITelephony) getITelephonyMSim(0);
  68. if (localITelephony == null)
  69. return false;
  70. try {
  71. boolean bool = localITelephony.isRadioOn();
  72. return bool;
  73. } catch (Throwable localThrowable) {
  74. localThrowable.printStackTrace();
  75. }
  76. return false;
  77. }

  78. @Override
  79. public boolean isSimStateIsReady(int paramInt) {
  80. return ((TelephonyManager) getMSimTelephonyManager(0)).getSimState() == 5;
  81. }

  82. @Override
  83. public int getSimOperator(int paramInt) {
  84. TelephonyManager localTelephonyManager = (TelephonyManager) getMSimTelephonyManager(paramInt);
  85. return Integer.parseInt(localTelephonyManager.getSimOperator());
  86. }

  87. @Override
  88. protected Object getITelephonyMSim(int paramInt) {
  89. return SimManager.getInstance().getITelephonyByPhone();
  90. }

  91. @Override
  92. protected Object getMSimTelephonyManager(int paramInt) {
  93. return SimManager.getInstance().getTelephonyManagerByPhone();
  94. }
  95. }
复制代码

总结

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

8 个回复

倒序浏览
虽然看不懂 但是感觉高大上
回复 使用道具 举报
学了这么久,终于看到终极目标的一角!  up!
回复 使用道具 举报
挺厉害的样子
回复 使用道具 举报

顶一个。。
回复 使用道具 举报
看不懂看不懂啊啊啊啊啊啊
回复 使用道具 举报
学习了, 楼主好人
回复 使用道具 举报
拜读了,加了楼主QQ,想进一步联系。
回复 使用道具 举报
baby14 金牌黑马 2019-6-11 06:56:59
9#
多谢分享
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马