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