SubscriptionManager.java revision 598d24c55817cfbd00b6dafdf772334a7039fe3e
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 android.telephony; 18 19import android.annotation.NonNull; 20import android.annotation.SdkConstant; 21import android.annotation.SdkConstant.SdkConstantType; 22import android.content.Context; 23import android.content.Intent; 24import android.content.res.Configuration; 25import android.content.res.Resources; 26import android.net.Uri; 27import android.telephony.Rlog; 28import android.os.Handler; 29import android.os.Message; 30import android.os.ServiceManager; 31import android.os.RemoteException; 32import android.util.DisplayMetrics; 33 34import com.android.internal.telephony.ISub; 35import com.android.internal.telephony.IOnSubscriptionsChangedListener; 36import com.android.internal.telephony.ITelephonyRegistry; 37import com.android.internal.telephony.PhoneConstants; 38import java.util.ArrayList; 39import java.util.List; 40 41/** 42 * SubscriptionManager is the application interface to SubscriptionController 43 * and provides information about the current Telephony Subscriptions. 44 * * <p> 45 * You do not instantiate this class directly; instead, you retrieve 46 * a reference to an instance through {@link #from}. 47 * <p> 48 * All SDK public methods require android.Manifest.permission.READ_PHONE_STATE. 49 */ 50public class SubscriptionManager { 51 private static final String LOG_TAG = "SubscriptionManager"; 52 private static final boolean DBG = false; 53 private static final boolean VDBG = false; 54 55 /** An invalid subscription identifier */ 56 public static final int INVALID_SUBSCRIPTION_ID = -1; 57 58 /** Base value for Dummy SUBSCRIPTION_ID's. */ 59 /** FIXME: Remove DummySubId's, but for now have them map just below INVALID_SUBSCRIPTION_ID 60 /** @hide */ 61 public static final int DUMMY_SUBSCRIPTION_ID_BASE = INVALID_SUBSCRIPTION_ID - 1; 62 63 /** An invalid phone identifier */ 64 /** @hide */ 65 public static final int INVALID_PHONE_INDEX = -1; 66 67 /** An invalid slot identifier */ 68 /** @hide */ 69 public static final int INVALID_SIM_SLOT_INDEX = -1; 70 71 /** Indicates the caller wants the default sub id. */ 72 /** @hide */ 73 public static final int DEFAULT_SUBSCRIPTION_ID = Integer.MAX_VALUE; 74 75 /** 76 * Indicates the caller wants the default phone id. 77 * Used in SubscriptionController and Phone but do we really need it??? 78 * @hide 79 */ 80 public static final int DEFAULT_PHONE_INDEX = Integer.MAX_VALUE; 81 82 /** Indicates the caller wants the default slot id. NOT used remove? */ 83 /** @hide */ 84 public static final int DEFAULT_SIM_SLOT_INDEX = Integer.MAX_VALUE; 85 86 /** Minimum possible subid that represents a subscription */ 87 /** @hide */ 88 public static final int MIN_SUBSCRIPTION_ID_VALUE = 0; 89 90 /** Maximum possible subid that represents a subscription */ 91 /** @hide */ 92 public static final int MAX_SUBSCRIPTION_ID_VALUE = DEFAULT_SUBSCRIPTION_ID - 1; 93 94 /** @hide */ 95 public static final Uri CONTENT_URI = Uri.parse("content://telephony/siminfo"); 96 97 /** 98 * TelephonyProvider unique key column name is the subscription id. 99 * <P>Type: TEXT (String)</P> 100 */ 101 /** @hide */ 102 public static final String UNIQUE_KEY_SUBSCRIPTION_ID = "_id"; 103 104 /** 105 * TelephonyProvider column name for SIM ICC Identifier 106 * <P>Type: TEXT (String)</P> 107 */ 108 /** @hide */ 109 public static final String ICC_ID = "icc_id"; 110 111 /** 112 * TelephonyProvider column name for user SIM_SlOT_INDEX 113 * <P>Type: INTEGER (int)</P> 114 */ 115 /** @hide */ 116 public static final String SIM_SLOT_INDEX = "sim_id"; 117 118 /** SIM is not inserted */ 119 /** @hide */ 120 public static final int SIM_NOT_INSERTED = -1; 121 122 /** 123 * TelephonyProvider column name for user displayed name. 124 * <P>Type: TEXT (String)</P> 125 */ 126 /** @hide */ 127 public static final String DISPLAY_NAME = "display_name"; 128 129 /** 130 * TelephonyProvider column name for the service provider name for the SIM. 131 * <P>Type: TEXT (String)</P> 132 */ 133 /** @hide */ 134 public static final String CARRIER_NAME = "carrier_name"; 135 136 /** 137 * Default name resource 138 * @hide 139 */ 140 public static final int DEFAULT_NAME_RES = com.android.internal.R.string.unknownName; 141 142 /** 143 * TelephonyProvider column name for source of the user displayed name. 144 * <P>Type: INT (int)</P> with one of the NAME_SOURCE_XXXX values below 145 * 146 * @hide 147 */ 148 public static final String NAME_SOURCE = "name_source"; 149 150 /** 151 * The name_source is undefined 152 * @hide 153 */ 154 public static final int NAME_SOURCE_UNDEFINDED = -1; 155 156 /** 157 * The name_source is the default 158 * @hide 159 */ 160 public static final int NAME_SOURCE_DEFAULT_SOURCE = 0; 161 162 /** 163 * The name_source is from the SIM 164 * @hide 165 */ 166 public static final int NAME_SOURCE_SIM_SOURCE = 1; 167 168 /** 169 * The name_source is from the user 170 * @hide 171 */ 172 public static final int NAME_SOURCE_USER_INPUT = 2; 173 174 /** 175 * TelephonyProvider column name for the color of a SIM. 176 * <P>Type: INTEGER (int)</P> 177 */ 178 /** @hide */ 179 public static final String COLOR = "color"; 180 181 /** @hide */ 182 public static final int COLOR_1 = 0; 183 184 /** @hide */ 185 public static final int COLOR_2 = 1; 186 187 /** @hide */ 188 public static final int COLOR_3 = 2; 189 190 /** @hide */ 191 public static final int COLOR_4 = 3; 192 193 /** @hide */ 194 public static final int COLOR_DEFAULT = COLOR_1; 195 196 /** 197 * TelephonyProvider column name for the phone number of a SIM. 198 * <P>Type: TEXT (String)</P> 199 */ 200 /** @hide */ 201 public static final String NUMBER = "number"; 202 203 /** 204 * TelephonyProvider column name for the number display format of a SIM. 205 * <P>Type: INTEGER (int)</P> 206 */ 207 /** @hide */ 208 public static final String DISPLAY_NUMBER_FORMAT = "display_number_format"; 209 210 /** @hide */ 211 public static final int DISPLAY_NUMBER_NONE = 0; 212 213 /** @hide */ 214 public static final int DISPLAY_NUMBER_FIRST = 1; 215 216 /** @hide */ 217 public static final int DISPLAY_NUMBER_LAST = 2; 218 219 /** @hide */ 220 public static final int DISPLAY_NUMBER_DEFAULT = DISPLAY_NUMBER_FIRST; 221 222 /** 223 * TelephonyProvider column name for permission for data roaming of a SIM. 224 * <P>Type: INTEGER (int)</P> 225 */ 226 /** @hide */ 227 public static final String DATA_ROAMING = "data_roaming"; 228 229 /** Indicates that data roaming is enabled for a subscription */ 230 public static final int DATA_ROAMING_ENABLE = 1; 231 232 /** Indicates that data roaming is disabled for a subscription */ 233 public static final int DATA_ROAMING_DISABLE = 0; 234 235 /** @hide */ 236 public static final int DATA_ROAMING_DEFAULT = DATA_ROAMING_DISABLE; 237 238 /** @hide */ 239 public static final int SIM_PROVISIONED = 0; 240 241 /** 242 * TelephonyProvider column name for the MCC associated with a SIM. 243 * <P>Type: INTEGER (int)</P> 244 * @hide 245 */ 246 public static final String MCC = "mcc"; 247 248 /** 249 * TelephonyProvider column name for the MNC associated with a SIM. 250 * <P>Type: INTEGER (int)</P> 251 * @hide 252 */ 253 public static final String MNC = "mnc"; 254 255 /** 256 * TelephonyProvider column name for the sim provisioning status associated with a SIM. 257 * <P>Type: INTEGER (int)</P> 258 * @hide 259 */ 260 public static final String SIM_PROVISIONING_STATUS = "sim_provisioning_status"; 261 262 /** 263 * TelephonyProvider column name for extreme threat in CB settings 264 * @hide 265 */ 266 public static final String CB_EXTREME_THREAT_ALERT = "enable_cmas_extreme_threat_alerts"; 267 268 /** 269 * TelephonyProvider column name for severe threat in CB settings 270 *@hide 271 */ 272 public static final String CB_SEVERE_THREAT_ALERT = "enable_cmas_severe_threat_alerts"; 273 274 /** 275 * TelephonyProvider column name for amber alert in CB settings 276 *@hide 277 */ 278 public static final String CB_AMBER_ALERT = "enable_cmas_amber_alerts"; 279 280 /** 281 * TelephonyProvider column name for emergency alert in CB settings 282 *@hide 283 */ 284 public static final String CB_EMERGENCY_ALERT = "enable_emergency_alerts"; 285 286 /** 287 * TelephonyProvider column name for alert sound duration in CB settings 288 *@hide 289 */ 290 public static final String CB_ALERT_SOUND_DURATION = "alert_sound_duration"; 291 292 /** 293 * TelephonyProvider column name for alert reminder interval in CB settings 294 *@hide 295 */ 296 public static final String CB_ALERT_REMINDER_INTERVAL = "alert_reminder_interval"; 297 298 /** 299 * TelephonyProvider column name for enabling vibrate in CB settings 300 *@hide 301 */ 302 public static final String CB_ALERT_VIBRATE = "enable_alert_vibrate"; 303 304 /** 305 * TelephonyProvider column name for enabling alert speech in CB settings 306 *@hide 307 */ 308 public static final String CB_ALERT_SPEECH = "enable_alert_speech"; 309 310 /** 311 * TelephonyProvider column name for ETWS test alert in CB settings 312 *@hide 313 */ 314 public static final String CB_ETWS_TEST_ALERT = "enable_etws_test_alerts"; 315 316 /** 317 * TelephonyProvider column name for enable channel50 alert in CB settings 318 *@hide 319 */ 320 public static final String CB_CHANNEL_50_ALERT = "enable_channel_50_alerts"; 321 322 /** 323 * TelephonyProvider column name for CMAS test alert in CB settings 324 *@hide 325 */ 326 public static final String CB_CMAS_TEST_ALERT= "enable_cmas_test_alerts"; 327 328 /** 329 * TelephonyProvider column name for Opt out dialog in CB settings 330 *@hide 331 */ 332 public static final String CB_OPT_OUT_DIALOG = "show_cmas_opt_out_dialog"; 333 334 /** 335 * Broadcast Action: The user has changed one of the default subs related to 336 * data, phone calls, or sms</p> 337 * 338 * TODO: Change to a listener 339 * @hide 340 */ 341 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 342 public static final String SUB_DEFAULT_CHANGED_ACTION = 343 "android.intent.action.SUB_DEFAULT_CHANGED"; 344 345 /** 346 * Broadcast Action: The default subscription has changed. This has the following 347 * extra values:</p> 348 * The {@link #EXTRA_SUBSCRIPTION_INDEX} extra indicates the current default subscription index 349 */ 350 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 351 public static final String ACTION_DEFAULT_SUBSCRIPTION_CHANGED 352 = "android.telephony.action.DEFAULT_SUBSCRIPTION_CHANGED"; 353 354 /** 355 * Broadcast Action: The default sms subscription has changed. This has the following 356 * extra values:</p> 357 * {@link #EXTRA_SUBSCRIPTION_INDEX} extra indicates the current default sms 358 * subscription index 359 */ 360 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 361 public static final String ACTION_DEFAULT_SMS_SUBSCRIPTION_CHANGED 362 = "android.telephony.action.DEFAULT_SMS_SUBSCRIPTION_CHANGED"; 363 364 /** 365 * Integer extra used with {@link #ACTION_DEFAULT_SUBSCRIPTION_CHANGED} and 366 * {@link #ACTION_DEFAULT_SMS_SUBSCRIPTION_CHANGED} to indicate the subscription 367 * which has changed. 368 */ 369 public static final String EXTRA_SUBSCRIPTION_INDEX = "android.telephony.extra.SUBSCRIPTION_INDEX"; 370 371 private final Context mContext; 372 373 /** 374 * A listener class for monitoring changes to {@link SubscriptionInfo} records. 375 * <p> 376 * Override the onSubscriptionsChanged method in the object that extends this 377 * class and pass it to {@link #addOnSubscriptionsChangedListener(OnSubscriptionsChangedListener)} 378 * to register your listener and to unregister invoke 379 * {@link #removeOnSubscriptionsChangedListener(OnSubscriptionsChangedListener)} 380 * <p> 381 * Permissions android.Manifest.permission.READ_PHONE_STATE is required 382 * for #onSubscriptionsChanged to be invoked. 383 */ 384 public static class OnSubscriptionsChangedListener { 385 private final Handler mHandler = new Handler() { 386 @Override 387 public void handleMessage(Message msg) { 388 if (DBG) { 389 log("handleMessage: invoke the overriden onSubscriptionsChanged()"); 390 } 391 OnSubscriptionsChangedListener.this.onSubscriptionsChanged(); 392 } 393 }; 394 395 /** 396 * Callback invoked when there is any change to any SubscriptionInfo. Typically 397 * this method would invoke {@link #getActiveSubscriptionInfoList} 398 */ 399 public void onSubscriptionsChanged() { 400 if (DBG) log("onSubscriptionsChanged: NOT OVERRIDDEN"); 401 } 402 403 /** 404 * The callback methods need to be called on the handler thread where 405 * this object was created. If the binder did that for us it'd be nice. 406 */ 407 IOnSubscriptionsChangedListener callback = new IOnSubscriptionsChangedListener.Stub() { 408 @Override 409 public void onSubscriptionsChanged() { 410 if (DBG) log("callback: received, sendEmptyMessage(0) to handler"); 411 mHandler.sendEmptyMessage(0); 412 } 413 }; 414 415 private void log(String s) { 416 Rlog.d(LOG_TAG, s); 417 } 418 } 419 420 /** @hide */ 421 public SubscriptionManager(Context context) { 422 if (DBG) logd("SubscriptionManager created"); 423 mContext = context; 424 } 425 426 /** 427 * Get an instance of the SubscriptionManager from the Context. 428 * This invokes {@link android.content.Context#getSystemService 429 * Context.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE)}. 430 * 431 * @param context to use. 432 * @return SubscriptionManager instance 433 */ 434 public static SubscriptionManager from(Context context) { 435 return (SubscriptionManager) context.getSystemService( 436 Context.TELEPHONY_SUBSCRIPTION_SERVICE); 437 } 438 439 /** 440 * Register for changes to the list of active {@link SubscriptionInfo} records or to the 441 * individual records themselves. When a change occurs the onSubscriptionsChanged method of 442 * the listener will be invoked immediately if there has been a notification. 443 * 444 * @param listener an instance of {@link OnSubscriptionsChangedListener} with 445 * onSubscriptionsChanged overridden. 446 */ 447 public void addOnSubscriptionsChangedListener(OnSubscriptionsChangedListener listener) { 448 String pkgForDebug = mContext != null ? mContext.getOpPackageName() : "<unknown>"; 449 if (DBG) { 450 logd("register OnSubscriptionsChangedListener pkgForDebug=" + pkgForDebug 451 + " listener=" + listener); 452 } 453 try { 454 // We use the TelephonyRegistry as it runs in the system and thus is always 455 // available. Where as SubscriptionController could crash and not be available 456 ITelephonyRegistry tr = ITelephonyRegistry.Stub.asInterface(ServiceManager.getService( 457 "telephony.registry")); 458 if (tr != null) { 459 tr.addOnSubscriptionsChangedListener(pkgForDebug, listener.callback); 460 } 461 } catch (RemoteException ex) { 462 // Should not happen 463 } 464 } 465 466 /** 467 * Unregister the {@link OnSubscriptionsChangedListener}. This is not strictly necessary 468 * as the listener will automatically be unregistered if an attempt to invoke the listener 469 * fails. 470 * 471 * @param listener that is to be unregistered. 472 */ 473 public void removeOnSubscriptionsChangedListener(OnSubscriptionsChangedListener listener) { 474 String pkgForDebug = mContext != null ? mContext.getOpPackageName() : "<unknown>"; 475 if (DBG) { 476 logd("unregister OnSubscriptionsChangedListener pkgForDebug=" + pkgForDebug 477 + " listener=" + listener); 478 } 479 try { 480 // We use the TelephonyRegistry as its runs in the system and thus is always 481 // available where as SubscriptionController could crash and not be available 482 ITelephonyRegistry tr = ITelephonyRegistry.Stub.asInterface(ServiceManager.getService( 483 "telephony.registry")); 484 if (tr != null) { 485 tr.removeOnSubscriptionsChangedListener(pkgForDebug, listener.callback); 486 } 487 } catch (RemoteException ex) { 488 // Should not happen 489 } 490 } 491 492 /** 493 * Get the active SubscriptionInfo with the input subId. 494 * 495 * @param subId The unique SubscriptionInfo key in database. 496 * @return SubscriptionInfo, maybe null if its not active. 497 */ 498 public SubscriptionInfo getActiveSubscriptionInfo(int subId) { 499 if (VDBG) logd("[getActiveSubscriptionInfo]+ subId=" + subId); 500 if (!isValidSubscriptionId(subId)) { 501 if (DBG) { 502 logd("[getActiveSubscriptionInfo]- invalid subId"); 503 } 504 return null; 505 } 506 507 SubscriptionInfo subInfo = null; 508 509 try { 510 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); 511 if (iSub != null) { 512 subInfo = iSub.getActiveSubscriptionInfo(subId, mContext.getOpPackageName()); 513 } 514 } catch (RemoteException ex) { 515 // ignore it 516 } 517 518 return subInfo; 519 520 } 521 522 /** 523 * Get the active SubscriptionInfo associated with the iccId 524 * @param iccId the IccId of SIM card 525 * @return SubscriptionInfo, maybe null if its not active 526 * @hide 527 */ 528 public SubscriptionInfo getActiveSubscriptionInfoForIccIndex(String iccId) { 529 if (VDBG) logd("[getActiveSubscriptionInfoForIccIndex]+ iccId=" + iccId); 530 if (iccId == null) { 531 logd("[getActiveSubscriptionInfoForIccIndex]- null iccid"); 532 return null; 533 } 534 535 SubscriptionInfo result = null; 536 537 try { 538 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); 539 if (iSub != null) { 540 result = iSub.getActiveSubscriptionInfoForIccId(iccId, mContext.getOpPackageName()); 541 } 542 } catch (RemoteException ex) { 543 // ignore it 544 } 545 546 return result; 547 } 548 549 /** 550 * Get the active SubscriptionInfo associated with the slotIndex 551 * @param slotIndex the slot which the subscription is inserted 552 * @return SubscriptionInfo, maybe null if its not active 553 */ 554 public SubscriptionInfo getActiveSubscriptionInfoForSimSlotIndex(int slotIndex) { 555 if (VDBG) logd("[getActiveSubscriptionInfoForSimSlotIndex]+ slotIndex=" + slotIndex); 556 if (!isValidSlotIndex(slotIndex)) { 557 logd("[getActiveSubscriptionInfoForSimSlotIndex]- invalid slotIndex"); 558 return null; 559 } 560 561 SubscriptionInfo result = null; 562 563 try { 564 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); 565 if (iSub != null) { 566 result = iSub.getActiveSubscriptionInfoForSimSlotIndex(slotIndex, 567 mContext.getOpPackageName()); 568 } 569 } catch (RemoteException ex) { 570 // ignore it 571 } 572 573 return result; 574 } 575 576 /** 577 * @return List of all SubscriptionInfo records in database, 578 * include those that were inserted before, maybe empty but not null. 579 * @hide 580 */ 581 public List<SubscriptionInfo> getAllSubscriptionInfoList() { 582 if (VDBG) logd("[getAllSubscriptionInfoList]+"); 583 584 List<SubscriptionInfo> result = null; 585 586 try { 587 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); 588 if (iSub != null) { 589 result = iSub.getAllSubInfoList(mContext.getOpPackageName()); 590 } 591 } catch (RemoteException ex) { 592 // ignore it 593 } 594 595 if (result == null) { 596 result = new ArrayList<SubscriptionInfo>(); 597 } 598 return result; 599 } 600 601 /** 602 * Get the SubscriptionInfo(s) of the currently inserted SIM(s). The records will be sorted 603 * by {@link SubscriptionInfo#getSimSlotIndex} then by {@link SubscriptionInfo#getSubscriptionId}. 604 * 605 * @return Sorted list of the currently {@link SubscriptionInfo} records available on the device. 606 * <ul> 607 * <li> 608 * If null is returned the current state is unknown but if a {@link OnSubscriptionsChangedListener} 609 * has been registered {@link OnSubscriptionsChangedListener#onSubscriptionsChanged} will be 610 * invoked in the future. 611 * </li> 612 * <li> 613 * If the list is empty then there are no {@link SubscriptionInfo} records currently available. 614 * </li> 615 * <li> 616 * if the list is non-empty the list is sorted by {@link SubscriptionInfo#getSimSlotIndex} 617 * then by {@link SubscriptionInfo#getSubscriptionId}. 618 * </li> 619 * </ul> 620 */ 621 public List<SubscriptionInfo> getActiveSubscriptionInfoList() { 622 List<SubscriptionInfo> result = null; 623 624 try { 625 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); 626 if (iSub != null) { 627 result = iSub.getActiveSubscriptionInfoList(mContext.getOpPackageName()); 628 } 629 } catch (RemoteException ex) { 630 // ignore it 631 } 632 return result; 633 } 634 635 /** 636 * @return the count of all subscriptions in the database, this includes 637 * all subscriptions that have been seen. 638 * @hide 639 */ 640 public int getAllSubscriptionInfoCount() { 641 if (VDBG) logd("[getAllSubscriptionInfoCount]+"); 642 643 int result = 0; 644 645 try { 646 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); 647 if (iSub != null) { 648 result = iSub.getAllSubInfoCount(mContext.getOpPackageName()); 649 } 650 } catch (RemoteException ex) { 651 // ignore it 652 } 653 654 return result; 655 } 656 657 /** 658 * @return the current number of active subscriptions. There is no guarantee the value 659 * returned by this method will be the same as the length of the list returned by 660 * {@link #getActiveSubscriptionInfoList}. 661 */ 662 public int getActiveSubscriptionInfoCount() { 663 int result = 0; 664 665 try { 666 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); 667 if (iSub != null) { 668 result = iSub.getActiveSubInfoCount(mContext.getOpPackageName()); 669 } 670 } catch (RemoteException ex) { 671 // ignore it 672 } 673 674 return result; 675 } 676 677 /** 678 * @return the maximum number of active subscriptions that will be returned by 679 * {@link #getActiveSubscriptionInfoList} and the value returned by 680 * {@link #getActiveSubscriptionInfoCount}. 681 */ 682 public int getActiveSubscriptionInfoCountMax() { 683 int result = 0; 684 685 try { 686 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); 687 if (iSub != null) { 688 result = iSub.getActiveSubInfoCountMax(); 689 } 690 } catch (RemoteException ex) { 691 // ignore it 692 } 693 694 return result; 695 } 696 697 /** 698 * Add a new SubscriptionInfo to SubscriptionInfo database if needed 699 * @param iccId the IccId of the SIM card 700 * @param slotIndex the slot which the SIM is inserted 701 * @return the URL of the newly created row or the updated row 702 * @hide 703 */ 704 public Uri addSubscriptionInfoRecord(String iccId, int slotIndex) { 705 if (VDBG) logd("[addSubscriptionInfoRecord]+ iccId:" + iccId + " slotIndex:" + slotIndex); 706 if (iccId == null) { 707 logd("[addSubscriptionInfoRecord]- null iccId"); 708 } 709 if (!isValidSlotIndex(slotIndex)) { 710 logd("[addSubscriptionInfoRecord]- invalid slotIndex"); 711 } 712 713 try { 714 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); 715 if (iSub != null) { 716 // FIXME: This returns 1 on success, 0 on error should should we return it? 717 iSub.addSubInfoRecord(iccId, slotIndex); 718 } 719 } catch (RemoteException ex) { 720 // ignore it 721 } 722 723 // FIXME: Always returns null? 724 return null; 725 726 } 727 728 /** 729 * Set SIM icon tint color by simInfo index 730 * @param tint the RGB value of icon tint color of the SIM 731 * @param subId the unique SubInfoRecord index in database 732 * @return the number of records updated 733 * @hide 734 */ 735 public int setIconTint(int tint, int subId) { 736 if (VDBG) logd("[setIconTint]+ tint:" + tint + " subId:" + subId); 737 if (!isValidSubscriptionId(subId)) { 738 logd("[setIconTint]- fail"); 739 return -1; 740 } 741 742 int result = 0; 743 744 try { 745 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); 746 if (iSub != null) { 747 result = iSub.setIconTint(tint, subId); 748 } 749 } catch (RemoteException ex) { 750 // ignore it 751 } 752 753 return result; 754 755 } 756 757 /** 758 * Set display name by simInfo index 759 * @param displayName the display name of SIM card 760 * @param subId the unique SubscriptionInfo index in database 761 * @return the number of records updated 762 * @hide 763 */ 764 public int setDisplayName(String displayName, int subId) { 765 return setDisplayName(displayName, subId, NAME_SOURCE_UNDEFINDED); 766 } 767 768 /** 769 * Set display name by simInfo index with name source 770 * @param displayName the display name of SIM card 771 * @param subId the unique SubscriptionInfo index in database 772 * @param nameSource 0: NAME_SOURCE_DEFAULT_SOURCE, 1: NAME_SOURCE_SIM_SOURCE, 773 * 2: NAME_SOURCE_USER_INPUT, -1 NAME_SOURCE_UNDEFINED 774 * @return the number of records updated or < 0 if invalid subId 775 * @hide 776 */ 777 public int setDisplayName(String displayName, int subId, long nameSource) { 778 if (VDBG) { 779 logd("[setDisplayName]+ displayName:" + displayName + " subId:" + subId 780 + " nameSource:" + nameSource); 781 } 782 if (!isValidSubscriptionId(subId)) { 783 logd("[setDisplayName]- fail"); 784 return -1; 785 } 786 787 int result = 0; 788 789 try { 790 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); 791 if (iSub != null) { 792 result = iSub.setDisplayNameUsingSrc(displayName, subId, nameSource); 793 } 794 } catch (RemoteException ex) { 795 // ignore it 796 } 797 798 return result; 799 800 } 801 802 /** 803 * Set phone number by subId 804 * @param number the phone number of the SIM 805 * @param subId the unique SubscriptionInfo index in database 806 * @return the number of records updated 807 * @hide 808 */ 809 public int setDisplayNumber(String number, int subId) { 810 if (number == null || !isValidSubscriptionId(subId)) { 811 logd("[setDisplayNumber]- fail"); 812 return -1; 813 } 814 815 int result = 0; 816 817 try { 818 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); 819 if (iSub != null) { 820 result = iSub.setDisplayNumber(number, subId); 821 } 822 } catch (RemoteException ex) { 823 // ignore it 824 } 825 826 return result; 827 828 } 829 830 /** 831 * Set data roaming by simInfo index 832 * @param roaming 0:Don't allow data when roaming, 1:Allow data when roaming 833 * @param subId the unique SubscriptionInfo index in database 834 * @return the number of records updated 835 * @hide 836 */ 837 public int setDataRoaming(int roaming, int subId) { 838 if (VDBG) logd("[setDataRoaming]+ roaming:" + roaming + " subId:" + subId); 839 if (roaming < 0 || !isValidSubscriptionId(subId)) { 840 logd("[setDataRoaming]- fail"); 841 return -1; 842 } 843 844 int result = 0; 845 846 try { 847 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); 848 if (iSub != null) { 849 result = iSub.setDataRoaming(roaming, subId); 850 } 851 } catch (RemoteException ex) { 852 // ignore it 853 } 854 855 return result; 856 } 857 858 /** 859 * Get slotIndex associated with the subscription. 860 * @return slotIndex as a positive integer or a negative value if an error either 861 * SIM_NOT_INSERTED or < 0 if an invalid slot index 862 * @hide 863 */ 864 public static int getSlotIndex(int subId) { 865 if (!isValidSubscriptionId(subId)) { 866 if (DBG) { 867 logd("[getSlotIndex]- fail"); 868 } 869 } 870 871 int result = INVALID_SIM_SLOT_INDEX; 872 873 try { 874 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); 875 if (iSub != null) { 876 result = iSub.getSlotIndex(subId); 877 } 878 } catch (RemoteException ex) { 879 // ignore it 880 } 881 882 return result; 883 884 } 885 886 /** @hide */ 887 public static int[] getSubId(int slotIndex) { 888 if (!isValidSlotIndex(slotIndex)) { 889 logd("[getSubId]- fail"); 890 return null; 891 } 892 893 int[] subId = null; 894 895 try { 896 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); 897 if (iSub != null) { 898 subId = iSub.getSubId(slotIndex); 899 } 900 } catch (RemoteException ex) { 901 // ignore it 902 } 903 904 return subId; 905 } 906 907 /** @hide */ 908 public static int getPhoneId(int subId) { 909 if (!isValidSubscriptionId(subId)) { 910 if (DBG) { 911 logd("[getPhoneId]- fail"); 912 } 913 return INVALID_PHONE_INDEX; 914 } 915 916 int result = INVALID_PHONE_INDEX; 917 918 try { 919 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); 920 if (iSub != null) { 921 result = iSub.getPhoneId(subId); 922 } 923 } catch (RemoteException ex) { 924 // ignore it 925 } 926 927 if (VDBG) logd("[getPhoneId]- phoneId=" + result); 928 return result; 929 930 } 931 932 private static void logd(String msg) { 933 Rlog.d(LOG_TAG, msg); 934 } 935 936 /** 937 * Returns the system's default subscription id. 938 * 939 * For a voice capable device, it will return getDefaultVoiceSubscriptionId. 940 * For a data only device, it will return the getDefaultDataSubscriptionId. 941 * May return an INVALID_SUBSCRIPTION_ID on error. 942 * 943 * @return the "system" default subscription id. 944 */ 945 public static int getDefaultSubscriptionId() { 946 int subId = INVALID_SUBSCRIPTION_ID; 947 948 try { 949 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); 950 if (iSub != null) { 951 subId = iSub.getDefaultSubId(); 952 } 953 } catch (RemoteException ex) { 954 // ignore it 955 } 956 957 if (VDBG) logd("getDefaultSubId=" + subId); 958 return subId; 959 } 960 961 /** 962 * Returns the system's default voice subscription id. 963 * 964 * On a data only device or on error, will return INVALID_SUBSCRIPTION_ID. 965 * 966 * @return the default voice subscription Id. 967 */ 968 public static int getDefaultVoiceSubscriptionId() { 969 int subId = INVALID_SUBSCRIPTION_ID; 970 971 try { 972 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); 973 if (iSub != null) { 974 subId = iSub.getDefaultVoiceSubId(); 975 } 976 } catch (RemoteException ex) { 977 // ignore it 978 } 979 980 if (VDBG) logd("getDefaultVoiceSubscriptionId, sub id = " + subId); 981 return subId; 982 } 983 984 /** @hide */ 985 public void setDefaultVoiceSubId(int subId) { 986 if (VDBG) logd("setDefaultVoiceSubId sub id = " + subId); 987 try { 988 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); 989 if (iSub != null) { 990 iSub.setDefaultVoiceSubId(subId); 991 } 992 } catch (RemoteException ex) { 993 // ignore it 994 } 995 } 996 997 /** 998 * Return the SubscriptionInfo for default voice subscription. 999 * 1000 * Will return null on data only devices, or on error. 1001 * 1002 * @return the SubscriptionInfo for the default voice subscription. 1003 * @hide 1004 */ 1005 public SubscriptionInfo getDefaultVoiceSubscriptionInfo() { 1006 return getActiveSubscriptionInfo(getDefaultVoiceSubscriptionId()); 1007 } 1008 1009 /** @hide */ 1010 public static int getDefaultVoicePhoneId() { 1011 return getPhoneId(getDefaultVoiceSubscriptionId()); 1012 } 1013 1014 /** 1015 * Returns the system's default SMS subscription id. 1016 * 1017 * On a data only device or on error, will return INVALID_SUBSCRIPTION_ID. 1018 * 1019 * @return the default SMS subscription Id. 1020 */ 1021 public static int getDefaultSmsSubscriptionId() { 1022 int subId = INVALID_SUBSCRIPTION_ID; 1023 1024 try { 1025 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); 1026 if (iSub != null) { 1027 subId = iSub.getDefaultSmsSubId(); 1028 } 1029 } catch (RemoteException ex) { 1030 // ignore it 1031 } 1032 1033 if (VDBG) logd("getDefaultSmsSubscriptionId, sub id = " + subId); 1034 return subId; 1035 } 1036 1037 /** @hide */ 1038 public void setDefaultSmsSubId(int subId) { 1039 if (VDBG) logd("setDefaultSmsSubId sub id = " + subId); 1040 try { 1041 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); 1042 if (iSub != null) { 1043 iSub.setDefaultSmsSubId(subId); 1044 } 1045 } catch (RemoteException ex) { 1046 // ignore it 1047 } 1048 } 1049 1050 /** 1051 * Return the SubscriptionInfo for default voice subscription. 1052 * 1053 * Will return null on data only devices, or on error. 1054 * 1055 * @return the SubscriptionInfo for the default SMS subscription. 1056 * @hide 1057 */ 1058 public SubscriptionInfo getDefaultSmsSubscriptionInfo() { 1059 return getActiveSubscriptionInfo(getDefaultSmsSubscriptionId()); 1060 } 1061 1062 /** @hide */ 1063 public int getDefaultSmsPhoneId() { 1064 return getPhoneId(getDefaultSmsSubscriptionId()); 1065 } 1066 1067 /** 1068 * Returns the system's default data subscription id. 1069 * 1070 * On a voice only device or on error, will return INVALID_SUBSCRIPTION_ID. 1071 * 1072 * @return the default data subscription Id. 1073 */ 1074 public static int getDefaultDataSubscriptionId() { 1075 int subId = INVALID_SUBSCRIPTION_ID; 1076 1077 try { 1078 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); 1079 if (iSub != null) { 1080 subId = iSub.getDefaultDataSubId(); 1081 } 1082 } catch (RemoteException ex) { 1083 // ignore it 1084 } 1085 1086 if (VDBG) logd("getDefaultDataSubscriptionId, sub id = " + subId); 1087 return subId; 1088 } 1089 1090 /** @hide */ 1091 public void setDefaultDataSubId(int subId) { 1092 if (VDBG) logd("setDataSubscription sub id = " + subId); 1093 try { 1094 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); 1095 if (iSub != null) { 1096 iSub.setDefaultDataSubId(subId); 1097 } 1098 } catch (RemoteException ex) { 1099 // ignore it 1100 } 1101 } 1102 1103 /** 1104 * Return the SubscriptionInfo for default data subscription. 1105 * 1106 * Will return null on voice only devices, or on error. 1107 * 1108 * @return the SubscriptionInfo for the default data subscription. 1109 * @hide 1110 */ 1111 public SubscriptionInfo getDefaultDataSubscriptionInfo() { 1112 return getActiveSubscriptionInfo(getDefaultDataSubscriptionId()); 1113 } 1114 1115 /** @hide */ 1116 public int getDefaultDataPhoneId() { 1117 return getPhoneId(getDefaultDataSubscriptionId()); 1118 } 1119 1120 /** @hide */ 1121 public void clearSubscriptionInfo() { 1122 try { 1123 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); 1124 if (iSub != null) { 1125 iSub.clearSubInfo(); 1126 } 1127 } catch (RemoteException ex) { 1128 // ignore it 1129 } 1130 1131 return; 1132 } 1133 1134 //FIXME this is vulnerable to race conditions 1135 /** @hide */ 1136 public boolean allDefaultsSelected() { 1137 if (!isValidSubscriptionId(getDefaultDataSubscriptionId())) { 1138 return false; 1139 } 1140 if (!isValidSubscriptionId(getDefaultSmsSubscriptionId())) { 1141 return false; 1142 } 1143 if (!isValidSubscriptionId(getDefaultVoiceSubscriptionId())) { 1144 return false; 1145 } 1146 return true; 1147 } 1148 1149 /** 1150 * If a default is set to subscription which is not active, this will reset that default back to 1151 * an invalid subscription id, i.e. < 0. 1152 * @hide 1153 */ 1154 public void clearDefaultsForInactiveSubIds() { 1155 if (VDBG) logd("clearDefaultsForInactiveSubIds"); 1156 try { 1157 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); 1158 if (iSub != null) { 1159 iSub.clearDefaultsForInactiveSubIds(); 1160 } 1161 } catch (RemoteException ex) { 1162 // ignore it 1163 } 1164 } 1165 1166 /** 1167 * @return true if a valid subId else false 1168 * @hide 1169 */ 1170 public static boolean isValidSubscriptionId(int subId) { 1171 return subId > INVALID_SUBSCRIPTION_ID ; 1172 } 1173 1174 /** 1175 * @return true if subId is an usable subId value else false. A 1176 * usable subId means its neither a INVALID_SUBSCRIPTION_ID nor a DEFAULT_SUB_ID. 1177 * @hide 1178 */ 1179 public static boolean isUsableSubIdValue(int subId) { 1180 return subId >= MIN_SUBSCRIPTION_ID_VALUE && subId <= MAX_SUBSCRIPTION_ID_VALUE; 1181 } 1182 1183 /** @hide */ 1184 public static boolean isValidSlotIndex(int slotIndex) { 1185 return slotIndex >= 0 && slotIndex < TelephonyManager.getDefault().getSimCount(); 1186 } 1187 1188 /** @hide */ 1189 public static boolean isValidPhoneId(int phoneId) { 1190 return phoneId >= 0 && phoneId < TelephonyManager.getDefault().getPhoneCount(); 1191 } 1192 1193 /** @hide */ 1194 public static void putPhoneIdAndSubIdExtra(Intent intent, int phoneId) { 1195 int[] subIds = SubscriptionManager.getSubId(phoneId); 1196 if (subIds != null && subIds.length > 0) { 1197 putPhoneIdAndSubIdExtra(intent, phoneId, subIds[0]); 1198 } else { 1199 logd("putPhoneIdAndSubIdExtra: no valid subs"); 1200 } 1201 } 1202 1203 /** @hide */ 1204 public static void putPhoneIdAndSubIdExtra(Intent intent, int phoneId, int subId) { 1205 if (VDBG) logd("putPhoneIdAndSubIdExtra: phoneId=" + phoneId + " subId=" + subId); 1206 intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId); 1207 intent.putExtra(EXTRA_SUBSCRIPTION_INDEX, subId); 1208 intent.putExtra(PhoneConstants.PHONE_KEY, phoneId); 1209 //FIXME this is using phoneId and slotIndex interchangeably 1210 //Eventually, this should be removed as it is not the slot id 1211 intent.putExtra(PhoneConstants.SLOT_KEY, phoneId); 1212 } 1213 1214 /** 1215 * @return the list of subId's that are active, 1216 * is never null but the length maybe 0. 1217 * @hide 1218 */ 1219 public @NonNull int[] getActiveSubscriptionIdList() { 1220 int[] subId = null; 1221 1222 try { 1223 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); 1224 if (iSub != null) { 1225 subId = iSub.getActiveSubIdList(); 1226 } 1227 } catch (RemoteException ex) { 1228 // ignore it 1229 } 1230 1231 if (subId == null) { 1232 subId = new int[0]; 1233 } 1234 1235 return subId; 1236 1237 } 1238 1239 /** 1240 * Returns true if the device is considered roaming on the current 1241 * network for a subscription. 1242 * <p> 1243 * Availability: Only when user registered to a network. 1244 * 1245 * @param subId The subscription ID 1246 * @return true if the network for the subscription is roaming, false otherwise 1247 */ 1248 public boolean isNetworkRoaming(int subId) { 1249 final int phoneId = getPhoneId(subId); 1250 if (phoneId < 0) { 1251 // What else can we do? 1252 return false; 1253 } 1254 return TelephonyManager.getDefault().isNetworkRoaming(subId); 1255 } 1256 1257 /** 1258 * Returns a constant indicating the state of sim for the slot index. 1259 * 1260 * @param slotIndex 1261 * 1262 * {@See TelephonyManager#SIM_STATE_UNKNOWN} 1263 * {@See TelephonyManager#SIM_STATE_ABSENT} 1264 * {@See TelephonyManager#SIM_STATE_PIN_REQUIRED} 1265 * {@See TelephonyManager#SIM_STATE_PUK_REQUIRED} 1266 * {@See TelephonyManager#SIM_STATE_NETWORK_LOCKED} 1267 * {@See TelephonyManager#SIM_STATE_READY} 1268 * {@See TelephonyManager#SIM_STATE_NOT_READY} 1269 * {@See TelephonyManager#SIM_STATE_PERM_DISABLED} 1270 * {@See TelephonyManager#SIM_STATE_CARD_IO_ERROR} 1271 * 1272 * {@hide} 1273 */ 1274 public static int getSimStateForSlotIndex(int slotIndex) { 1275 int simState = TelephonyManager.SIM_STATE_UNKNOWN; 1276 1277 try { 1278 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); 1279 if (iSub != null) { 1280 simState = iSub.getSimStateForSlotIndex(slotIndex); 1281 } 1282 } catch (RemoteException ex) { 1283 } 1284 1285 return simState; 1286 } 1287 1288 /** 1289 * Store properties associated with SubscriptionInfo in database 1290 * @param subId Subscription Id of Subscription 1291 * @param propKey Column name in database associated with SubscriptionInfo 1292 * @param propValue Value to store in DB for particular subId & column name 1293 * @hide 1294 */ 1295 public static void setSubscriptionProperty(int subId, String propKey, String propValue) { 1296 try { 1297 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); 1298 if (iSub != null) { 1299 iSub.setSubscriptionProperty(subId, propKey, propValue); 1300 } 1301 } catch (RemoteException ex) { 1302 // ignore it 1303 } 1304 } 1305 1306 /** 1307 * Store properties associated with SubscriptionInfo in database 1308 * @param subId Subscription Id of Subscription 1309 * @param propKey Column name in SubscriptionInfo database 1310 * @return Value associated with subId and propKey column in database 1311 * @hide 1312 */ 1313 private static String getSubscriptionProperty(int subId, String propKey, 1314 Context context) { 1315 String resultValue = null; 1316 try { 1317 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); 1318 if (iSub != null) { 1319 resultValue = iSub.getSubscriptionProperty(subId, propKey, 1320 context.getOpPackageName()); 1321 } 1322 } catch (RemoteException ex) { 1323 // ignore it 1324 } 1325 return resultValue; 1326 } 1327 1328 /** 1329 * Returns boolean value corresponding to query result. 1330 * @param subId Subscription Id of Subscription 1331 * @param propKey Column name in SubscriptionInfo database 1332 * @param defValue Default boolean value to be returned 1333 * @return boolean result value to be returned 1334 * @hide 1335 */ 1336 public static boolean getBooleanSubscriptionProperty(int subId, String propKey, 1337 boolean defValue, Context context) { 1338 String result = getSubscriptionProperty(subId, propKey, context); 1339 if (result != null) { 1340 try { 1341 return Integer.parseInt(result) == 1; 1342 } catch (NumberFormatException err) { 1343 logd("getBooleanSubscriptionProperty NumberFormat exception"); 1344 } 1345 } 1346 return defValue; 1347 } 1348 1349 /** 1350 * Returns integer value corresponding to query result. 1351 * @param subId Subscription Id of Subscription 1352 * @param propKey Column name in SubscriptionInfo database 1353 * @param defValue Default integer value to be returned 1354 * @return integer result value to be returned 1355 * @hide 1356 */ 1357 public static int getIntegerSubscriptionProperty(int subId, String propKey, int defValue, 1358 Context context) { 1359 String result = getSubscriptionProperty(subId, propKey, context); 1360 if (result != null) { 1361 try { 1362 return Integer.parseInt(result); 1363 } catch (NumberFormatException err) { 1364 logd("getBooleanSubscriptionProperty NumberFormat exception"); 1365 } 1366 } 1367 return defValue; 1368 } 1369 1370 /** 1371 * Returns the resources associated with Subscription. 1372 * @param context Context object 1373 * @param subId Subscription Id of Subscription who's resources are required 1374 * @return Resources associated with Subscription. 1375 * @hide 1376 */ 1377 public static Resources getResourcesForSubId(Context context, int subId) { 1378 final SubscriptionInfo subInfo = 1379 SubscriptionManager.from(context).getActiveSubscriptionInfo(subId); 1380 1381 Configuration config = context.getResources().getConfiguration(); 1382 Configuration newConfig = new Configuration(); 1383 newConfig.setTo(config); 1384 if (subInfo != null) { 1385 newConfig.mcc = subInfo.getMcc(); 1386 newConfig.mnc = subInfo.getMnc(); 1387 if (newConfig.mnc == 0) newConfig.mnc = Configuration.MNC_ZERO; 1388 } 1389 DisplayMetrics metrics = context.getResources().getDisplayMetrics(); 1390 DisplayMetrics newMetrics = new DisplayMetrics(); 1391 newMetrics.setTo(metrics); 1392 return new Resources(context.getResources().getAssets(), newMetrics, newConfig); 1393 } 1394 1395 /** 1396 * @return true if the sub ID is active. i.e. The sub ID corresponds to a known subscription 1397 * and the SIM providing the subscription is present in a slot and in "LOADED" state. 1398 * @hide 1399 */ 1400 public boolean isActiveSubId(int subId) { 1401 try { 1402 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); 1403 if (iSub != null) { 1404 return iSub.isActiveSubId(subId); 1405 } 1406 } catch (RemoteException ex) { 1407 } 1408 return false; 1409 } 1410} 1411