SubscriptionManager.java revision 278b8f950948435fb08db0a12313e2ea704fa637
1/* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package android.telephony; 18 19import android.annotation.NonNull; 20import android.annotation.SdkConstant; 21import android.annotation.SdkConstant.SdkConstantType; 22import android.content.Context; 23import android.content.Intent; 24import android.net.Uri; 25import android.telephony.Rlog; 26import android.os.Handler; 27import android.os.Message; 28import android.os.ServiceManager; 29import android.os.RemoteException; 30 31import com.android.internal.telephony.ISub; 32import com.android.internal.telephony.IOnSubscriptionsChangedListener; 33import com.android.internal.telephony.ITelephonyRegistry; 34import com.android.internal.telephony.PhoneConstants; 35import java.util.ArrayList; 36import java.util.List; 37 38/** 39 * SubscriptionManager is the application interface to SubscriptionController 40 * and provides information about the current Telephony Subscriptions. 41 * * <p> 42 * You do not instantiate this class directly; instead, you retrieve 43 * a reference to an instance through {@link #from}. 44 * <p> 45 * All SDK public methods require android.Manifest.permission.READ_PHONE_STATE. 46 */ 47public class SubscriptionManager { 48 private static final String LOG_TAG = "SubscriptionManager"; 49 private static final boolean DBG = false; 50 private static final boolean VDBG = false; 51 52 /** An invalid subscription identifier */ 53 /** @hide */ 54 public static final int INVALID_SUBSCRIPTION_ID = -1; 55 56 /** Base value for Dummy SUBSCRIPTION_ID's. */ 57 /** FIXME: Remove DummySubId's, but for now have them map just below INVALID_SUBSCRIPTION_ID 58 /** @hide */ 59 public static final int DUMMY_SUBSCRIPTION_ID_BASE = INVALID_SUBSCRIPTION_ID - 1; 60 61 /** An invalid phone identifier */ 62 /** @hide */ 63 public static final int INVALID_PHONE_INDEX = -1; 64 65 /** An invalid slot identifier */ 66 /** @hide */ 67 public static final int INVALID_SIM_SLOT_INDEX = -1; 68 69 /** Indicates the caller wants the default sub id. */ 70 /** @hide */ 71 public static final int DEFAULT_SUBSCRIPTION_ID = Integer.MAX_VALUE; 72 73 /** 74 * Indicates the caller wants the default phone id. 75 * Used in SubscriptionController and PhoneBase but do we really need it??? 76 * @hide 77 */ 78 public static final int DEFAULT_PHONE_INDEX = Integer.MAX_VALUE; 79 80 /** Indicates the caller wants the default slot id. NOT used remove? */ 81 /** @hide */ 82 public static final int DEFAULT_SIM_SLOT_INDEX = Integer.MAX_VALUE; 83 84 /** Minimum possible subid that represents a subscription */ 85 /** @hide */ 86 public static final int MIN_SUBSCRIPTION_ID_VALUE = 0; 87 88 /** Maximum possible subid that represents a subscription */ 89 /** @hide */ 90 public static final int MAX_SUBSCRIPTION_ID_VALUE = DEFAULT_SUBSCRIPTION_ID - 1; 91 92 /** @hide */ 93 public static final Uri CONTENT_URI = Uri.parse("content://telephony/siminfo"); 94 95 /** 96 * TelephonyProvider unique key column name is the subscription id. 97 * <P>Type: TEXT (String)</P> 98 */ 99 /** @hide */ 100 public static final String UNIQUE_KEY_SUBSCRIPTION_ID = "_id"; 101 102 /** 103 * TelephonyProvider column name for SIM ICC Identifier 104 * <P>Type: TEXT (String)</P> 105 */ 106 /** @hide */ 107 public static final String ICC_ID = "icc_id"; 108 109 /** 110 * TelephonyProvider column name for user SIM_SlOT_INDEX 111 * <P>Type: INTEGER (int)</P> 112 */ 113 /** @hide */ 114 public static final String SIM_SLOT_INDEX = "sim_id"; 115 116 /** SIM is not inserted */ 117 /** @hide */ 118 public static final int SIM_NOT_INSERTED = -1; 119 120 /** 121 * TelephonyProvider column name for user displayed name. 122 * <P>Type: TEXT (String)</P> 123 */ 124 /** @hide */ 125 public static final String DISPLAY_NAME = "display_name"; 126 127 /** 128 * TelephonyProvider column name for the service provider name for the SIM. 129 * <P>Type: TEXT (String)</P> 130 */ 131 /** @hide */ 132 public static final String CARRIER_NAME = "carrier_name"; 133 134 /** 135 * Default name resource 136 * @hide 137 */ 138 public static final int DEFAULT_NAME_RES = com.android.internal.R.string.unknownName; 139 140 /** 141 * TelephonyProvider column name for source of the user displayed name. 142 * <P>Type: INT (int)</P> with one of the NAME_SOURCE_XXXX values below 143 * 144 * @hide 145 */ 146 public static final String NAME_SOURCE = "name_source"; 147 148 /** 149 * The name_source is undefined 150 * @hide 151 */ 152 public static final int NAME_SOURCE_UNDEFINDED = -1; 153 154 /** 155 * The name_source is the default 156 * @hide 157 */ 158 public static final int NAME_SOURCE_DEFAULT_SOURCE = 0; 159 160 /** 161 * The name_source is from the SIM 162 * @hide 163 */ 164 public static final int NAME_SOURCE_SIM_SOURCE = 1; 165 166 /** 167 * The name_source is from the user 168 * @hide 169 */ 170 public static final int NAME_SOURCE_USER_INPUT = 2; 171 172 /** 173 * TelephonyProvider column name for the color of a SIM. 174 * <P>Type: INTEGER (int)</P> 175 */ 176 /** @hide */ 177 public static final String COLOR = "color"; 178 179 /** @hide */ 180 public static final int COLOR_1 = 0; 181 182 /** @hide */ 183 public static final int COLOR_2 = 1; 184 185 /** @hide */ 186 public static final int COLOR_3 = 2; 187 188 /** @hide */ 189 public static final int COLOR_4 = 3; 190 191 /** @hide */ 192 public static final int COLOR_DEFAULT = COLOR_1; 193 194 /** 195 * TelephonyProvider column name for the phone number of a SIM. 196 * <P>Type: TEXT (String)</P> 197 */ 198 /** @hide */ 199 public static final String NUMBER = "number"; 200 201 /** 202 * TelephonyProvider column name for the number display format of a SIM. 203 * <P>Type: INTEGER (int)</P> 204 */ 205 /** @hide */ 206 public static final String DISPLAY_NUMBER_FORMAT = "display_number_format"; 207 208 /** @hide */ 209 public static final int DISPLAY_NUMBER_NONE = 0; 210 211 /** @hide */ 212 public static final int DISPLAY_NUMBER_FIRST = 1; 213 214 /** @hide */ 215 public static final int DISPLAY_NUMBER_LAST = 2; 216 217 /** @hide */ 218 public static final int DISPLAY_NUMBER_DEFAULT = DISPLAY_NUMBER_FIRST; 219 220 /** 221 * TelephonyProvider column name for permission for data roaming of a SIM. 222 * <P>Type: INTEGER (int)</P> 223 */ 224 /** @hide */ 225 public static final String DATA_ROAMING = "data_roaming"; 226 227 /** Indicates that data roaming is enabled for a subscription */ 228 public static final int DATA_ROAMING_ENABLE = 1; 229 230 /** Indicates that data roaming is disabled for a subscription */ 231 public static final int DATA_ROAMING_DISABLE = 0; 232 233 /** @hide */ 234 public static final int DATA_ROAMING_DEFAULT = DATA_ROAMING_DISABLE; 235 236 /** 237 * TelephonyProvider column name for the MCC associated with a SIM. 238 * <P>Type: INTEGER (int)</P> 239 * @hide 240 */ 241 public static final String MCC = "mcc"; 242 243 /** 244 * TelephonyProvider column name for the MNC associated with a SIM. 245 * <P>Type: INTEGER (int)</P> 246 * @hide 247 */ 248 public static final String MNC = "mnc"; 249 250 /** 251 * Broadcast Action: The user has changed one of the default subs related to 252 * data, phone calls, or sms</p> 253 * 254 * TODO: Change to a listener 255 * @hide 256 */ 257 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 258 public static final String SUB_DEFAULT_CHANGED_ACTION = 259 "android.intent.action.SUB_DEFAULT_CHANGED"; 260 261 private final Context mContext; 262 263 /** 264 * A listener class for monitoring changes to {@link SubscriptionInfo} records. 265 * <p> 266 * Override the onSubscriptionsChanged method in the object that extends this 267 * class and pass it to {@link #addOnSubscriptionsChangedListener(OnSubscriptionsChangedListener)} 268 * to register your listener and to unregister invoke 269 * {@link #removeOnSubscriptionsChangedListener(OnSubscriptionsChangedListener)} 270 * <p> 271 * Permissions android.Manifest.permission.READ_PHONE_STATE is required 272 * for #onSubscriptionsChanged to be invoked. 273 */ 274 public static class OnSubscriptionsChangedListener { 275 private final Handler mHandler = new Handler() { 276 @Override 277 public void handleMessage(Message msg) { 278 if (DBG) { 279 log("handleMessage: invoke the overriden onSubscriptionsChanged()"); 280 } 281 OnSubscriptionsChangedListener.this.onSubscriptionsChanged(); 282 } 283 }; 284 285 /** 286 * Callback invoked when there is any change to any SubscriptionInfo. Typically 287 * this method would invoke {@link #getActiveSubscriptionInfoList} 288 */ 289 public void onSubscriptionsChanged() { 290 if (DBG) log("onSubscriptionsChanged: NOT OVERRIDDEN"); 291 } 292 293 /** 294 * The callback methods need to be called on the handler thread where 295 * this object was created. If the binder did that for us it'd be nice. 296 */ 297 IOnSubscriptionsChangedListener callback = new IOnSubscriptionsChangedListener.Stub() { 298 @Override 299 public void onSubscriptionsChanged() { 300 if (DBG) log("callback: received, sendEmptyMessage(0) to handler"); 301 mHandler.sendEmptyMessage(0); 302 } 303 }; 304 305 private void log(String s) { 306 Rlog.d(LOG_TAG, s); 307 } 308 } 309 310 /** @hide */ 311 public SubscriptionManager(Context context) { 312 if (DBG) logd("SubscriptionManager created"); 313 mContext = context; 314 } 315 316 /** 317 * Get an instance of the SubscriptionManager from the Context. 318 * This invokes {@link android.content.Context#getSystemService 319 * Context.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE)}. 320 * 321 * @param context to use. 322 * @return SubscriptionManager instance 323 */ 324 public static SubscriptionManager from(Context context) { 325 return (SubscriptionManager) context.getSystemService( 326 Context.TELEPHONY_SUBSCRIPTION_SERVICE); 327 } 328 329 /** 330 * Register for changes to the list of active {@link SubscriptionInfo} records or to the 331 * individual records themselves. When a change occurs the onSubscriptionsChanged method of 332 * the listener will be invoked immediately if there has been a notification. 333 * 334 * @param listener an instance of {@link OnSubscriptionsChangedListener} with 335 * onSubscriptionsChanged overridden. 336 */ 337 public void addOnSubscriptionsChangedListener(OnSubscriptionsChangedListener listener) { 338 String pkgForDebug = mContext != null ? mContext.getOpPackageName() : "<unknown>"; 339 if (DBG) { 340 logd("register OnSubscriptionsChangedListener pkgForDebug=" + pkgForDebug 341 + " listener=" + listener); 342 } 343 try { 344 // We use the TelephonyRegistry as it runs in the system and thus is always 345 // available. Where as SubscriptionController could crash and not be available 346 ITelephonyRegistry tr = ITelephonyRegistry.Stub.asInterface(ServiceManager.getService( 347 "telephony.registry")); 348 if (tr != null) { 349 tr.addOnSubscriptionsChangedListener(pkgForDebug, listener.callback); 350 } 351 } catch (RemoteException ex) { 352 // Should not happen 353 } 354 } 355 356 /** 357 * Unregister the {@link OnSubscriptionsChangedListener}. This is not strictly necessary 358 * as the listener will automatically be unregistered if an attempt to invoke the listener 359 * fails. 360 * 361 * @param listener that is to be unregistered. 362 */ 363 public void removeOnSubscriptionsChangedListener(OnSubscriptionsChangedListener listener) { 364 String pkgForDebug = mContext != null ? mContext.getOpPackageName() : "<unknown>"; 365 if (DBG) { 366 logd("unregister OnSubscriptionsChangedListener pkgForDebug=" + pkgForDebug 367 + " listener=" + listener); 368 } 369 try { 370 // We use the TelephonyRegistry as its runs in the system and thus is always 371 // available where as SubscriptionController could crash and not be available 372 ITelephonyRegistry tr = ITelephonyRegistry.Stub.asInterface(ServiceManager.getService( 373 "telephony.registry")); 374 if (tr != null) { 375 tr.removeOnSubscriptionsChangedListener(pkgForDebug, listener.callback); 376 } 377 } catch (RemoteException ex) { 378 // Should not happen 379 } 380 } 381 382 /** 383 * Get the active SubscriptionInfo with the subId key 384 * @param subId The unique SubscriptionInfo key in database 385 * @return SubscriptionInfo, maybe null if its not active. 386 */ 387 public SubscriptionInfo getActiveSubscriptionInfo(int subId) { 388 if (VDBG) logd("[getActiveSubscriptionInfo]+ subId=" + subId); 389 if (!isValidSubscriptionId(subId)) { 390 if (DBG) { 391 logd("[getActiveSubscriptionInfo]- invalid subId"); 392 } 393 return null; 394 } 395 396 SubscriptionInfo subInfo = null; 397 398 try { 399 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); 400 if (iSub != null) { 401 subInfo = iSub.getActiveSubscriptionInfo(subId, mContext.getOpPackageName()); 402 } 403 } catch (RemoteException ex) { 404 // ignore it 405 } 406 407 return subInfo; 408 409 } 410 411 /** 412 * Get the active SubscriptionInfo associated with the iccId 413 * @param iccId the IccId of SIM card 414 * @return SubscriptionInfo, maybe null if its not active 415 * @hide 416 */ 417 public SubscriptionInfo getActiveSubscriptionInfoForIccIndex(String iccId) { 418 if (VDBG) logd("[getActiveSubscriptionInfoForIccIndex]+ iccId=" + iccId); 419 if (iccId == null) { 420 logd("[getActiveSubscriptionInfoForIccIndex]- null iccid"); 421 return null; 422 } 423 424 SubscriptionInfo result = null; 425 426 try { 427 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); 428 if (iSub != null) { 429 result = iSub.getActiveSubscriptionInfoForIccId(iccId, mContext.getOpPackageName()); 430 } 431 } catch (RemoteException ex) { 432 // ignore it 433 } 434 435 return result; 436 } 437 438 /** 439 * Get the active SubscriptionInfo associated with the slotIdx 440 * @param slotIdx the slot which the subscription is inserted 441 * @return SubscriptionInfo, maybe null if its not active 442 */ 443 public SubscriptionInfo getActiveSubscriptionInfoForSimSlotIndex(int slotIdx) { 444 if (VDBG) logd("[getActiveSubscriptionInfoForSimSlotIndex]+ slotIdx=" + slotIdx); 445 if (!isValidSlotId(slotIdx)) { 446 logd("[getActiveSubscriptionInfoForSimSlotIndex]- invalid slotIdx"); 447 return null; 448 } 449 450 SubscriptionInfo result = null; 451 452 try { 453 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); 454 if (iSub != null) { 455 result = iSub.getActiveSubscriptionInfoForSimSlotIndex(slotIdx, 456 mContext.getOpPackageName()); 457 } 458 } catch (RemoteException ex) { 459 // ignore it 460 } 461 462 return result; 463 } 464 465 /** 466 * @return List of all SubscriptionInfo records in database, 467 * include those that were inserted before, maybe empty but not null. 468 * @hide 469 */ 470 public List<SubscriptionInfo> getAllSubscriptionInfoList() { 471 if (VDBG) logd("[getAllSubscriptionInfoList]+"); 472 473 List<SubscriptionInfo> result = null; 474 475 try { 476 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); 477 if (iSub != null) { 478 result = iSub.getAllSubInfoList(mContext.getOpPackageName()); 479 } 480 } catch (RemoteException ex) { 481 // ignore it 482 } 483 484 if (result == null) { 485 result = new ArrayList<SubscriptionInfo>(); 486 } 487 return result; 488 } 489 490 /** 491 * Get the SubscriptionInfo(s) of the currently inserted SIM(s). The records will be sorted 492 * by {@link SubscriptionInfo#getSimSlotIndex} then by {@link SubscriptionInfo#getSubscriptionId}. 493 * 494 * @return Sorted list of the currently {@link SubscriptionInfo} records available on the device. 495 * <ul> 496 * <li> 497 * If null is returned the current state is unknown but if a {@link OnSubscriptionsChangedListener} 498 * has been registered {@link OnSubscriptionsChangedListener#onSubscriptionsChanged} will be 499 * invoked in the future. 500 * </li> 501 * <li> 502 * If the list is empty then there are no {@link SubscriptionInfo} records currently available. 503 * </li> 504 * <li> 505 * if the list is non-empty the list is sorted by {@link SubscriptionInfo#getSimSlotIndex} 506 * then by {@link SubscriptionInfo#getSubscriptionId}. 507 * </li> 508 * </ul> 509 */ 510 public List<SubscriptionInfo> getActiveSubscriptionInfoList() { 511 List<SubscriptionInfo> result = null; 512 513 try { 514 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); 515 if (iSub != null) { 516 result = iSub.getActiveSubscriptionInfoList(mContext.getOpPackageName()); 517 } 518 } catch (RemoteException ex) { 519 // ignore it 520 } 521 return result; 522 } 523 524 /** 525 * @return the count of all subscriptions in the database, this includes 526 * all subscriptions that have been seen. 527 * @hide 528 */ 529 public int getAllSubscriptionInfoCount() { 530 if (VDBG) logd("[getAllSubscriptionInfoCount]+"); 531 532 int result = 0; 533 534 try { 535 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); 536 if (iSub != null) { 537 result = iSub.getAllSubInfoCount(mContext.getOpPackageName()); 538 } 539 } catch (RemoteException ex) { 540 // ignore it 541 } 542 543 return result; 544 } 545 546 /** 547 * @return the current number of active subscriptions. There is no guarantee the value 548 * returned by this method will be the same as the length of the list returned by 549 * {@link #getActiveSubscriptionInfoList}. 550 */ 551 public int getActiveSubscriptionInfoCount() { 552 int result = 0; 553 554 try { 555 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); 556 if (iSub != null) { 557 result = iSub.getActiveSubInfoCount(mContext.getOpPackageName()); 558 } 559 } catch (RemoteException ex) { 560 // ignore it 561 } 562 563 return result; 564 } 565 566 /** 567 * @return the maximum number of active subscriptions that will be returned by 568 * {@link #getActiveSubscriptionInfoList} and the value returned by 569 * {@link #getActiveSubscriptionInfoCount}. 570 */ 571 public int getActiveSubscriptionInfoCountMax() { 572 int result = 0; 573 574 try { 575 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); 576 if (iSub != null) { 577 result = iSub.getActiveSubInfoCountMax(); 578 } 579 } catch (RemoteException ex) { 580 // ignore it 581 } 582 583 return result; 584 } 585 586 /** 587 * Add a new SubscriptionInfo to SubscriptionInfo database if needed 588 * @param iccId the IccId of the SIM card 589 * @param slotId the slot which the SIM is inserted 590 * @return the URL of the newly created row or the updated row 591 * @hide 592 */ 593 public Uri addSubscriptionInfoRecord(String iccId, int slotId) { 594 if (VDBG) logd("[addSubscriptionInfoRecord]+ iccId:" + iccId + " slotId:" + slotId); 595 if (iccId == null) { 596 logd("[addSubscriptionInfoRecord]- null iccId"); 597 } 598 if (!isValidSlotId(slotId)) { 599 logd("[addSubscriptionInfoRecord]- invalid slotId"); 600 } 601 602 try { 603 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); 604 if (iSub != null) { 605 // FIXME: This returns 1 on success, 0 on error should should we return it? 606 iSub.addSubInfoRecord(iccId, slotId); 607 } 608 } catch (RemoteException ex) { 609 // ignore it 610 } 611 612 // FIXME: Always returns null? 613 return null; 614 615 } 616 617 /** 618 * Set SIM icon tint color by simInfo index 619 * @param tint the RGB value of icon tint color of the SIM 620 * @param subId the unique SubInfoRecord index in database 621 * @return the number of records updated 622 * @hide 623 */ 624 public int setIconTint(int tint, int subId) { 625 if (VDBG) logd("[setIconTint]+ tint:" + tint + " subId:" + subId); 626 if (!isValidSubscriptionId(subId)) { 627 logd("[setIconTint]- fail"); 628 return -1; 629 } 630 631 int result = 0; 632 633 try { 634 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); 635 if (iSub != null) { 636 result = iSub.setIconTint(tint, subId); 637 } 638 } catch (RemoteException ex) { 639 // ignore it 640 } 641 642 return result; 643 644 } 645 646 /** 647 * Set display name by simInfo index 648 * @param displayName the display name of SIM card 649 * @param subId the unique SubscriptionInfo index in database 650 * @return the number of records updated 651 * @hide 652 */ 653 public int setDisplayName(String displayName, int subId) { 654 return setDisplayName(displayName, subId, NAME_SOURCE_UNDEFINDED); 655 } 656 657 /** 658 * Set display name by simInfo index with name source 659 * @param displayName the display name of SIM card 660 * @param subId the unique SubscriptionInfo index in database 661 * @param nameSource 0: NAME_SOURCE_DEFAULT_SOURCE, 1: NAME_SOURCE_SIM_SOURCE, 662 * 2: NAME_SOURCE_USER_INPUT, -1 NAME_SOURCE_UNDEFINED 663 * @return the number of records updated or < 0 if invalid subId 664 * @hide 665 */ 666 public int setDisplayName(String displayName, int subId, long nameSource) { 667 if (VDBG) { 668 logd("[setDisplayName]+ displayName:" + displayName + " subId:" + subId 669 + " nameSource:" + nameSource); 670 } 671 if (!isValidSubscriptionId(subId)) { 672 logd("[setDisplayName]- fail"); 673 return -1; 674 } 675 676 int result = 0; 677 678 try { 679 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); 680 if (iSub != null) { 681 result = iSub.setDisplayNameUsingSrc(displayName, subId, nameSource); 682 } 683 } catch (RemoteException ex) { 684 // ignore it 685 } 686 687 return result; 688 689 } 690 691 /** 692 * Set phone number by subId 693 * @param number the phone number of the SIM 694 * @param subId the unique SubscriptionInfo index in database 695 * @return the number of records updated 696 * @hide 697 */ 698 public int setDisplayNumber(String number, int subId) { 699 if (number == null || !isValidSubscriptionId(subId)) { 700 logd("[setDisplayNumber]- fail"); 701 return -1; 702 } 703 704 int result = 0; 705 706 try { 707 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); 708 if (iSub != null) { 709 result = iSub.setDisplayNumber(number, subId); 710 } 711 } catch (RemoteException ex) { 712 // ignore it 713 } 714 715 return result; 716 717 } 718 719 /** 720 * Set data roaming by simInfo index 721 * @param roaming 0:Don't allow data when roaming, 1:Allow data when roaming 722 * @param subId the unique SubscriptionInfo index in database 723 * @return the number of records updated 724 * @hide 725 */ 726 public int setDataRoaming(int roaming, int subId) { 727 if (VDBG) logd("[setDataRoaming]+ roaming:" + roaming + " subId:" + subId); 728 if (roaming < 0 || !isValidSubscriptionId(subId)) { 729 logd("[setDataRoaming]- fail"); 730 return -1; 731 } 732 733 int result = 0; 734 735 try { 736 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); 737 if (iSub != null) { 738 result = iSub.setDataRoaming(roaming, subId); 739 } 740 } catch (RemoteException ex) { 741 // ignore it 742 } 743 744 return result; 745 } 746 747 /** 748 * Get slotId associated with the subscription. 749 * @return slotId as a positive integer or a negative value if an error either 750 * SIM_NOT_INSERTED or < 0 if an invalid slot index 751 * @hide 752 */ 753 public static int getSlotId(int subId) { 754 if (!isValidSubscriptionId(subId)) { 755 if (DBG) { 756 logd("[getSlotId]- fail"); 757 } 758 } 759 760 int result = INVALID_SIM_SLOT_INDEX; 761 762 try { 763 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); 764 if (iSub != null) { 765 result = iSub.getSlotId(subId); 766 } 767 } catch (RemoteException ex) { 768 // ignore it 769 } 770 771 return result; 772 773 } 774 775 /** @hide */ 776 public static int[] getSubId(int slotId) { 777 if (!isValidSlotId(slotId)) { 778 logd("[getSubId]- fail"); 779 return null; 780 } 781 782 int[] subId = null; 783 784 try { 785 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); 786 if (iSub != null) { 787 subId = iSub.getSubId(slotId); 788 } 789 } catch (RemoteException ex) { 790 // ignore it 791 } 792 793 return subId; 794 } 795 796 /** @hide */ 797 public static int getPhoneId(int subId) { 798 if (!isValidSubscriptionId(subId)) { 799 if (DBG) { 800 logd("[getPhoneId]- fail"); 801 } 802 return INVALID_PHONE_INDEX; 803 } 804 805 int result = INVALID_PHONE_INDEX; 806 807 try { 808 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); 809 if (iSub != null) { 810 result = iSub.getPhoneId(subId); 811 } 812 } catch (RemoteException ex) { 813 // ignore it 814 } 815 816 if (VDBG) logd("[getPhoneId]- phoneId=" + result); 817 return result; 818 819 } 820 821 private static void logd(String msg) { 822 Rlog.d(LOG_TAG, msg); 823 } 824 825 /** 826 * @return the "system" defaultSubId on a voice capable device this 827 * will be getDefaultVoiceSubId() and on a data only device it will be 828 * getDefaultDataSubId(). 829 * @hide 830 */ 831 public static int getDefaultSubId() { 832 int subId = INVALID_SUBSCRIPTION_ID; 833 834 try { 835 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); 836 if (iSub != null) { 837 subId = iSub.getDefaultSubId(); 838 } 839 } catch (RemoteException ex) { 840 // ignore it 841 } 842 843 if (VDBG) logd("getDefaultSubId=" + subId); 844 return subId; 845 } 846 847 /** @hide */ 848 public static int getDefaultVoiceSubId() { 849 int subId = INVALID_SUBSCRIPTION_ID; 850 851 try { 852 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); 853 if (iSub != null) { 854 subId = iSub.getDefaultVoiceSubId(); 855 } 856 } catch (RemoteException ex) { 857 // ignore it 858 } 859 860 if (VDBG) logd("getDefaultVoiceSubId, sub id = " + subId); 861 return subId; 862 } 863 864 /** @hide */ 865 public void setDefaultVoiceSubId(int subId) { 866 if (VDBG) logd("setDefaultVoiceSubId sub id = " + subId); 867 try { 868 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); 869 if (iSub != null) { 870 iSub.setDefaultVoiceSubId(subId); 871 } 872 } catch (RemoteException ex) { 873 // ignore it 874 } 875 } 876 877 /** @hide */ 878 public SubscriptionInfo getDefaultVoiceSubscriptionInfo() { 879 return getActiveSubscriptionInfo(getDefaultVoiceSubId()); 880 } 881 882 /** @hide */ 883 public static int getDefaultVoicePhoneId() { 884 return getPhoneId(getDefaultVoiceSubId()); 885 } 886 887 /** 888 * @return subId of the DefaultSms subscription or 889 * a value < 0 if an error. 890 * 891 * @hide 892 */ 893 public static int getDefaultSmsSubId() { 894 int subId = INVALID_SUBSCRIPTION_ID; 895 896 try { 897 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); 898 if (iSub != null) { 899 subId = iSub.getDefaultSmsSubId(); 900 } 901 } catch (RemoteException ex) { 902 // ignore it 903 } 904 905 if (VDBG) logd("getDefaultSmsSubId, sub id = " + subId); 906 return subId; 907 } 908 909 /** @hide */ 910 public void setDefaultSmsSubId(int subId) { 911 if (VDBG) logd("setDefaultSmsSubId sub id = " + subId); 912 try { 913 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); 914 if (iSub != null) { 915 iSub.setDefaultSmsSubId(subId); 916 } 917 } catch (RemoteException ex) { 918 // ignore it 919 } 920 } 921 922 /** @hide */ 923 public SubscriptionInfo getDefaultSmsSubscriptionInfo() { 924 return getActiveSubscriptionInfo(getDefaultSmsSubId()); 925 } 926 927 /** @hide */ 928 public int getDefaultSmsPhoneId() { 929 return getPhoneId(getDefaultSmsSubId()); 930 } 931 932 /** @hide */ 933 public static int getDefaultDataSubId() { 934 int subId = INVALID_SUBSCRIPTION_ID; 935 936 try { 937 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); 938 if (iSub != null) { 939 subId = iSub.getDefaultDataSubId(); 940 } 941 } catch (RemoteException ex) { 942 // ignore it 943 } 944 945 if (VDBG) logd("getDefaultDataSubId, sub id = " + subId); 946 return subId; 947 } 948 949 /** @hide */ 950 public void setDefaultDataSubId(int subId) { 951 if (VDBG) logd("setDataSubscription sub id = " + subId); 952 try { 953 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); 954 if (iSub != null) { 955 iSub.setDefaultDataSubId(subId); 956 } 957 } catch (RemoteException ex) { 958 // ignore it 959 } 960 } 961 962 /** @hide */ 963 public SubscriptionInfo getDefaultDataSubscriptionInfo() { 964 return getActiveSubscriptionInfo(getDefaultDataSubId()); 965 } 966 967 /** @hide */ 968 public int getDefaultDataPhoneId() { 969 return getPhoneId(getDefaultDataSubId()); 970 } 971 972 /** @hide */ 973 public void clearSubscriptionInfo() { 974 try { 975 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); 976 if (iSub != null) { 977 iSub.clearSubInfo(); 978 } 979 } catch (RemoteException ex) { 980 // ignore it 981 } 982 983 return; 984 } 985 986 //FIXME this is vulnerable to race conditions 987 /** @hide */ 988 public boolean allDefaultsSelected() { 989 if (!isValidSubscriptionId(getDefaultDataSubId())) { 990 return false; 991 } 992 if (!isValidSubscriptionId(getDefaultSmsSubId())) { 993 return false; 994 } 995 if (!isValidSubscriptionId(getDefaultVoiceSubId())) { 996 return false; 997 } 998 return true; 999 } 1000 1001 /** 1002 * If a default is set to subscription which is not active, this will reset that default back to 1003 * an invalid subscription id, i.e. < 0. 1004 * @hide 1005 */ 1006 public void clearDefaultsForInactiveSubIds() { 1007 if (VDBG) logd("clearDefaultsForInactiveSubIds"); 1008 try { 1009 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); 1010 if (iSub != null) { 1011 iSub.clearDefaultsForInactiveSubIds(); 1012 } 1013 } catch (RemoteException ex) { 1014 // ignore it 1015 } 1016 } 1017 1018 /** 1019 * @return true if a valid subId else false 1020 * @hide 1021 */ 1022 public static boolean isValidSubscriptionId(int subId) { 1023 return subId > INVALID_SUBSCRIPTION_ID ; 1024 } 1025 1026 /** 1027 * @return true if subId is an usable subId value else false. A 1028 * usable subId means its neither a INVALID_SUBSCRIPTION_ID nor a DEFAULT_SUB_ID. 1029 * @hide 1030 */ 1031 public static boolean isUsableSubIdValue(int subId) { 1032 return subId >= MIN_SUBSCRIPTION_ID_VALUE && subId <= MAX_SUBSCRIPTION_ID_VALUE; 1033 } 1034 1035 /** @hide */ 1036 public static boolean isValidSlotId(int slotId) { 1037 return slotId >= 0 && slotId < TelephonyManager.getDefault().getSimCount(); 1038 } 1039 1040 /** @hide */ 1041 public static boolean isValidPhoneId(int phoneId) { 1042 return phoneId >= 0 && phoneId < TelephonyManager.getDefault().getPhoneCount(); 1043 } 1044 1045 /** @hide */ 1046 public static void putPhoneIdAndSubIdExtra(Intent intent, int phoneId) { 1047 int[] subIds = SubscriptionManager.getSubId(phoneId); 1048 if (subIds != null && subIds.length > 0) { 1049 putPhoneIdAndSubIdExtra(intent, phoneId, subIds[0]); 1050 } else { 1051 logd("putPhoneIdAndSubIdExtra: no valid subs"); 1052 } 1053 } 1054 1055 /** @hide */ 1056 public static void putPhoneIdAndSubIdExtra(Intent intent, int phoneId, int subId) { 1057 if (VDBG) logd("putPhoneIdAndSubIdExtra: phoneId=" + phoneId + " subId=" + subId); 1058 intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId); 1059 intent.putExtra(PhoneConstants.PHONE_KEY, phoneId); 1060 //FIXME this is using phoneId and slotId interchangeably 1061 //Eventually, this should be removed as it is not the slot id 1062 intent.putExtra(PhoneConstants.SLOT_KEY, phoneId); 1063 } 1064 1065 /** 1066 * @return the list of subId's that are active, 1067 * is never null but the length maybe 0. 1068 * @hide 1069 */ 1070 public @NonNull int[] getActiveSubscriptionIdList() { 1071 int[] subId = null; 1072 1073 try { 1074 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); 1075 if (iSub != null) { 1076 subId = iSub.getActiveSubIdList(); 1077 } 1078 } catch (RemoteException ex) { 1079 // ignore it 1080 } 1081 1082 if (subId == null) { 1083 subId = new int[0]; 1084 } 1085 1086 return subId; 1087 1088 } 1089 1090 /** 1091 * Returns true if the device is considered roaming on the current 1092 * network for a subscription. 1093 * <p> 1094 * Availability: Only when user registered to a network. 1095 * 1096 * @param subId The subscription ID 1097 * @return true if the network for the subscription is roaming, false otherwise 1098 */ 1099 public boolean isNetworkRoaming(int subId) { 1100 final int phoneId = getPhoneId(subId); 1101 if (phoneId < 0) { 1102 // What else can we do? 1103 return false; 1104 } 1105 return TelephonyManager.getDefault().isNetworkRoaming(subId); 1106 } 1107 1108 /** 1109 * Returns a constant indicating the state of sim for the slot idx. 1110 * 1111 * @param slotIdx 1112 * 1113 * {@See TelephonyManager#SIM_STATE_UNKNOWN} 1114 * {@See TelephonyManager#SIM_STATE_ABSENT} 1115 * {@See TelephonyManager#SIM_STATE_PIN_REQUIRED} 1116 * {@See TelephonyManager#SIM_STATE_PUK_REQUIRED} 1117 * {@See TelephonyManager#SIM_STATE_NETWORK_LOCKED} 1118 * {@See TelephonyManager#SIM_STATE_READY} 1119 * {@See TelephonyManager#SIM_STATE_NOT_READY} 1120 * {@See TelephonyManager#SIM_STATE_PERM_DISABLED} 1121 * {@See TelephonyManager#SIM_STATE_CARD_IO_ERROR} 1122 * 1123 * {@hide} 1124 */ 1125 public static int getSimStateForSlotIdx(int slotIdx) { 1126 int simState = TelephonyManager.SIM_STATE_UNKNOWN; 1127 1128 try { 1129 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); 1130 if (iSub != null) { 1131 simState = iSub.getSimStateForSlotIdx(slotIdx); 1132 } 1133 } catch (RemoteException ex) { 1134 } 1135 logd("getSimStateForSubscriber: simState=" + simState + " slotIdx=" + slotIdx); 1136 return simState; 1137 } 1138 1139 /** 1140 * @return true if the sub ID is active. i.e. The sub ID corresponds to a known subscription 1141 * and the SIM providing the subscription is present in a slot and in "LOADED" state. 1142 * @hide 1143 */ 1144 public boolean isActiveSubId(int subId) { 1145 try { 1146 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); 1147 if (iSub != null) { 1148 return iSub.isActiveSubId(subId); 1149 } 1150 } catch (RemoteException ex) { 1151 } 1152 return false; 1153 } 1154} 1155