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