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