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