OSDN Git Service

88ed36f7fcc9cf8870d26d2c6ab0b0f94ed3b303
[android-x86/packages-apps-Settings.git] / src / com / android / settings / sim / SimSettings.java
1 /*
2  * Copyright (C) 2014 The Android Open Source Project
3  *
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
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 package com.android.settings.sim;
18
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;
58
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;
68
69 import java.util.ArrayList;
70 import java.util.List;
71
72 public class SimSettings extends RestrictedSettingsFragment implements Indexable {
73     private static final String TAG = "SimSettings";
74     private static final boolean DBG = false;
75
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;
82
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";
92
93     private IExtTelephony mExtTelephony = IExtTelephony.Stub.
94             asInterface(ServiceManager.getService("extphone"));
95
96     /**
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.
101      */
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;
110
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];
119
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";
129
130     public SimSettings() {
131         super(DISALLOW_CONFIG_SIM);
132     }
133
134     @Override
135     protected int getMetricsCategory() {
136         return MetricsLogger.SIM;
137     }
138
139     @Override
140     public void onCreate(final Bundle bundle) {
141         super.onCreate(bundle);
142         mContext = getActivity();
143
144         mSubscriptionManager = SubscriptionManager.from(getActivity());
145         final TelephonyManager tm =
146                 (TelephonyManager) getActivity().getSystemService(Context.TELEPHONY_SERVICE);
147         addPreferencesFromResource(R.xml.sim_settings);
148
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());
156
157         IntentFilter intentFilter = new IntentFilter(ACTION_UICC_MANUAL_PROVISION_STATUS_CHANGED);
158         mContext.registerReceiver(mReceiver, intentFilter);
159     }
160
161     @Override
162     public void onDestroy() {
163         mContext.unregisterReceiver(mReceiver);
164         Log.d(TAG,"on onDestroy");
165         super.onDestroy();
166     }
167
168     private final SubscriptionManager.OnSubscriptionsChangedListener mOnSubscriptionsChangeListener
169             = new SubscriptionManager.OnSubscriptionsChangedListener() {
170         @Override
171         public void onSubscriptionsChanged() {
172             if (DBG) log("onSubscriptionsChanged:");
173             Activity activity = getActivity();
174             if (activity != null && !activity.isFinishing()) {
175                 updateSubscriptions();
176             }
177         }
178     };
179
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);
186             }
187         }
188         mMobileNetwork.removeAll();
189         mAvailableSubInfos.clear();
190         mSelectableSubInfos.clear();
191
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);
204             }
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);
216         }
217         updateAllOptions();
218     }
219
220     private void updateAllOptions() {
221         updateSimSlotValues();
222         updateActivitesCategory();
223     }
224
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();
231             }
232         }
233     }
234
235     private void updateActivitesCategory() {
236         updateCellularDataValues();
237         updateCallValues();
238         updateSmsValues();
239     }
240
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());
247         try {
248             isSMSPrompt = mExtTelephony.isSMSPromptEnabled();
249         } catch (RemoteException ex) {
250             loge("RemoteException @isSMSPromptEnabled" + ex);
251         } catch (NullPointerException ex) {
252             loge("NullPointerException @isSMSPromptEnabled" + ex);
253         }
254         // External telephony interfaces may not exist, fall back to our impl
255         if (mExtTelephony == null) {
256             isSMSPrompt = SmsManager.getDefault().isSMSPromptEnabled();
257         }
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));
262         } else {
263             simPref.setSummary(sir.getDisplayName());
264         }
265         simPref.setEnabled(mSelectableSubInfos.size() > 1);
266     }
267
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);
273
274         if (sir != null) {
275             simPref.setSummary(sir.getDisplayName());
276         } else if (sir == null) {
277             simPref.setSummary(R.string.sim_selection_required_pref);
278         }
279
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);
286     }
287
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();
295
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);
301     }
302
303     @Override
304     public void onResume() {
305         super.onResume();
306         mSubscriptionManager.addOnSubscriptionsChangedListener(mOnSubscriptionsChangeListener);
307         initLTEPreference();
308         updateSubscriptions();
309         listen();
310     }
311
312     @Override
313     public void onPause() {
314         super.onPause();
315         mSubscriptionManager.removeOnSubscriptionsChangedListener(mOnSubscriptionsChangeListener);
316         unRegisterPhoneStateListener();
317
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();
323             }
324         }
325     }
326
327     @Override
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);
333
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);
338             return true;
339         } else if (findPreference(KEY_CELLULAR_DATA) == preference) {
340             intent.putExtra(SimDialogActivity.DIALOG_TYPE_KEY, SimDialogActivity.DATA_PICK);
341             context.startActivity(intent);
342             return true;
343         } else if (findPreference(KEY_CALLS) == preference) {
344             intent.putExtra(SimDialogActivity.DIALOG_TYPE_KEY, SimDialogActivity.CALLS_PICK);
345             context.startActivity(intent);
346             return true;
347         } else if (findPreference(KEY_SMS) == preference) {
348             intent.putExtra(SimDialogActivity.DIALOG_TYPE_KEY, SimDialogActivity.SMS_PICK);
349             context.startActivity(intent);
350             return true;
351         }
352
353         return false;
354     }
355     private void loge(String msg) {
356         if (DBG) Log.e(TAG + "message", msg);
357     }
358
359     private void simEnablerUpdate() {
360         if (isAdded()) {
361             updateAllOptions();
362         } else {
363             needUpdate = true;
364         }
365     }
366
367     private class SimPreference extends Preference {
368         SubscriptionInfo mSubInfoRecord;
369         int mSlotId;
370         Context mContext;
371         public SimPreference(Context context, SubscriptionInfo subInfoRecord, int slotId) {
372             super(context);
373
374             mContext = context;
375             mSubInfoRecord = subInfoRecord;
376             mSlotId = slotId;
377             setKey("sim" + mSlotId);
378             update();
379         }
380         public SimPreference (Context context, AttributeSet attrs, int defStyle) {
381             super(context, attrs, defStyle);
382         }
383
384         public void update() {
385             final Resources res = mContext.getResources();
386
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());
392                 } else {
393                     setSummary(mSubInfoRecord.getDisplayName() + " - " +
394                             getPhoneNumber(mSubInfoRecord));
395                     setEnabled(true);
396                 }
397                 setIcon(new BitmapDrawable(res, (mSubInfoRecord.createIconBitmap(mContext))));
398             } else {
399                 setSummary(R.string.sim_slot_empty);
400                 setFragment(null);
401                 setEnabled(false);
402             }
403         }
404
405         private int getSlotId() {
406             return mSlotId;
407         }
408
409         @Override
410         protected void onAttachedToActivity() {
411             super.onAttachedToActivity();
412             if (needUpdate) {
413                 needUpdate = false;
414                 updateAllOptions();
415             }
416         }
417     }
418
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 {
422
423         private String TAG = "SimEnablerPreference";
424         private static final boolean DBG = true;
425
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;
430
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;
434
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;
439
440
441
442         private static final String DISPLAY_NUMBERS_TYPE = "display_numbers_type";
443
444         private SubscriptionInfo mSir;
445         private boolean mCurrentUiccProvisionState;
446         private boolean mIsChecked;
447
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;
454
455         private IExtTelephony mExtTelephony;
456
457
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");
462             mContext = context;
463             mSlotId = slotId;
464             mSir = sir;
465             mSubInfoRecord = sir;
466             if (mContext.getResources().getBoolean(R.bool.config_custom_multi_sim_checkbox)) {
467                 setWidgetLayoutResource(R.layout.custom_sim_checkbox);
468             } else {
469                 setWidgetLayoutResource(R.layout.custom_sim_switch);
470             }
471
472             mExtTelephony = IExtTelephony.Stub.asInterface(ServiceManager.getService("extphone"));
473
474             setSwitchVisibility(View.VISIBLE);
475             setKey("sim" + mSlotId);
476             update();
477         }
478
479         private void sendMessage(int event, Handler handler, int delay) {
480             Message message = handler.obtainMessage(event);
481             handler.sendMessageDelayed(message, delay);
482         }
483
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);
487         }
488
489         private boolean hasCard() {
490             return TelephonyManager.getDefault().hasIccCard(mSlotId);
491         }
492
493         private boolean isAirplaneModeOn() {
494             return (Settings.Global.getInt(mContext.getContentResolver(),
495                     Settings.Global.AIRPLANE_MODE_ON, 0) != 0);
496         }
497
498         private int getProvisionStatus(int slotId) {
499             return mUiccProvisionStatus[slotId];
500         }
501
502         @Override
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);
508             update();
509             // now use other config screen to active/deactive sim card\
510             mSwitch.setVisibility(mSwitchVisibility);
511
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);
517             } else {
518                 mSwitch.setVisibility(View.VISIBLE);
519                 mSwitch.setEnabled(!isAirplaneModeOn() && isCurrentSubValid());
520             }
521         }
522
523         @Override
524         public void update() {
525             final Resources res = mContext.getResources();
526             logd("update()" + mSir);
527             try {
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);
537             }
538
539             if (mUiccProvisionStatus[mSlotId] == INVALID_STATE) {
540                 mUiccProvisionStatus[mSlotId] = PROVISIONED;
541             }
542
543             boolean isSubValid = isCurrentSubValid();
544             setEnabled(isSubValid);
545
546             logd("update: isSubValid "  + isSubValid + " provision status["
547                     + mSlotId + "] = " + mUiccProvisionStatus[mSlotId]);
548             setTitle(res.getString(R.string.sim_card_number_title, mSlotId + 1));
549             if (isSubValid) {
550                 updateSummary();
551                 setIcon(new BitmapDrawable(res, (mSir.createIconBitmap(mContext))));
552             } else {
553                 setSummary(res.getString(R.string.sim_slot_empty));
554             }
555         }
556
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;
561             if (hasCard()) {
562                 List<SubscriptionInfo> sirList =
563                         mSubscriptionManager.getActiveSubscriptionInfoList();
564                 if (sirList != null ) {
565                     for (SubscriptionInfo sir : sirList) {
566                         if (sir != null && mSlotId == sir.getSimSlotIndex()) {
567                             mSir = sir;
568                             break;
569                         }
570                     }
571                     if (mSir != null &&
572                             SubscriptionManager.isValidSubscriptionId(mSir.getSubscriptionId()) &&
573                             mSir.getSimSlotIndex() >= 0 &&
574                             getProvisionStatus(mSir.getSimSlotIndex()) >= 0) {
575                         isSubValid = true;
576                     }
577                 }
578             }
579             return isSubValid;
580         }
581
582         public void setSwitchVisibility (int visibility) {
583             mSwitchVisibility = visibility;
584         }
585
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);
596                 }
597                 mSwitch.setOnCheckedChangeListener(this);
598                 mCurrentUiccProvisionState = uiccProvisionState;
599             }
600         }
601
602         private void updateSummary() {
603             Resources res = mContext.getResources();
604             String summary;
605             boolean isActivated = (getProvisionStatus(mSir.getSimSlotIndex()) == PROVISIONED);
606             logd("updateSummary: subId " + mSir.getSubscriptionId() + " isActivated = "
607                     + isActivated + " slot id = " + mSlotId);
608
609             String displayName = mSir == null ? "SIM" : (String)mSir.getDisplayName();
610             if (isActivated) {
611                 summary = displayName;
612                 if (!TextUtils.isEmpty(mSir.getNumber())) {
613                     summary = displayName + " - " + mSir.getNumber();
614                 }
615             } else {
616                 summary = mContext.getString(R.string.sim_enabler_summary, displayName,
617                         res.getString(hasCard() ? R.string.sim_disabled : R.string.sim_missing));
618             }
619
620             setSummary(summary);
621             setChecked(isActivated);
622         }
623
624
625         /**
626         * get number of Subs provisioned on the device
627         * @param context
628         * @return
629         */
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++;
638                 }
639             }
640             return activeSubInfoCount;
641         }
642
643         public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
644             mIsChecked = isChecked;
645             logd("onClick: " + isChecked);
646
647             handleUserRequest();
648         }
649
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
654         //    active state.
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);
661                 return;
662             }
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);
670                     return;
671                 }
672             }
673
674             if (!mIsChecked) {
675                 if (getNumOfSubsProvisioned() > 1) {
676                     logd("More than one sub is active, Deactivation possible.");
677                     showAlertDialog(CONFIRM_ALERT_DLG_ID, 0);
678                 } else {
679                     logd("Only one sub is active. Deactivation not possible.");
680                     showAlertDialog(ERROR_ALERT_DLG_ID, R.string.sim_enabler_both_inactive);
681                     return;
682                 }
683             } else {
684                 logd("Activate the sub");
685                 sendUiccProvisioningRequest();
686             }
687         }
688
689         private void sendUiccProvisioningRequest() {
690             if (!mSwitch.isEnabled()) {
691                 return;
692             }
693             new SimEnablerDisabler().execute();
694         }
695
696         private class SimEnablerDisabler extends AsyncTask<Void, Void, Integer> {
697
698             int newProvisionedState = NOT_PROVISIONED;
699
700             @Override
701             protected void onPreExecute() {
702                 super.onPreExecute();
703                 mCmdInProgress = true;
704                 showProgressDialog();
705                 setEnabled(false);
706             }
707
708             @Override
709             protected Integer doInBackground(Void... params) {
710                 int result = -1;
711                 newProvisionedState = NOT_PROVISIONED;
712                 try {
713                     if (mIsChecked) {
714                         result = mExtTelephony.activateUiccCard(mSir.getSimSlotIndex());
715                         newProvisionedState = PROVISIONED;
716                     } else {
717                         result = mExtTelephony.deactivateUiccCard(mSir.getSimSlotIndex());
718                     }
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);
723                 }
724                 return result;
725             }
726
727             @Override
728             protected void onPostExecute(Integer result) {
729                 processSetUiccDone(result.intValue(), newProvisionedState);
730             }
731         }
732
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;
737         }
738
739         private void showAlertDialog(int dialogId, int msgId) {
740
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)
746                     .setTitle(title);
747
748             switch(dialogId) {
749                 case CONFIRM_ALERT_DLG_ID:
750                     String message;
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));
758                         } else {
759                             message = mContext.getString(R.string.sim_enabler_need_disable_sim);
760                         }
761                         builder.setTitle(R.string.sim_enabler_will_disable_sim_title);
762                     } else {
763                         message = mContext.getString(R.string.sim_enabler_need_disable_sim);
764                     }
765                     builder.setMessage(message);
766                     builder.setPositiveButton(android.R.string.ok, mDialogClickListener);
767                     builder.setNegativeButton(android.R.string.no, mDialogClickListener);
768                     builder.setOnCancelListener(mDialogCanceListener);
769                     break;
770
771                 case ERROR_ALERT_DLG_ID:
772                     builder.setMessage(mContext.getString(msgId));
773                     builder.setNeutralButton(android.R.string.ok, mDialogClickListener);
774                     builder.setCancelable(false);
775                     break;
776
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);
783                     break;
784             default:
785             break;
786             }
787
788             sAlertDialog = builder.create();
789             sAlertDialog.setCanceledOnTouchOutside(false);
790             sAlertDialog.show();
791         }
792
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;
802                 }
803             }
804             return activeSlotId;
805         }
806
807         private void showProgressDialog() {
808             String title = mSir == null ? "SUB" : mSir.getDisplayName().toString();
809
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();
820
821             sendMessage(EVT_PROGRESS_DLG_TIME_OUT, mHandler, PROGRESS_DLG_TIME_OUT);
822         }
823
824         private void dismissDialog(Dialog dialog) {
825             if((dialog != null) && (dialog.isShowing())) {
826                 dialog.dismiss();
827                 dialog = null;
828             }
829         }
830
831         public void cleanUpPendingDialogs() {
832             dismissDialog(sProgressDialog);
833             dismissDialog(sAlertDialog);
834         }
835
836         private DialogInterface.OnClickListener mDialogClickListener = new DialogInterface
837                 .OnClickListener() {
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) {
843                             update();
844                         } else if (which == DialogInterface.BUTTON_NEUTRAL) {
845                             update();
846                         }
847                     }
848                 };
849
850         private DialogInterface.OnCancelListener mDialogCanceListener = new DialogInterface
851                 .OnCancelListener() {
852                     public void onCancel(DialogInterface dialog) {
853                         update();
854                     }
855                 };
856
857
858         private Handler mHandler = new Handler() {
859                 @Override
860                 public void handleMessage(Message msg) {
861
862                     switch(msg.what) {
863                         case EVT_UPDATE:
864                             simEnablerUpdate();
865
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);
871                             update();
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);
877                             } else {
878                                 showAlertDialog(RESULT_ALERT_DLG_ID, 0);
879                             }
880                             mHandler.removeMessages(EVT_PROGRESS_DLG_TIME_OUT);
881                             break;
882
883                         case EVT_SHOW_PROGRESS_DLG:
884                             logd("EVT_SHOW_PROGRESS_DLG");
885                             showProgressDialog();
886                             break;
887
888                         case EVT_PROGRESS_DLG_TIME_OUT:
889                             logd("EVT_PROGRESS_DLG_TIME_OUT");
890                             dismissDialog(sProgressDialog);
891                             // Must update UI when time out
892                             update();
893                             break;
894
895                         default:
896                         break;
897                     }
898                 }
899             };
900
901         private void logd(String msg) {
902             if (DBG) Log.d(TAG + "(" + mSlotId + ")", msg);
903         }
904
905         private void loge(String msg) {
906             Log.e(TAG + "(" + mSlotId + ")", msg);
907         }
908     }
909
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());
916     }
917
918     private void log(String s) {
919         Log.d(TAG, s);
920     }
921
922     /**
923      * For search
924      */
925     public static final SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
926             new BaseSearchIndexProvider() {
927                 @Override
928                 public List<SearchIndexableResource> getXmlResourcesToIndex(Context context,
929                         boolean enabled) {
930                     ArrayList<SearchIndexableResource> result =
931                             new ArrayList<SearchIndexableResource>();
932
933                     if (Utils.showSimCardTile(context)) {
934                         SearchIndexableResource sir = new SearchIndexableResource(context);
935                         sir.xmlResId = R.xml.sim_settings;
936                         result.add(sir);
937                     }
938
939                     return result;
940                 }
941             };
942
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;
947
948         if (mUiccProvisionStatus[slotId] == PROVISIONED) retVal = true;
949         return retVal;
950     }
951
952     private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
953         @Override
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,
961                         NOT_PROVISIONED);
962                  updateSubscriptions();
963                  Log.d(TAG, "Received ACTION_UICC_MANUAL_PROVISION_STATUS_CHANGED on phoneId: "
964                          + phoneId + " new sub state " + newProvisionedState);
965             }
966         }
967     };
968
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;
976
977         log("isPrimarySubFeatureEnable :" + isPrimarySubFeatureEnable +
978                 " primarySetable :" + primarySetable);
979
980         if (!isPrimarySubFeatureEnable || !primarySetable) {
981             final PreferenceCategory simActivities =
982                     (PreferenceCategory) findPreference(SIM_ACTIVITIES_CATEGORY);
983             simActivities.removePreference(mPrimarySubSelect);
984             return;
985         }
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;
990
991         log("init LTE primary slot : " + currentPrimarySlot + " isManualMode :" + isManualMode);
992
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);
998         } else {
999             mPrimarySubSelect.setSummary("");
1000         }
1001         mPrimarySubSelect.setEnabled(isManualMode);
1002     }
1003
1004     private boolean disableDds() {
1005         boolean disableDds = Settings.Global.getInt(mContext.getContentResolver(),
1006                 CONFIG_DISABLE_DDS_PREFERENCE, 0) == 1;
1007
1008         log(" config disable dds =  " + disableDds);
1009         return disableDds;
1010     }
1011
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);
1021             }
1022         }
1023     }
1024
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;
1032             }
1033         }
1034     }
1035
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) {
1043             @Override
1044             public void onCallStateChanged(int state, String incomingNumber) {
1045                 if (DBG) log("PhoneStateListener.onCallStateChanged: state=" + state);
1046                 mCallState[i] = state;
1047                 updateCellularDataValues();
1048             }
1049         };
1050         return mPhoneStateListener[phoneId];
1051     }
1052
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;
1058             }
1059         }
1060         Log.d(TAG, "isCallStateIdle " + callStateIdle);
1061         return callStateIdle;
1062     }
1063 }