安卓4.4原生并不支持双卡,展讯4.4添加了双卡功能。
下面整理一下应用层的开机双卡选择流程:
Telephony开始
packages/services/Telephony/src/com/sprd/phone/BootCompletedReceiver.java
接收modem广播,判断是否是双卡
<receiver android:name="com.sprd.phone.BootCompletedReceiver" > <intent-filter> <action android:name="com.android.modemassert.MODEM_STAT_CHANGE" /> </intent-filter> </receiver>
if (!TelephonyManager.isMultiSim()) { //isMultiSim()也是自定义的方法,结尾处有详述 // SPRD: modify for bug369560 if (action.equals(TelephonyIntents.ACTION_SIM_STATE_CHANGED)) { //SIM卡状态 String state = intent.getStringExtra(IccCardConstants.INTENT_KEY_ICC_STATE); //phoneId,0或1 int phoneId = intent.getIntExtra(IccCardConstants.INTENT_KEY_PHONE_ID, 0); if (IccCardConstants.INTENT_VALUE_ICC_LOCKED.equals(state) || IccCardConstants.INTENT_VALUE_ICC_ABSENT.equals(state) || IccCardConstants.INTENT_VALUE_ICC_READY.equals(state)) { mSimStateChangedFlag |= (1 << phoneId); Message simMsg = new Message(); simMsg.what = EVENT_SIM_STATE_CHANGED; simMsg.arg1 = mSimStateChangedFlag; mHandler.sendMessage(simMsg); } } return; }
由mHandler处理
private static final String SHOW_SELECT_PRIMARY_CARD_DIALOG = "android.intent.action.SHOW_SELECT_PRIMARY_CARD_DIALOG"; Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { int phoneCount = TelephonyManager.getPhoneCount(); switch(msg.what){ case EVENT_SELECTCARD: boolean isSimPresent = false; for(int i =0;i<phoneCount;i++){ if(PhoneFactory.getSimState(i) != State.ABSENT){ isSimPresent = true; break; } } if (isSimPresent) { System.putInt(mContext.getContentResolver(), System.Standby_Select_Card_Show, 1); Intent it = new Intent(mContext, StandbyDialogActivity.class); //提示SIM卡准备好 it.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); mContext.startActivity(it); } break; case EVENT_CHARCHANGED: //提醒主卡改变 if (isAllSimChecked() && !mHasPromptCardChanged){ if (checkCard(mContext)) { mHasPromptCardChanged = true; Intent it = new Intent(mContext, PromptCardChanged.class); it.putExtra(PromptCardChanged.SIM_CHANGE_STATUS, sim_change_status); it.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); mContext.startActivity(it); } } break; case EVENT_SIM_STATE_CHANGED: //SIM卡状态改变 boolean isSimsChanged = false; for (int i = 0; i < mPhoneNumber; i++) { String lastIccId = preferences.getString(SIM_ICC_ID + i, null); String newIccId = getIccId(i); if (newIccId == null || !newIccId.equals(lastIccId)) { isSimsChanged = true; //其实也是判断iccid } } if (isSimsChanged) { mRadioTaskManager.savePreferredNetworkType(TelephonyManager.NT_UNKNOWN); //这里开始双卡选择 setMultiModeSlotAccordingToPolicy(); } else { int primaryCard = TelephonyManager.from(mContext).getPrimaryCard(); if (!SimManager.isValidPhoneId(primaryCard)) { setMultiModeSlotAccordingToPolicy(); //SIM卡状态没变化 ,但是主卡验证失败也会重新选择 } else { mRadioTaskManager.setDefaultDataPhoneIdNeedUpdate(false); mRadioTaskManager.manualSetPrimaryCard(primaryCard); } } } private void setMultiModeSlotAccordingToPolicy() { Settings.Secure.putInt( mContext.getContentResolver(),Settings.Secure.SERVICE_PRIMARY_CARD, -1); SimManager simManager = SimManager.get(mContext); if(simManager == null){ Log.d(TAG,"simManager = "+null); return; } final Sim[] sims = simManager.getSims(); if (mPolicy.isPrimaryCardNeedManualSet() && sims.length > 1) { prepareForMultiModeSlotChooseDialog(); //如果有两个卡进行双卡选择 } else { mRadioTaskManager.autoSetPrimaryCardAccordingToPolicy(); String operatorName = SystemProperties.get("ro.operator", ""); if ("reliance".equals(operatorName)) {//这应该是一种特定运营商,不太清楚 prepareForMultiModeSlotChooseDialog(); } } } //发送广播进行主卡选择,由Settings里面接收 private void prepareForMultiModeSlotChooseDialog() { Intent intent = new Intent(SHOW_SELECT_PRIMARY_CARD_DIALOG); intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND); mContext.sendBroadcast(intent); }
Settings
src/com/android/settings/sim/SimSelectNotification.java
<receiver android:name=".sim.SimSelectNotification"> <intent-filter> <action android:name="android.intent.action.SIM_STATE_CHANGED"></action> <action android:name="android.intent.action.SHOW_SELECT_PRIMARY_CARD_DIALOG"></action> </intent-filter> </receiver>
public void onReceive(Context context, Intent intent) { /* SPRD: [Bug512963] Add for selecting primary card after boot with SIM card changed. @{ */ if (PRIMARY_CARD_SELECTION_DIALOG.equals(intent.getAction())) { Log.d(TAG, "receive broadcast : SHOW_SELECT_PRIMARY_CARD_DIALOG"); //其实是打开SimDialogActivity Intent targetIntent = new Intent(context, SimDialogActivity.class); targetIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); targetIntent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK); //弹出双卡选择,设置参数 targetIntent.putExtra(SimDialogActivity.DIALOG_TYPE_KEY, SimDialogActivity.PRIMARY_PICK); targetIntent.putExtra(SimDialogActivity.PRIMARYCARD_PICK_CANCELABLE, true); context.startActivity(targetIntent); } /* @} */ }
src/com/android/settings/sim/SimDialogActivity.java
//在onCreate和onNewIntent方法中调用processIntent(); processIntent(); private void processIntent() { final Bundle extras = getIntent().getExtras(); if (extras == null) { Log.e(TAG, "invalid extras null"); finish(); return; } final int dialogType = extras.getInt(DIALOG_TYPE_KEY, INVALID_PICK); mIsPrimaryCardCancelable = extras.getBoolean(PRIMARYCARD_PICK_CANCELABLE); switch (dialogType) { case DATA_PICK: case CALLS_PICK: case SMS_PICK: case PRIMARY_PICK: //创建Dialog并显示 mDialogType = dialogType; mSimChooseDialog = createDialog(this, mDialogType); mSimChooseDialog.show(); break; case PREFERRED_PICK: displayPreferredDialog(extras.getInt(PREFERRED_SIM)); break; default: throw new IllegalArgumentException("Invalid dialog type " + dialogType + " sent."); } }
再看一下createDialog方法,逻辑就很简单了:
public Dialog createDialog(final Context context, final int id) { dismissSimChooseDialog(); final ArrayList<String> list = new ArrayList<String>(); final Sim[] subInfoList = mSimManager.getActiveSims(); final int selectableSubInfoLength = subInfoList == null ? 0 : subInfoList.length; final StatusBarManager statusBarManager = (StatusBarManager) getSystemService(Context.STATUS_BAR_SERVICE); final Sim[] subInfoListForCallAndSms = new Sim[selectableSubInfoLength + 1]; final DialogInterface.OnClickListener selectionListener = new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int value) { // SPRD: modify by add radioButton on set defult sub id setDefaltSubIdByDialogId(context, id, value, subInfoList); } }; Dialog.OnKeyListener keyListener = new Dialog.OnKeyListener() { @Override public boolean onKey(DialogInterface arg0, int keyCode, KeyEvent event) { /* SPRD: add option for selecting primary card @{ */ if (keyCode == KeyEvent.KEYCODE_BACK && !mIsPrimaryCardCancelable) { finish(); return true; } else if (keyCode == KeyEvent.KEYCODE_BACK && mIsPrimaryCardCancelable) { return true; } else { return false; } /* @} */ } }; if (id == CALLS_PICK || id == SMS_PICK) { list.add(getResources().getString(R.string.sim_calls_ask_first_prefs_title)); for (int i = 1; i < subInfoListForCallAndSms.length; i++) { subInfoListForCallAndSms[i] = subInfoList[i-1]; } } for (int i = 0; i < selectableSubInfoLength; ++i) { final Sim sir = subInfoList[i]; CharSequence displayName = sir.getName(); if (displayName == null) { displayName = ""; } list.add(displayName.toString()); } String[] arr = list.toArray(new String[0]); AlertDialog.Builder builder = new AlertDialog.Builder(context, AlertDialog.THEME_HOLO_LIGHT); ListAdapter adapter = new SelectAccountListAdapter( (id == CALLS_PICK || id == SMS_PICK)? subInfoListForCallAndSms: subInfoList, builder.getContext(), R.layout.select_account_list_item, arr, id); switch (id) { case DATA_PICK: builder.setTitle(R.string.select_sim_for_data); break; case CALLS_PICK: builder.setTitle(R.string.select_sim_for_calls); break; case SMS_PICK: builder.setTitle(R.string.sim_card_select_title); break; /* SPRD: add option of selecting primary card @{ */ case PRIMARY_PICK: /* SPRD: add for bug 543820 @{ */ View titleView = LayoutInflater.from(this).inflate( R.layout.select_primary_card_title, null); TextView textview = (TextView) titleView .findViewById(R.id.multi_mode_slot_introduce); if (TelephonyManager.isDeviceSupportLte()) { textview.setText(getString(R.string.select_primary_slot_description_4g)); } textview.setTextColor(Color.BLACK); builder.setCustomTitle(titleView); /* @} */ break; /* @} */ default: throw new IllegalArgumentException("Invalid dialog type " + id + " in SIM dialog."); } Dialog dialog = builder.setAdapter(adapter, selectionListener).create(); dialog.setOnKeyListener(keyListener); dialog.setOnCancelListener(new DialogInterface.OnCancelListener() { @Override public void onCancel(DialogInterface dialogInterface) { finish(); } }); /* SPRD: add option of selecting primary card @{ */ if (mIsPrimaryCardCancelable) { dialog.setOnDismissListener(new DialogInterface.OnDismissListener() { @Override public void onDismiss(DialogInterface dialog) { statusBarManager.disable(StatusBarManager.DISABLE_NONE); } }); dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG); dialog.setCanceledOnTouchOutside(false); statusBarManager.disable(StatusBarManager.DISABLE_EXPAND); } /* @} */ return dialog; }
TelephonyManager.isMultiSim()
frameworks/base/telephony/java/android/telephony/TelephonyManager.java
/** SPRD: check if is multiple sim */ public static boolean isMultiSim() { return SprdPhoneSupport.isMultiSim(); //调用了SprdSupport.java的方法 }
frameworks/base/telephony/java/android/telephony/SprdPhoneSupport.java
//其实是判断的SIM卡插入的个数 public static boolean isMultiSim() { return getPhoneCount() > 1; } public static final int DEFAULT_PHONE_COUNT = 1; //获取SIM卡个数 public static int getPhoneCount() { return SystemProperties.getInt("persist.msms.phone_count", DEFAULT_PHONE_COUNT); }
所以最终修改的是persist.msms.phone_count
的属性值,那么它是在哪里被修改的?看下面
frameworks/base/telephony/java/android/telephony/TelephonyManager.java
//检查系统属性 public static void checkSystemProperties(Context context){ if(isSystemPropertiesInvalid(context,PROP_PHONE_COUNT)){ //设置persist.msms.phone_count属性,属性值通过getSystemString获取 SystemProperties.set(PROP_PHONE_COUNT, getSystemString(context, PROP_PHONE_COUNT)); } ... } //判断属性的合法性 private static boolean isSystemPropertiesInvalid(Context context, String string) { Log.d(TAG, "isSystemPropertiesInvalid: string=" + string + ", getSystemString=" + getSystemString(context, string) + ", getSystemProperties=" + SystemProperties.get(string, "")); //属性不为空,且系统属性值与prop文件内的属性值不相等。 //因为默认persist.msms.phone_count=2,如果只插一张卡(getSytemString为1)就需要修改了 return (!TextUtils.isEmpty(getSystemString(context, string)) && (!getSystemString(context, string).equals(SystemProperties.get(string, "")))); } //获取系统属性值 private static String getSystemString(Context context, String string){ return Settings.System.getString(context.getContentResolver(), string); }