SimSettings.java revision 0ee68facad30e97375a94c0701f61ea0d78d4e9c
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
17package com.android.settings.sim;
18
19import android.app.AlertDialog;
20import android.content.Context;
21import android.content.ContentUris;
22import android.content.DialogInterface;
23import android.content.res.Resources;
24import android.database.Cursor;
25import android.graphics.drawable.BitmapDrawable;
26import android.net.Uri;
27import android.os.Bundle;
28import android.preference.Preference;
29import android.preference.PreferenceCategory;
30import android.preference.PreferenceScreen;
31import android.provider.SearchIndexableResource;
32import android.provider.Telephony;
33import android.telephony.SubscriptionInfo;
34import android.telephony.SubscriptionManager;
35import android.telephony.TelephonyManager;
36import android.telephony.PhoneNumberUtils;
37import android.telecom.PhoneAccount;
38import android.telecom.PhoneAccountHandle;
39import android.telecom.TelecomManager;
40import android.text.TextUtils;
41import android.util.Log;
42import android.view.LayoutInflater;
43import android.view.View;
44import android.widget.ArrayAdapter;
45import android.widget.EditText;
46import android.widget.ImageView;
47import android.widget.Spinner;
48import android.widget.TextView;
49import android.app.Dialog;
50import android.view.ViewGroup;
51import android.widget.AdapterView;
52import android.widget.ListAdapter;
53
54import com.android.internal.telephony.PhoneFactory;
55import com.android.settings.RestrictedSettingsFragment;
56import com.android.settings.Utils;
57import com.android.settings.search.BaseSearchIndexProvider;
58import com.android.settings.search.Indexable;
59import com.android.settings.R;
60
61import java.util.ArrayList;
62import java.util.Collections;
63import java.util.Comparator;
64import java.util.Iterator;
65import java.util.List;
66
67public class SimSettings extends RestrictedSettingsFragment implements Indexable {
68    private static final String TAG = "SimSettings";
69
70    private static final String DISALLOW_CONFIG_SIM = "no_config_sim";
71    private static final String SIM_CARD_CATEGORY = "sim_cards";
72    private static final String KEY_CELLULAR_DATA = "sim_cellular_data";
73    private static final String KEY_CALLS = "sim_calls";
74    private static final String KEY_SMS = "sim_sms";
75    private static final String KEY_ACTIVITIES = "activities";
76    private static final int ID_INDEX = 0;
77    private static final int NAME_INDEX = 1;
78    private static final int APN_INDEX = 2;
79    private static final int PROXY_INDEX = 3;
80    private static final int PORT_INDEX = 4;
81    private static final int USER_INDEX = 5;
82    private static final int SERVER_INDEX = 6;
83    private static final int PASSWORD_INDEX = 7;
84    private static final int MMSC_INDEX = 8;
85    private static final int MCC_INDEX = 9;
86    private static final int MNC_INDEX = 10;
87    private static final int NUMERIC_INDEX = 11;
88    private static final int MMSPROXY_INDEX = 12;
89    private static final int MMSPORT_INDEX = 13;
90    private static final int AUTH_TYPE_INDEX = 14;
91    private static final int TYPE_INDEX = 15;
92    private static final int PROTOCOL_INDEX = 16;
93    private static final int CARRIER_ENABLED_INDEX = 17;
94    private static final int BEARER_INDEX = 18;
95    private static final int ROAMING_PROTOCOL_INDEX = 19;
96    private static final int MVNO_TYPE_INDEX = 20;
97    private static final int MVNO_MATCH_DATA_INDEX = 21;
98    private static final int DATA_PICK = 0;
99    private static final int CALLS_PICK = 1;
100    private static final int SMS_PICK = 2;
101
102    /**
103     * By UX design we use only one Subscription Information(SubInfo) record per SIM slot.
104     * mAvalableSubInfos is the list of SubInfos we present to the user.
105     * mSubInfoList is the list of all SubInfos.
106     * mSelectableSubInfos is the list of SubInfos that a user can select for data, calls, and SMS.
107     */
108    private List<SubscriptionInfo> mAvailableSubInfos = null;
109    private List<SubscriptionInfo> mSubInfoList = null;
110    private List<SubscriptionInfo> mSelectableSubInfos = null;
111
112    private SubscriptionInfo mCellularData = null;
113    private SubscriptionInfo mCalls = null;
114    private SubscriptionInfo mSMS = null;
115
116    private PreferenceCategory mSimCards = null;
117
118    public SimSettings() {
119        super(DISALLOW_CONFIG_SIM);
120    }
121
122    @Override
123    public void onCreate(final Bundle bundle) {
124        super.onCreate(bundle);
125
126        if (mSubInfoList == null) {
127            mSubInfoList = SubscriptionManager.getActiveSubscriptionInfoList();
128        }
129
130        createPreferences();
131        updateAllOptions();
132    }
133
134    private void createPreferences() {
135        final TelephonyManager tm =
136            (TelephonyManager) getActivity().getSystemService(Context.TELEPHONY_SERVICE);
137
138        addPreferencesFromResource(R.xml.sim_settings);
139
140        mSimCards = (PreferenceCategory)findPreference(SIM_CARD_CATEGORY);
141
142        final int numSlots = tm.getSimCount();
143        mAvailableSubInfos = new ArrayList<SubscriptionInfo>(numSlots);
144        mSelectableSubInfos = new ArrayList<SubscriptionInfo>();
145        for (int i = 0; i < numSlots; ++i) {
146            final SubscriptionInfo sir = Utils.findRecordBySlotId(i);
147            mSimCards.addPreference(new SimPreference(getActivity(), sir, i));
148            mAvailableSubInfos.add(sir);
149            if (sir != null) {
150                mSelectableSubInfos.add(sir);
151            }
152        }
153
154        updateActivitesCategory();
155    }
156
157    private void updateAvailableSubInfos(){
158        final TelephonyManager tm =
159            (TelephonyManager) getActivity().getSystemService(Context.TELEPHONY_SERVICE);
160        final int numSlots = tm.getSimCount();
161
162        mAvailableSubInfos = new ArrayList<SubscriptionInfo>(numSlots);
163        for (int i = 0; i < numSlots; ++i) {
164            final SubscriptionInfo sir = Utils.findRecordBySlotId(i);
165            mAvailableSubInfos.add(sir);
166            if (sir != null) {
167            }
168        }
169    }
170
171    private void updateAllOptions() {
172        updateSimSlotValues();
173        updateActivitesCategory();
174    }
175
176    private void updateSimSlotValues() {
177        SubscriptionManager.getAllSubscriptionInfoList();
178
179        final int prefSize = mSimCards.getPreferenceCount();
180        for (int i = 0; i < prefSize; ++i) {
181            Preference pref = mSimCards.getPreference(i);
182            if (pref instanceof SimPreference) {
183                ((SimPreference)pref).update();
184            }
185        }
186    }
187
188    private void updateActivitesCategory() {
189        updateCellularDataValues();
190        updateCallValues();
191        updateSmsValues();
192    }
193
194    private void updateSmsValues() {
195        final Preference simPref = findPreference(KEY_SMS);
196        final SubscriptionInfo sir = Utils.findRecordBySubId(SubscriptionManager.getDefaultSmsSubId());
197        simPref.setTitle(R.string.sms_messages_title);
198        if (mSubInfoList.size() == 1) {
199            simPref.setSummary(mSubInfoList.get(0).getDisplayName());
200        } else if (sir != null) {
201            simPref.setSummary(sir.getDisplayName());
202        } else if (sir == null) {
203            simPref.setSummary(R.string.sim_selection_required_pref);
204        }
205        simPref.setEnabled(mSelectableSubInfos.size() >= 1);
206    }
207
208    private void updateCellularDataValues() {
209        final Preference simPref = findPreference(KEY_CELLULAR_DATA);
210        final SubscriptionInfo sir = Utils.findRecordBySubId(SubscriptionManager.getDefaultDataSubId());
211        simPref.setTitle(R.string.cellular_data_title);
212        if (mSubInfoList.size() == 1) {
213            simPref.setSummary(mSubInfoList.get(0).getDisplayName());
214        } else if (sir != null) {
215            simPref.setSummary(sir.getDisplayName());
216        } else if (sir == null) {
217            simPref.setSummary(R.string.sim_selection_required_pref);
218        }
219        simPref.setEnabled(mSelectableSubInfos.size() >= 1);
220    }
221
222    private void updateCallValues() {
223        final Preference simPref = findPreference(KEY_CALLS);
224        final TelecomManager telecomManager = TelecomManager.from(getActivity());
225        final PhoneAccountHandle phoneAccount =
226            telecomManager.getUserSelectedOutgoingPhoneAccount();
227
228        simPref.setTitle(R.string.calls_title);
229        simPref.setSummary(phoneAccount == null
230                ? getResources().getString(R.string.sim_selection_required_pref)
231                : (String)telecomManager.getPhoneAccount(phoneAccount).getLabel());
232    }
233
234    @Override
235    public void onResume() {
236        super.onResume();
237
238        mSubInfoList = SubscriptionManager.getActiveSubscriptionInfoList();
239        updateAvailableSubInfos();
240        updateAllOptions();
241    }
242
243    @Override
244    public boolean onPreferenceTreeClick(final PreferenceScreen preferenceScreen,
245            final Preference preference) {
246        if (preference instanceof SimPreference) {
247            ((SimPreference)preference).createEditDialog((SimPreference)preference);
248        } else if (findPreference(KEY_CELLULAR_DATA) == preference) {
249            showDialog(DATA_PICK);
250        } else if (findPreference(KEY_CALLS) == preference) {
251            showDialog(CALLS_PICK);
252        } else if (findPreference(KEY_SMS) == preference) {
253            showDialog(SMS_PICK);
254        }
255
256        return true;
257    }
258
259    @Override
260    public Dialog onCreateDialog(final int id) {
261        final ArrayList<String> list = new ArrayList<String>();
262        final int selectableSubInfoLength = mSelectableSubInfos.size();
263
264        final DialogInterface.OnClickListener selectionListener =
265                new DialogInterface.OnClickListener() {
266                    @Override
267                    public void onClick(DialogInterface dialog, int value) {
268
269                        final SubscriptionInfo sir;
270
271                        if (id == DATA_PICK) {
272                            sir = mSelectableSubInfos.get(value);
273                            SubscriptionManager.setDefaultDataSubId(sir.getSubscriptionId());
274                        } else if (id == CALLS_PICK) {
275                            final TelecomManager telecomManager =
276                                    TelecomManager.from(getActivity());
277                            final List<PhoneAccountHandle> phoneAccountsList =
278                                    telecomManager.getCallCapablePhoneAccounts();
279                            telecomManager.setUserSelectedOutgoingPhoneAccount(
280                                    value < 1 ? null : phoneAccountsList.get(value - 1));
281                        } else if (id == SMS_PICK) {
282                            sir = mSelectableSubInfos.get(value);
283                            SubscriptionManager.setDefaultSmsSubId(sir.getSubscriptionId());
284                        }
285
286                        updateActivitesCategory();
287                    }
288                };
289
290        if (id == CALLS_PICK) {
291            final TelecomManager telecomManager = TelecomManager.from(getActivity());
292            final Iterator<PhoneAccountHandle> phoneAccounts =
293                    telecomManager.getCallCapablePhoneAccounts().listIterator();
294
295            list.add(getResources().getString(R.string.sim_calls_ask_first_prefs_title));
296            while (phoneAccounts.hasNext()) {
297                final PhoneAccount phoneAccount =
298                        telecomManager.getPhoneAccount(phoneAccounts.next());
299                list.add((String)phoneAccount.getLabel());
300            }
301        } else {
302            for (int i = 0; i < selectableSubInfoLength; ++i) {
303                final SubscriptionInfo sir = mSelectableSubInfos.get(i);
304                CharSequence displayName = sir.getDisplayName();
305                if (displayName == null) {
306                    displayName = "";
307                }
308                list.add(displayName.toString());
309            }
310        }
311
312        String[] arr = list.toArray(new String[0]);
313
314        AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
315
316        ListAdapter adapter = new SelectAccountListAdapter(
317                builder.getContext(),
318                R.layout.select_account_list_item,
319                arr, id);
320
321        if (id == DATA_PICK) {
322            builder.setTitle(R.string.select_sim_for_data);
323        } else if (id == CALLS_PICK) {
324            builder.setTitle(R.string.select_sim_for_calls);
325        } else if (id == SMS_PICK) {
326            builder.setTitle(R.string.sim_card_select_title);
327        }
328
329        return builder.setAdapter(adapter, selectionListener)
330            .create();
331    }
332
333    private class SelectAccountListAdapter extends ArrayAdapter<String> {
334        private Context mContext;
335        private int mResId;
336        private int mDialogId;
337        private final float OPACITY = 0.54f;
338
339        public SelectAccountListAdapter(
340                Context context, int resource, String[] arr, int dialogId) {
341            super(context, resource, arr);
342            mContext = context;
343            mResId = resource;
344            mDialogId = dialogId;
345        }
346
347        @Override
348        public View getView(int position, View convertView, ViewGroup parent) {
349            LayoutInflater inflater = (LayoutInflater)
350                    mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
351            View rowView;
352            final ViewHolder holder;
353            SubscriptionInfo sir;
354
355            if (convertView == null) {
356                // Cache views for faster scrolling
357                rowView = inflater.inflate(mResId, null);
358                holder = new ViewHolder();
359                holder.title = (TextView) rowView.findViewById(R.id.title);
360                holder.summary = (TextView) rowView.findViewById(R.id.summary);
361                holder.icon = (ImageView) rowView.findViewById(R.id.icon);
362                rowView.setTag(holder);
363            } else {
364                rowView = convertView;
365                holder = (ViewHolder) rowView.getTag();
366            }
367
368            if (mDialogId == CALLS_PICK) {
369                holder.title.setText(getItem(position));
370                holder.summary.setText("");
371                holder.icon.setImageDrawable(getResources()
372                        .getDrawable(R.drawable.ic_live_help));
373                holder.icon.setAlpha(OPACITY);
374            } else {
375                sir = mSelectableSubInfos.get(position);
376                holder.title.setText(sir.getDisplayName());
377                holder.summary.setText(sir.getNumber());
378                holder.icon.setImageBitmap(sir.createIconBitmap(mContext));
379            }
380            return rowView;
381        }
382
383        private class ViewHolder {
384            TextView title;
385            TextView summary;
386            ImageView icon;
387        }
388    }
389
390    private class SimPreference extends Preference{
391        private SubscriptionInfo mSubInfoRecord;
392        private int mSlotId;
393        private int[] tintArr;
394        Context mContext;
395
396        public SimPreference(Context context, SubscriptionInfo subInfoRecord, int slotId) {
397            super(context);
398
399            mContext = context;
400            mSubInfoRecord = subInfoRecord;
401            mSlotId = slotId;
402            setKey("sim" + mSlotId);
403            update();
404            tintArr = context.getResources().getIntArray(com.android.internal.R.array.sim_colors);
405        }
406
407        public void update() {
408            final Resources res = getResources();
409
410            setTitle(String.format(getResources()
411                    .getString(R.string.sim_editor_title), (mSlotId + 1)));
412            if (mSubInfoRecord != null) {
413                if (TextUtils.isEmpty(mSubInfoRecord.getNumber().toString())) {
414                   setSummary(mSubInfoRecord.getDisplayName());
415                } else {
416                    setSummary(mSubInfoRecord.getDisplayName() + " - " +
417                            mSubInfoRecord.getNumber().toString());
418                    setEnabled(true);
419                }
420                setIcon(new BitmapDrawable(res, (mSubInfoRecord.createIconBitmap(mContext))));
421            } else {
422                setSummary(R.string.sim_slot_empty);
423                setFragment(null);
424                setEnabled(false);
425            }
426        }
427
428        public SubscriptionInfo getSubInfoRecord() {
429            return mSubInfoRecord;
430        }
431
432        public void createEditDialog(SimPreference simPref) {
433            final Resources res = getResources();
434
435            AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
436
437            final View dialogLayout = getActivity().getLayoutInflater().inflate(
438                    R.layout.multi_sim_dialog, null);
439            builder.setView(dialogLayout);
440
441            EditText nameText = (EditText)dialogLayout.findViewById(R.id.sim_name);
442            nameText.setText(mSubInfoRecord.getDisplayName());
443
444            final Spinner tintSpinner = (Spinner) dialogLayout.findViewById(R.id.spinner);
445            ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(getContext(),
446                    R.array.color_picker, android.R.layout.simple_spinner_item);
447            adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
448            tintSpinner.setAdapter(adapter);
449
450            for (int i = 0; i < tintArr.length; i++) {
451                if (tintArr[i] == mSubInfoRecord.getIconTint()) {
452                    tintSpinner.setSelection(i);
453                    break;
454                }
455            }
456
457            tintSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
458                @Override
459                public void onItemSelected(AdapterView<?> parent, View view,
460                    int pos, long id){
461                    tintSpinner.setSelection(pos);
462                }
463
464                @Override
465                public void onNothingSelected(AdapterView<?> parent) {
466                }
467            });
468
469            TextView numberView = (TextView)dialogLayout.findViewById(R.id.number);
470            final String rawNumber = mSubInfoRecord.getNumber();
471            if (TextUtils.isEmpty(rawNumber)) {
472                numberView.setText(res.getString(com.android.internal.R.string.unknownName));
473            } else {
474                numberView.setText(PhoneNumberUtils.formatNumber(rawNumber));
475            }
476
477            TextView carrierView = (TextView)dialogLayout.findViewById(R.id.carrier);
478            carrierView.setText(mSubInfoRecord.getCarrierName());
479
480            builder.setTitle(String.format(res.getString(R.string.sim_editor_title),
481                    (mSubInfoRecord.getSimSlotIndex() + 1)));
482
483            builder.setPositiveButton(R.string.okay, new DialogInterface.OnClickListener() {
484                @Override
485                public void onClick(DialogInterface dialog, int whichButton) {
486                    final EditText nameText = (EditText)dialogLayout.findViewById(R.id.sim_name);
487
488                    String displayName = nameText.getText().toString();
489                    int subId = mSubInfoRecord.getSubscriptionId();
490                    mSubInfoRecord.setDisplayName(displayName);
491                    SubscriptionManager.setDisplayName(displayName, subId,
492                            SubscriptionManager.NAME_SOURCE_USER_INPUT);
493                    Utils.findRecordBySubId(subId).setDisplayName(displayName);
494
495                    final int tintSelected = tintSpinner.getSelectedItemPosition();
496                    int subscriptionId = mSubInfoRecord.getSubscriptionId();
497                    int tint = tintArr[tintSelected];
498                    mSubInfoRecord.setIconTint(tint);
499                    SubscriptionManager.setIconTint(tint, subscriptionId);
500                    Utils.findRecordBySubId(subscriptionId).setIconTint(tint);
501
502                    updateAllOptions();
503                    update();
504                }
505            });
506
507            builder.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
508                @Override
509                public void onClick(DialogInterface dialog, int whichButton) {
510                    dialog.dismiss();
511                }
512            });
513
514            builder.create().show();
515        }
516    }
517
518    /**
519     * Sort Subscription List in SIM Id, Subscription Id
520     * @param context The Context
521     * @return Sorted Subscription List or NULL if no activated Subscription
522     */
523    public static List<SubscriptionInfo> getSortedSubInfoList(Context context) {
524        List<SubscriptionInfo> infoList = SubscriptionManager.getActiveSubscriptionInfoList();
525        if (infoList != null) {
526            Collections.sort(infoList, new Comparator<SubscriptionInfo>() {
527
528                @Override
529                public int compare(SubscriptionInfo arg0, SubscriptionInfo arg1) {
530                    int flag = arg0.getSimSlotIndex() - arg1.getSimSlotIndex();
531                    if (flag == 0) {
532                        return arg0.getSubscriptionId() - arg1.getSubscriptionId();
533                    }
534                    return flag;
535                }
536            });
537        }
538        return infoList;
539    }
540
541    /**
542     * For search
543     */
544    public static final SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
545            new BaseSearchIndexProvider() {
546                @Override
547                public List<SearchIndexableResource> getXmlResourcesToIndex(Context context,
548                        boolean enabled) {
549                    ArrayList<SearchIndexableResource> result =
550                            new ArrayList<SearchIndexableResource>();
551
552                    if (Utils.showSimCardTile(context)) {
553                        SearchIndexableResource sir = new SearchIndexableResource(context);
554                        sir.xmlResId = R.xml.sim_settings;
555                        result.add(sir);
556                    }
557
558                    return result;
559                }
560            };
561
562}
563