2 * Copyright (C) 2014 The Android Open Source Project
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 package com.android.settings.sim;
19 import android.app.Activity;
20 import android.app.AlertDialog;
21 import android.app.Dialog;
22 import android.app.ProgressDialog;
23 import android.content.BroadcastReceiver;
24 import android.content.ComponentName;
25 import android.content.Context;
26 import android.content.DialogInterface;
27 import android.content.Intent;
28 import android.content.IntentFilter;
29 import android.content.res.Resources;
30 import android.graphics.drawable.BitmapDrawable;
31 import android.os.AsyncTask;
32 import android.os.Bundle;
33 import android.os.Handler;
34 import android.os.Message;
35 import android.os.RemoteException;
36 import android.os.ServiceManager;
37 import android.os.SystemProperties;
38 import android.preference.Preference;
39 import android.preference.PreferenceScreen;
40 import android.preference.PreferenceCategory;
41 import android.provider.SearchIndexableResource;
42 import android.provider.Settings;
43 import android.telephony.PhoneStateListener;
44 import android.telephony.SmsManager;
45 import android.telephony.SubscriptionInfo;
46 import android.telephony.SubscriptionManager;
47 import android.telephony.TelephonyManager;
48 import android.telecom.PhoneAccountHandle;
49 import android.telecom.TelecomManager;
50 import android.text.TextUtils;
51 import android.util.AttributeSet;
52 import android.util.Log;
53 import android.view.LayoutInflater;
54 import android.view.View;
55 import android.view.ViewGroup;
56 import android.widget.CompoundButton;
57 import android.widget.CompoundButton.OnCheckedChangeListener;
59 import com.android.internal.logging.MetricsLogger;
60 import com.android.internal.telephony.PhoneConstants;
61 import com.android.settings.RestrictedSettingsFragment;
62 import com.android.settings.Utils;
63 import com.android.settings.search.BaseSearchIndexProvider;
64 import com.android.settings.search.Indexable;
65 import com.android.settings.R;
66 import com.android.internal.telephony.IExtTelephony;
67 import com.android.internal.telephony.TelephonyProperties;
69 import java.util.ArrayList;
70 import java.util.List;
72 public class SimSettings extends RestrictedSettingsFragment implements Indexable {
73 private static final String TAG = "SimSettings";
74 private static final boolean DBG = false;
76 // These are the list of possible values that
77 // IExtTelephony.getCurrentUiccCardProvisioningStatus() can return
78 private static final int PROVISIONED = 1;
79 private static final int NOT_PROVISIONED = 0;
80 private static final int INVALID_STATE = -1;
81 private static final int CARD_NOT_PRESENT = -2;
83 private static final String DISALLOW_CONFIG_SIM = "no_config_sim";
84 private static final String SIM_CARD_CATEGORY = "sim_cards";
85 private static final String KEY_CELLULAR_DATA = "sim_cellular_data";
86 private static final String KEY_CALLS = "sim_calls";
87 private static final String KEY_SMS = "sim_sms";
88 public static final String EXTRA_SLOT_ID = "slot_id";
89 private static final String SIM_ACTIVITIES_CATEGORY = "sim_activities";
90 private static final String MOBILE_NETWORK_CATEGORY = "mobile_network";
91 private static final String KEY_PRIMARY_SUB_SELECT = "select_primary_sub";
93 private IExtTelephony mExtTelephony = IExtTelephony.Stub.
94 asInterface(ServiceManager.getService("extphone"));
97 * By UX design we use only one Subscription Information(SubInfo) record per SIM slot.
98 * mAvalableSubInfos is the list of SubInfos we present to the user.
99 * mSubInfoList is the list of all SubInfos.
100 * mSelectableSubInfos is the list of SubInfos that a user can select for data, calls, and SMS.
102 private List<SubscriptionInfo> mAvailableSubInfos = null;
103 private List<SubscriptionInfo> mSubInfoList = null;
104 private List<SubscriptionInfo> mSelectableSubInfos = null;
105 private PreferenceCategory mSimCards = null;
106 private PreferenceCategory mMobileNetwork;
107 private SubscriptionManager mSubscriptionManager;
108 private int mNumSlots;
109 private Context mContext;
111 private static AlertDialog sAlertDialog = null;
112 private static ProgressDialog sProgressDialog = null;
113 private boolean needUpdate = false;
114 private int mPhoneCount = TelephonyManager.getDefault().getPhoneCount();
115 private int[] mUiccProvisionStatus = new int[mPhoneCount];
116 private Preference mPrimarySubSelect = null;
117 private int[] mCallState = new int[mPhoneCount];
118 private PhoneStateListener[] mPhoneStateListener = new PhoneStateListener[mPhoneCount];
120 private static final String ACTION_UICC_MANUAL_PROVISION_STATUS_CHANGED =
121 "org.codeaurora.intent.action.ACTION_UICC_MANUAL_PROVISION_STATUS_CHANGED";
122 private static final String EXTRA_NEW_PROVISION_STATE = "newProvisionState";
123 private static final String CONFIG_LTE_SUB_SELECT_MODE = "config_lte_sub_select_mode";
124 private static final String CONFIG_PRIMARY_SUB_SETABLE = "config_primary_sub_setable";
125 private static final String CONFIG_CURRENT_PRIMARY_SUB = "config_current_primary_sub";
126 // If this config set to '1' DDS option would be greyed out on UI.
127 // For more info pls refere framework code.
128 private static final String CONFIG_DISABLE_DDS_PREFERENCE = "config_disable_dds_preference";
130 public SimSettings() {
131 super(DISALLOW_CONFIG_SIM);
135 protected int getMetricsCategory() {
136 return MetricsLogger.SIM;
140 public void onCreate(final Bundle bundle) {
141 super.onCreate(bundle);
142 mContext = getActivity();
144 mSubscriptionManager = SubscriptionManager.from(getActivity());
145 final TelephonyManager tm =
146 (TelephonyManager) getActivity().getSystemService(Context.TELEPHONY_SERVICE);
147 addPreferencesFromResource(R.xml.sim_settings);
149 mPrimarySubSelect = (Preference) findPreference(KEY_PRIMARY_SUB_SELECT);
150 mNumSlots = tm.getSimCount();
151 mSimCards = (PreferenceCategory)findPreference(SIM_CARD_CATEGORY);
152 mMobileNetwork = (PreferenceCategory) findPreference(MOBILE_NETWORK_CATEGORY);
153 mAvailableSubInfos = new ArrayList<SubscriptionInfo>(mNumSlots);
154 mSelectableSubInfos = new ArrayList<SubscriptionInfo>();
155 SimSelectNotification.cancelNotification(getActivity());
157 IntentFilter intentFilter = new IntentFilter(ACTION_UICC_MANUAL_PROVISION_STATUS_CHANGED);
158 mContext.registerReceiver(mReceiver, intentFilter);
162 public void onDestroy() {
163 mContext.unregisterReceiver(mReceiver);
164 Log.d(TAG,"on onDestroy");
168 private final SubscriptionManager.OnSubscriptionsChangedListener mOnSubscriptionsChangeListener
169 = new SubscriptionManager.OnSubscriptionsChangedListener() {
171 public void onSubscriptionsChanged() {
172 if (DBG) log("onSubscriptionsChanged:");
173 Activity activity = getActivity();
174 if (activity != null && !activity.isFinishing()) {
175 updateSubscriptions();
180 private void updateSubscriptions() {
181 mSubInfoList = mSubscriptionManager.getActiveSubscriptionInfoList();
182 for (int i = 0; i < mNumSlots; ++i) {
183 Preference pref = mSimCards.findPreference("sim" + i);
184 if (pref instanceof SimPreference) {
185 mSimCards.removePreference(pref);
188 mMobileNetwork.removeAll();
189 mAvailableSubInfos.clear();
190 mSelectableSubInfos.clear();
192 for (int i = 0; i < mNumSlots; ++i) {
193 final SubscriptionInfo sir = mSubscriptionManager
194 .getActiveSubscriptionInfoForSimSlotIndex(i);
195 int subscriptionId = sir != null ?
196 sir.getSubscriptionId() :
197 SubscriptionManager.INVALID_SUBSCRIPTION_ID;
198 SimPreference simPreference = new SimEnablerPreference(mContext, sir, i);
199 simPreference.setOrder(i-mNumSlots);
200 mSimCards.addPreference(simPreference);
201 mAvailableSubInfos.add(sir);
202 if (sir != null && (isSubProvisioned(i))) {
203 mSelectableSubInfos.add(sir);
205 Intent mobileNetworkIntent = new Intent();
206 mobileNetworkIntent.setComponent(new ComponentName(
207 "com.android.phone", "com.android.phone.MobileNetworkSettings"));
208 SubscriptionManager.putPhoneIdAndSubIdExtra(mobileNetworkIntent, i, subscriptionId);
209 Preference mobileNetworkPref = new Preference(getActivity());
210 mobileNetworkPref.setTitle(
211 getString(R.string.sim_mobile_network_settings_title, (i + 1)));
212 mobileNetworkPref.setIntent(mobileNetworkIntent);
213 mobileNetworkPref.setEnabled(
214 subscriptionId != SubscriptionManager.INVALID_SUBSCRIPTION_ID);
215 mMobileNetwork.addPreference(mobileNetworkPref);
220 private void updateAllOptions() {
221 updateSimSlotValues();
222 updateActivitesCategory();
225 private void updateSimSlotValues() {
226 final int prefSize = mSimCards.getPreferenceCount();
227 for (int i = 0; i < prefSize; ++i) {
228 Preference pref = mSimCards.getPreference(i);
229 if (pref instanceof SimPreference) {
230 ((SimPreference)pref).update();
235 private void updateActivitesCategory() {
236 updateCellularDataValues();
241 private void updateSmsValues() {
242 final Preference simPref = findPreference(KEY_SMS);
243 simPref.setTitle(R.string.sms_messages_title);
244 boolean isSMSPrompt = false;
245 SubscriptionInfo sir = mSubscriptionManager.getActiveSubscriptionInfo(
246 mSubscriptionManager.getDefaultSmsSubId());
248 isSMSPrompt = mExtTelephony.isSMSPromptEnabled();
249 } catch (RemoteException ex) {
250 loge("RemoteException @isSMSPromptEnabled" + ex);
251 } catch (NullPointerException ex) {
252 loge("NullPointerException @isSMSPromptEnabled" + ex);
254 // External telephony interfaces may not exist, fall back to our impl
255 if (mExtTelephony == null) {
256 isSMSPrompt = SmsManager.getDefault().isSMSPromptEnabled();
258 log("[updateSmsValues] isSMSPrompt: " + isSMSPrompt);
259 if (isSMSPrompt || sir == null) {
260 simPref.setSummary(mContext.getResources().getString(
261 R.string.sim_calls_ask_first_prefs_title));
263 simPref.setSummary(sir.getDisplayName());
265 simPref.setEnabled(mSelectableSubInfos.size() > 1);
268 private void updateCellularDataValues() {
269 final Preference simPref = findPreference(KEY_CELLULAR_DATA);
270 final SubscriptionInfo sir = mSubscriptionManager.getDefaultDataSubscriptionInfo();
271 simPref.setTitle(R.string.cellular_data_title);
272 if (DBG) log("[updateCellularDataValues] mSubInfoList=" + mSubInfoList);
275 simPref.setSummary(sir.getDisplayName());
276 } else if (sir == null) {
277 simPref.setSummary(R.string.sim_selection_required_pref);
280 boolean callStateIdle = isCallStateIdle();
281 final boolean ecbMode = SystemProperties.getBoolean(
282 TelephonyProperties.PROPERTY_INECM_MODE, false);
283 // Enable data preference in msim mode and call state idle
284 simPref.setEnabled((mSelectableSubInfos.size() > 1) && !disableDds()
285 && callStateIdle && !ecbMode);
288 private void updateCallValues() {
289 final Preference simPref = findPreference(KEY_CALLS);
290 final TelecomManager telecomManager = TelecomManager.from(mContext);
291 final PhoneAccountHandle phoneAccount =
292 telecomManager.getUserSelectedOutgoingPhoneAccount();
293 final List<PhoneAccountHandle> allPhoneAccounts =
294 telecomManager.getCallCapablePhoneAccounts();
296 simPref.setTitle(R.string.calls_title);
297 simPref.setSummary(phoneAccount == null
298 ? mContext.getResources().getString(R.string.sim_calls_ask_first_prefs_title)
299 : (String)telecomManager.getPhoneAccount(phoneAccount).getLabel());
300 simPref.setEnabled(allPhoneAccounts.size() > 1);
304 public void onResume() {
306 mSubscriptionManager.addOnSubscriptionsChangedListener(mOnSubscriptionsChangeListener);
308 updateSubscriptions();
313 public void onPause() {
315 mSubscriptionManager.removeOnSubscriptionsChangedListener(mOnSubscriptionsChangeListener);
316 unRegisterPhoneStateListener();
318 for (int i = 0; i < mSimCards.getPreferenceCount(); ++i) {
319 Preference pref = mSimCards.getPreference(i);
320 if (pref instanceof SimEnablerPreference) {
321 // Calling cleanUp() here to dismiss/cleanup any pending dialog exists.
322 ((SimEnablerPreference)pref).cleanUpPendingDialogs();
328 public boolean onPreferenceTreeClick(final PreferenceScreen preferenceScreen,
329 final Preference preference) {
330 final Context context = mContext;
331 Intent intent = new Intent(context, SimDialogActivity.class);
332 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
334 if (preference instanceof SimPreference) {
335 Intent newIntent = new Intent(context, SimPreferenceDialog.class);
336 newIntent.putExtra(EXTRA_SLOT_ID, ((SimPreference)preference).getSlotId());
337 startActivity(newIntent);
339 } else if (findPreference(KEY_CELLULAR_DATA) == preference) {
340 intent.putExtra(SimDialogActivity.DIALOG_TYPE_KEY, SimDialogActivity.DATA_PICK);
341 context.startActivity(intent);
343 } else if (findPreference(KEY_CALLS) == preference) {
344 intent.putExtra(SimDialogActivity.DIALOG_TYPE_KEY, SimDialogActivity.CALLS_PICK);
345 context.startActivity(intent);
347 } else if (findPreference(KEY_SMS) == preference) {
348 intent.putExtra(SimDialogActivity.DIALOG_TYPE_KEY, SimDialogActivity.SMS_PICK);
349 context.startActivity(intent);
355 private void loge(String msg) {
356 if (DBG) Log.e(TAG + "message", msg);
359 private void simEnablerUpdate() {
367 private class SimPreference extends Preference {
368 SubscriptionInfo mSubInfoRecord;
371 public SimPreference(Context context, SubscriptionInfo subInfoRecord, int slotId) {
375 mSubInfoRecord = subInfoRecord;
377 setKey("sim" + mSlotId);
380 public SimPreference (Context context, AttributeSet attrs, int defStyle) {
381 super(context, attrs, defStyle);
384 public void update() {
385 final Resources res = mContext.getResources();
387 setTitle(String.format(mContext.getResources()
388 .getString(R.string.sim_editor_title), (mSlotId + 1)));
389 if (mSubInfoRecord != null) {
390 if (TextUtils.isEmpty(getPhoneNumber(mSubInfoRecord))) {
391 setSummary(mSubInfoRecord.getDisplayName());
393 setSummary(mSubInfoRecord.getDisplayName() + " - " +
394 getPhoneNumber(mSubInfoRecord));
397 setIcon(new BitmapDrawable(res, (mSubInfoRecord.createIconBitmap(mContext))));
399 setSummary(R.string.sim_slot_empty);
405 private int getSlotId() {
410 protected void onAttachedToActivity() {
411 super.onAttachedToActivity();
419 // This is to show SIM Enable options on/off on UI for user selection.
420 // User can activate/de-activate through SIM on/off options.
421 private class SimEnablerPreference extends SimPreference implements OnCheckedChangeListener {
423 private String TAG = "SimEnablerPreference";
424 private static final boolean DBG = true;
426 private static final int EVT_UPDATE = 1;
427 private static final int EVT_SHOW_RESULT_DLG = 2;
428 private static final int EVT_SHOW_PROGRESS_DLG = 3;
429 private static final int EVT_PROGRESS_DLG_TIME_OUT = 4;
431 private static final int CONFIRM_ALERT_DLG_ID = 1;
432 private static final int ERROR_ALERT_DLG_ID = 2;
433 private static final int RESULT_ALERT_DLG_ID = 3;
435 private static final int REQUEST_SUCCESS = 0;
436 private static final int GENERIC_FAILURE = -1;
437 private static final int INVALID_INPUT = -2;
438 private static final int REQUEST_IN_PROGRESS = -3;
442 private static final String DISPLAY_NUMBERS_TYPE = "display_numbers_type";
444 private SubscriptionInfo mSir;
445 private boolean mCurrentUiccProvisionState;
446 private boolean mIsChecked;
448 private boolean mCmdInProgress = false;
449 private int mSwitchVisibility = View.VISIBLE;
450 private CompoundButton mSwitch;
451 //Delay for progress dialog to dismiss
452 private static final int PROGRESS_DLG_TIME_OUT = 30000;
453 private static final int MSG_DELAY_TIME = 2000;
455 private IExtTelephony mExtTelephony;
458 public SimEnablerPreference(Context context, SubscriptionInfo sir, int slotId) {
459 super(context, (AttributeSet)null,
460 com.android.internal.R.attr.checkBoxPreferenceStyle);
461 logd("Contructor..Enter");
465 mSubInfoRecord = sir;
466 if (mContext.getResources().getBoolean(R.bool.config_custom_multi_sim_checkbox)) {
467 setWidgetLayoutResource(R.layout.custom_sim_checkbox);
469 setWidgetLayoutResource(R.layout.custom_sim_switch);
472 mExtTelephony = IExtTelephony.Stub.asInterface(ServiceManager.getService("extphone"));
474 setSwitchVisibility(View.VISIBLE);
475 setKey("sim" + mSlotId);
479 private void sendMessage(int event, Handler handler, int delay) {
480 Message message = handler.obtainMessage(event);
481 handler.sendMessageDelayed(message, delay);
484 private void sendMessage(int event, Handler handler, int delay, int arg1, int arg2) {
485 Message message = handler.obtainMessage(event, arg1, arg2);
486 handler.sendMessageDelayed(message, delay);
489 private boolean hasCard() {
490 return TelephonyManager.getDefault().hasIccCard(mSlotId);
493 private boolean isAirplaneModeOn() {
494 return (Settings.Global.getInt(mContext.getContentResolver(),
495 Settings.Global.AIRPLANE_MODE_ON, 0) != 0);
498 private int getProvisionStatus(int slotId) {
499 return mUiccProvisionStatus[slotId];
503 protected void onBindView(View view) {
504 super.onBindView(view);
505 logd("onBindView....");
506 mSwitch = (CompoundButton) view.findViewById(R.id.sub_switch_widget);
507 mSwitch.setOnCheckedChangeListener(this);
509 // now use other config screen to active/deactive sim card\
510 mSwitch.setVisibility(mSwitchVisibility);
512 // Disable manual provisioning option to user when
513 // device is in Airplane mode. Hide it if the extphone framework
514 // is not present, as the operation relies on said framework.
515 if (mExtTelephony == null) {
516 mSwitch.setVisibility(View.GONE);
518 mSwitch.setVisibility(View.VISIBLE);
519 mSwitch.setEnabled(!isAirplaneModeOn() && isCurrentSubValid());
524 public void update() {
525 final Resources res = mContext.getResources();
526 logd("update()" + mSir);
528 //get current provision state of the SIM.
529 mUiccProvisionStatus[mSlotId] =
530 mExtTelephony.getCurrentUiccCardProvisioningStatus(mSlotId);
531 } catch (RemoteException ex) {
532 mUiccProvisionStatus[mSlotId] = INVALID_STATE;
533 loge("Failed to get pref, slotId: "+ mSlotId +" Exception: " + ex);
534 } catch (NullPointerException ex) {
535 mUiccProvisionStatus[mSlotId] = INVALID_STATE;
536 loge("Failed to get pref, slotId: "+ mSlotId +" Exception: " + ex);
539 if (mUiccProvisionStatus[mSlotId] == INVALID_STATE) {
540 mUiccProvisionStatus[mSlotId] = PROVISIONED;
543 boolean isSubValid = isCurrentSubValid();
544 setEnabled(isSubValid);
546 logd("update: isSubValid " + isSubValid + " provision status["
547 + mSlotId + "] = " + mUiccProvisionStatus[mSlotId]);
548 setTitle(res.getString(R.string.sim_card_number_title, mSlotId + 1));
551 setIcon(new BitmapDrawable(res, (mSir.createIconBitmap(mContext))));
553 setSummary(res.getString(R.string.sim_slot_empty));
557 // This method returns true if SubScription record corresponds to this
558 // Preference screen has a valid SIM and slot index/SubId.
559 private boolean isCurrentSubValid() {
560 boolean isSubValid = false;
562 List<SubscriptionInfo> sirList =
563 mSubscriptionManager.getActiveSubscriptionInfoList();
564 if (sirList != null ) {
565 for (SubscriptionInfo sir : sirList) {
566 if (sir != null && mSlotId == sir.getSimSlotIndex()) {
572 SubscriptionManager.isValidSubscriptionId(mSir.getSubscriptionId()) &&
573 mSir.getSimSlotIndex() >= 0 &&
574 getProvisionStatus(mSir.getSimSlotIndex()) >= 0) {
582 public void setSwitchVisibility (int visibility) {
583 mSwitchVisibility = visibility;
586 // Based on the received SIM provision state this method
587 // sets the check box on Sim Preference UI and updates new
588 // state to mCurrentUiccProvisionState.
589 private void setChecked(boolean uiccProvisionState) {
590 logd("setChecked: uiccProvisionState " + uiccProvisionState + "sir:" + mSir);
591 if (mSwitch != null) {
592 mSwitch.setOnCheckedChangeListener(null);
593 // Do not update update checkstatus again in progress
594 if (!mCmdInProgress) {
595 mSwitch.setChecked(uiccProvisionState);
597 mSwitch.setOnCheckedChangeListener(this);
598 mCurrentUiccProvisionState = uiccProvisionState;
602 private void updateSummary() {
603 Resources res = mContext.getResources();
605 boolean isActivated = (getProvisionStatus(mSir.getSimSlotIndex()) == PROVISIONED);
606 logd("updateSummary: subId " + mSir.getSubscriptionId() + " isActivated = "
607 + isActivated + " slot id = " + mSlotId);
609 String displayName = mSir == null ? "SIM" : (String)mSir.getDisplayName();
611 summary = displayName;
612 if (!TextUtils.isEmpty(mSir.getNumber())) {
613 summary = displayName + " - " + mSir.getNumber();
616 summary = mContext.getString(R.string.sim_enabler_summary, displayName,
617 res.getString(hasCard() ? R.string.sim_disabled : R.string.sim_missing));
621 setChecked(isActivated);
626 * get number of Subs provisioned on the device
630 public int getNumOfSubsProvisioned() {
631 int activeSubInfoCount = 0;
632 List<SubscriptionInfo> subInfoLists =
633 mSubscriptionManager.getActiveSubscriptionInfoList();
634 if (subInfoLists != null) {
635 for (SubscriptionInfo subInfo : subInfoLists) {
636 if (getProvisionStatus(subInfo.getSimSlotIndex())
637 == PROVISIONED) activeSubInfoCount++;
640 return activeSubInfoCount;
643 public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
644 mIsChecked = isChecked;
645 logd("onClick: " + isChecked);
650 // This internal method called when user changes preference from UI
651 // 1. For activation/deactivation request from User, if device in APM mode
652 // OR if voice call active on any SIM it dispay error dialog and returns.
653 // 2. For deactivation request it returns error dialog if only one SUB in
655 // 3. In other cases it sends user request to framework.
656 synchronized private void handleUserRequest() {
657 if (isAirplaneModeOn()) {
658 // do nothing but warning
659 logd("APM is on, EXIT!");
660 showAlertDialog(ERROR_ALERT_DLG_ID, R.string.sim_enabler_airplane_on);
663 for (int i = 0; i < mPhoneCount; i++) {
664 int[] subId = SubscriptionManager.getSubId(i);
665 //when voice call in progress, subscription can't be activate/deactivate.
666 if (TelephonyManager.getDefault().getCallState(subId[0])
667 != TelephonyManager.CALL_STATE_IDLE) {
668 logd("Call state for phoneId: " + i + " is not idle, EXIT!");
669 showAlertDialog(ERROR_ALERT_DLG_ID, R.string.sim_enabler_in_call);
675 if (getNumOfSubsProvisioned() > 1) {
676 logd("More than one sub is active, Deactivation possible.");
677 showAlertDialog(CONFIRM_ALERT_DLG_ID, 0);
679 logd("Only one sub is active. Deactivation not possible.");
680 showAlertDialog(ERROR_ALERT_DLG_ID, R.string.sim_enabler_both_inactive);
684 logd("Activate the sub");
685 sendUiccProvisioningRequest();
689 private void sendUiccProvisioningRequest() {
690 if (!mSwitch.isEnabled()) {
693 new SimEnablerDisabler().execute();
696 private class SimEnablerDisabler extends AsyncTask<Void, Void, Integer> {
698 int newProvisionedState = NOT_PROVISIONED;
701 protected void onPreExecute() {
702 super.onPreExecute();
703 mCmdInProgress = true;
704 showProgressDialog();
709 protected Integer doInBackground(Void... params) {
711 newProvisionedState = NOT_PROVISIONED;
714 result = mExtTelephony.activateUiccCard(mSir.getSimSlotIndex());
715 newProvisionedState = PROVISIONED;
717 result = mExtTelephony.deactivateUiccCard(mSir.getSimSlotIndex());
719 } catch (RemoteException ex) {
720 loge("Activate sub failed " + result + " phoneId " + mSir.getSimSlotIndex());
721 } catch (NullPointerException ex) {
722 loge("Failed to activate sub Exception: " + ex);
728 protected void onPostExecute(Integer result) {
729 processSetUiccDone(result.intValue(), newProvisionedState);
733 private void processSetUiccDone(int result, int newProvisionedState) {
734 sendMessage(EVT_UPDATE, mHandler, MSG_DELAY_TIME);
735 sendMessage(EVT_SHOW_RESULT_DLG, mHandler, MSG_DELAY_TIME, result, newProvisionedState);
736 mCmdInProgress = false;
739 private void showAlertDialog(int dialogId, int msgId) {
741 String title = mSir == null ? "SUB" : mSir.getDisplayName().toString();
742 // Confirm only one AlertDialog instance to show.
743 dismissDialog(sAlertDialog);
744 dismissDialog(sProgressDialog);
745 AlertDialog.Builder builder = new AlertDialog.Builder(mContext)
749 case CONFIRM_ALERT_DLG_ID:
751 if (mContext.getResources().getBoolean(
752 R.bool.confirm_to_switch_data_service)) {
753 if (SubscriptionManager.getDefaultDataSubId() ==
754 mSir.getSubscriptionId()) {
755 message = mContext.getString(
756 R.string.sim_enabler_need_switch_data_service,
757 getProvisionedSlotId(mContext));
759 message = mContext.getString(R.string.sim_enabler_need_disable_sim);
761 builder.setTitle(R.string.sim_enabler_will_disable_sim_title);
763 message = mContext.getString(R.string.sim_enabler_need_disable_sim);
765 builder.setMessage(message);
766 builder.setPositiveButton(android.R.string.ok, mDialogClickListener);
767 builder.setNegativeButton(android.R.string.no, mDialogClickListener);
768 builder.setOnCancelListener(mDialogCanceListener);
771 case ERROR_ALERT_DLG_ID:
772 builder.setMessage(mContext.getString(msgId));
773 builder.setNeutralButton(android.R.string.ok, mDialogClickListener);
774 builder.setCancelable(false);
777 case RESULT_ALERT_DLG_ID:
778 String msg = mCurrentUiccProvisionState ?
779 mContext.getString(R.string.sub_activate_success) :
780 mContext.getString(R.string.sub_deactivate_success);
781 builder.setMessage(msg);
782 builder.setNeutralButton(android.R.string.ok, null);
788 sAlertDialog = builder.create();
789 sAlertDialog.setCanceledOnTouchOutside(false);
793 private int getProvisionedSlotId(Context context) {
794 int activeSlotId = -1;
795 List<SubscriptionInfo> subInfoLists =
796 mSubscriptionManager.getActiveSubscriptionInfoList();
797 if (subInfoLists != null) {
798 for (SubscriptionInfo subInfo : subInfoLists) {
799 if (getProvisionStatus(subInfo.getSimSlotIndex()) == PROVISIONED
800 && subInfo.getSubscriptionId() != mSir.getSubscriptionId())
801 activeSlotId = subInfo.getSimSlotIndex() + 1;
807 private void showProgressDialog() {
808 String title = mSir == null ? "SUB" : mSir.getDisplayName().toString();
810 String msg = mContext.getString(mIsChecked ? R.string.sim_enabler_enabling
811 : R.string.sim_enabler_disabling);
812 dismissDialog(sProgressDialog);
813 sProgressDialog = new ProgressDialog(mContext);
814 sProgressDialog.setIndeterminate(true);
815 sProgressDialog.setTitle(title);
816 sProgressDialog.setMessage(msg);
817 sProgressDialog.setCancelable(false);
818 sProgressDialog.setCanceledOnTouchOutside(false);
819 sProgressDialog.show();
821 sendMessage(EVT_PROGRESS_DLG_TIME_OUT, mHandler, PROGRESS_DLG_TIME_OUT);
824 private void dismissDialog(Dialog dialog) {
825 if((dialog != null) && (dialog.isShowing())) {
831 public void cleanUpPendingDialogs() {
832 dismissDialog(sProgressDialog);
833 dismissDialog(sAlertDialog);
836 private DialogInterface.OnClickListener mDialogClickListener = new DialogInterface
838 public void onClick(DialogInterface dialog, int which) {
839 if (which == DialogInterface.BUTTON_POSITIVE) {
840 dismissDialog(sAlertDialog);
841 sendUiccProvisioningRequest();
842 } else if (which == DialogInterface.BUTTON_NEGATIVE) {
844 } else if (which == DialogInterface.BUTTON_NEUTRAL) {
850 private DialogInterface.OnCancelListener mDialogCanceListener = new DialogInterface
851 .OnCancelListener() {
852 public void onCancel(DialogInterface dialog) {
858 private Handler mHandler = new Handler() {
860 public void handleMessage(Message msg) {
866 case EVT_SHOW_RESULT_DLG:
867 int result = msg.arg1;
868 int newProvisionedState = msg.arg2;
869 logd("EVT_SHOW_RESULT_DLG result: " + result +
870 " new provisioned state " + newProvisionedState);
872 if (result != REQUEST_SUCCESS) {
873 int msgId = (newProvisionedState == PROVISIONED) ?
874 R.string.sub_activate_failed :
875 R.string.sub_deactivate_failed;
876 showAlertDialog(ERROR_ALERT_DLG_ID, msgId);
878 showAlertDialog(RESULT_ALERT_DLG_ID, 0);
880 mHandler.removeMessages(EVT_PROGRESS_DLG_TIME_OUT);
883 case EVT_SHOW_PROGRESS_DLG:
884 logd("EVT_SHOW_PROGRESS_DLG");
885 showProgressDialog();
888 case EVT_PROGRESS_DLG_TIME_OUT:
889 logd("EVT_PROGRESS_DLG_TIME_OUT");
890 dismissDialog(sProgressDialog);
891 // Must update UI when time out
901 private void logd(String msg) {
902 if (DBG) Log.d(TAG + "(" + mSlotId + ")", msg);
905 private void loge(String msg) {
906 Log.e(TAG + "(" + mSlotId + ")", msg);
910 // Returns the line1Number. Line1number should always be read from TelephonyManager since it can
911 // be overridden for display purposes.
912 private String getPhoneNumber(SubscriptionInfo info) {
913 final TelephonyManager tm =
914 (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
915 return tm.getLine1NumberForSubscriber(info.getSubscriptionId());
918 private void log(String s) {
925 public static final SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
926 new BaseSearchIndexProvider() {
928 public List<SearchIndexableResource> getXmlResourcesToIndex(Context context,
930 ArrayList<SearchIndexableResource> result =
931 new ArrayList<SearchIndexableResource>();
933 if (Utils.showSimCardTile(context)) {
934 SearchIndexableResource sir = new SearchIndexableResource(context);
935 sir.xmlResId = R.xml.sim_settings;
943 // Internal utility, returns true if Uicc card
944 // corresponds to given slotId is provisioned.
945 private boolean isSubProvisioned(int slotId) {
946 boolean retVal = false;
948 if (mUiccProvisionStatus[slotId] == PROVISIONED) retVal = true;
952 private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
954 public void onReceive(Context context, Intent intent) {
955 String action = intent.getAction();
956 Log.d(TAG, "Intent received: " + action);
957 if (ACTION_UICC_MANUAL_PROVISION_STATUS_CHANGED.equals(action)) {
958 int phoneId = intent.getIntExtra(PhoneConstants.PHONE_KEY,
959 SubscriptionManager.INVALID_SUBSCRIPTION_ID);
960 int newProvisionedState = intent.getIntExtra(EXTRA_NEW_PROVISION_STATE,
962 updateSubscriptions();
963 Log.d(TAG, "Received ACTION_UICC_MANUAL_PROVISION_STATUS_CHANGED on phoneId: "
964 + phoneId + " new sub state " + newProvisionedState);
969 // When primarycard feature enabled this provides menu option for user
970 // to view/select current primary slot.
971 private void initLTEPreference() {
972 boolean isPrimarySubFeatureEnable =
973 SystemProperties.getBoolean("persist.radio.primarycard", false);
974 boolean primarySetable = Settings.Global.getInt(mContext.getContentResolver(),
975 CONFIG_PRIMARY_SUB_SETABLE, 0) == 1;
977 log("isPrimarySubFeatureEnable :" + isPrimarySubFeatureEnable +
978 " primarySetable :" + primarySetable);
980 if (!isPrimarySubFeatureEnable || !primarySetable) {
981 final PreferenceCategory simActivities =
982 (PreferenceCategory) findPreference(SIM_ACTIVITIES_CATEGORY);
983 simActivities.removePreference(mPrimarySubSelect);
986 int currentPrimarySlot = Settings.Global.getInt(mContext.getContentResolver(),
987 CONFIG_CURRENT_PRIMARY_SUB, SubscriptionManager.INVALID_SIM_SLOT_INDEX);
988 boolean isManualMode = Settings.Global.getInt(mContext.getContentResolver(),
989 CONFIG_LTE_SUB_SELECT_MODE, 1) == 0;
991 log("init LTE primary slot : " + currentPrimarySlot + " isManualMode :" + isManualMode);
993 if (SubscriptionManager.isValidSlotId(currentPrimarySlot)) {
994 final SubscriptionInfo subInfo = mSubscriptionManager
995 .getActiveSubscriptionInfoForSimSlotIndex(currentPrimarySlot);
996 CharSequence lteSummary = (subInfo == null ) ? null : subInfo.getDisplayName();
997 mPrimarySubSelect.setSummary(lteSummary);
999 mPrimarySubSelect.setSummary("");
1001 mPrimarySubSelect.setEnabled(isManualMode);
1004 private boolean disableDds() {
1005 boolean disableDds = Settings.Global.getInt(mContext.getContentResolver(),
1006 CONFIG_DISABLE_DDS_PREFERENCE, 0) == 1;
1008 log(" config disable dds = " + disableDds);
1012 private void listen() {
1013 TelephonyManager tm =
1014 (TelephonyManager) getActivity().getSystemService(Context.TELEPHONY_SERVICE);
1015 if (mSelectableSubInfos.size() > 1) {
1016 Log.d(TAG, "Register for call state change");
1017 for (int i = 0; i < mPhoneCount; i++) {
1018 int subId = mSelectableSubInfos.get(i).getSubscriptionId();
1019 tm.listen(getPhoneStateListener(i, subId),
1020 PhoneStateListener.LISTEN_CALL_STATE);
1025 private void unRegisterPhoneStateListener() {
1026 TelephonyManager tm =
1027 (TelephonyManager) getActivity().getSystemService(Context.TELEPHONY_SERVICE);
1028 for (int i = 0; i < mPhoneCount; i++) {
1029 if (mPhoneStateListener[i] != null) {
1030 tm.listen(mPhoneStateListener[i], PhoneStateListener.LISTEN_NONE);
1031 mPhoneStateListener[i] = null;
1036 private PhoneStateListener getPhoneStateListener(int phoneId, int subId) {
1037 // Disable Sim selection for Data when voice call is going on as changing the default data
1038 // sim causes a modem reset currently and call gets disconnected
1039 // ToDo : Add subtext on disabled preference to let user know that default data sim cannot
1040 // be changed while call is going on
1041 final int i = phoneId;
1042 mPhoneStateListener[phoneId] = new PhoneStateListener(subId) {
1044 public void onCallStateChanged(int state, String incomingNumber) {
1045 if (DBG) log("PhoneStateListener.onCallStateChanged: state=" + state);
1046 mCallState[i] = state;
1047 updateCellularDataValues();
1050 return mPhoneStateListener[phoneId];
1053 private boolean isCallStateIdle() {
1054 boolean callStateIdle = true;
1055 for (int i = 0; i < mCallState.length; i++) {
1056 if (TelephonyManager.CALL_STATE_IDLE != mCallState[i]) {
1057 callStateIdle = false;
1060 Log.d(TAG, "isCallStateIdle " + callStateIdle);
1061 return callStateIdle;