SubscriptionManager.java revision 21301f6016ce50594f6cd9c66581ee9a08b57be9
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.getPackageName() : "<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.getPackageName() : "<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 logd("[getActiveSubscriptionInfo]- invalid subId"); 391 return null; 392 } 393 394 SubscriptionInfo subInfo = null; 395 396 try { 397 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); 398 if (iSub != null) { 399 subInfo = iSub.getActiveSubscriptionInfo(subId, mContext.getOpPackageName()); 400 } 401 } catch (RemoteException ex) { 402 // ignore it 403 } 404 405 return subInfo; 406 407 } 408 409 /** 410 * Get the active SubscriptionInfo associated with the iccId 411 * @param iccId the IccId of SIM card 412 * @return SubscriptionInfo, maybe null if its not active 413 * @hide 414 */ 415 public SubscriptionInfo getActiveSubscriptionInfoForIccIndex(String iccId) { 416 if (VDBG) logd("[getActiveSubscriptionInfoForIccIndex]+ iccId=" + iccId); 417 if (iccId == null) { 418 logd("[getActiveSubscriptionInfoForIccIndex]- null iccid"); 419 return null; 420 } 421 422 SubscriptionInfo result = null; 423 424 try { 425 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); 426 if (iSub != null) { 427 result = iSub.getActiveSubscriptionInfoForIccId(iccId, mContext.getOpPackageName()); 428 } 429 } catch (RemoteException ex) { 430 // ignore it 431 } 432 433 return result; 434 } 435 436 /** 437 * Get the active SubscriptionInfo associated with the slotIdx 438 * @param slotIdx the slot which the subscription is inserted 439 * @return SubscriptionInfo, maybe null if its not active 440 */ 441 public SubscriptionInfo getActiveSubscriptionInfoForSimSlotIndex(int slotIdx) { 442 if (VDBG) logd("[getActiveSubscriptionInfoForSimSlotIndex]+ slotIdx=" + slotIdx); 443 if (!isValidSlotId(slotIdx)) { 444 logd("[getActiveSubscriptionInfoForSimSlotIndex]- invalid slotIdx"); 445 return null; 446 } 447 448 SubscriptionInfo result = null; 449 450 try { 451 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); 452 if (iSub != null) { 453 result = iSub.getActiveSubscriptionInfoForSimSlotIndex(slotIdx, 454 mContext.getOpPackageName()); 455 } 456 } catch (RemoteException ex) { 457 // ignore it 458 } 459 460 return result; 461 } 462 463 /** 464 * @return List of all SubscriptionInfo records in database, 465 * include those that were inserted before, maybe empty but not null. 466 * @hide 467 */ 468 public List<SubscriptionInfo> getAllSubscriptionInfoList() { 469 if (VDBG) logd("[getAllSubscriptionInfoList]+"); 470 471 List<SubscriptionInfo> result = null; 472 473 try { 474 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); 475 if (iSub != null) { 476 result = iSub.getAllSubInfoList(mContext.getOpPackageName()); 477 } 478 } catch (RemoteException ex) { 479 // ignore it 480 } 481 482 if (result == null) { 483 result = new ArrayList<SubscriptionInfo>(); 484 } 485 return result; 486 } 487 488 /** 489 * Get the SubscriptionInfo(s) of the currently inserted SIM(s). The records will be sorted 490 * by {@link SubscriptionInfo#getSimSlotIndex} then by {@link SubscriptionInfo#getSubscriptionId}. 491 * 492 * @return Sorted list of the currently {@link SubscriptionInfo} records available on the device. 493 * <ul> 494 * <li> 495 * If null is returned the current state is unknown but if a {@link OnSubscriptionsChangedListener} 496 * has been registered {@link OnSubscriptionsChangedListener#onSubscriptionsChanged} will be 497 * invoked in the future. 498 * </li> 499 * <li> 500 * If the list is empty then there are no {@link SubscriptionInfo} records currently available. 501 * </li> 502 * <li> 503 * if the list is non-empty the list is sorted by {@link SubscriptionInfo#getSimSlotIndex} 504 * then by {@link SubscriptionInfo#getSubscriptionId}. 505 * </li> 506 * </ul> 507 */ 508 public List<SubscriptionInfo> getActiveSubscriptionInfoList() { 509 List<SubscriptionInfo> result = null; 510 511 try { 512 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); 513 if (iSub != null) { 514 result = iSub.getActiveSubscriptionInfoList(mContext.getOpPackageName()); 515 } 516 } catch (RemoteException ex) { 517 // ignore it 518 } 519 return result; 520 } 521 522 /** 523 * @return the count of all subscriptions in the database, this includes 524 * all subscriptions that have been seen. 525 * @hide 526 */ 527 public int getAllSubscriptionInfoCount() { 528 if (VDBG) logd("[getAllSubscriptionInfoCount]+"); 529 530 int result = 0; 531 532 try { 533 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); 534 if (iSub != null) { 535 result = iSub.getAllSubInfoCount(mContext.getOpPackageName()); 536 } 537 } catch (RemoteException ex) { 538 // ignore it 539 } 540 541 return result; 542 } 543 544 /** 545 * @return the current number of active subscriptions. There is no guarantee the value 546 * returned by this method will be the same as the length of the list returned by 547 * {@link #getActiveSubscriptionInfoList}. 548 */ 549 public int getActiveSubscriptionInfoCount() { 550 int result = 0; 551 552 try { 553 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); 554 if (iSub != null) { 555 result = iSub.getActiveSubInfoCount(mContext.getOpPackageName()); 556 } 557 } catch (RemoteException ex) { 558 // ignore it 559 } 560 561 return result; 562 } 563 564 /** 565 * @return the maximum number of active subscriptions that will be returned by 566 * {@link #getActiveSubscriptionInfoList} and the value returned by 567 * {@link #getActiveSubscriptionInfoCount}. 568 */ 569 public int getActiveSubscriptionInfoCountMax() { 570 int result = 0; 571 572 try { 573 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); 574 if (iSub != null) { 575 result = iSub.getActiveSubInfoCountMax(); 576 } 577 } catch (RemoteException ex) { 578 // ignore it 579 } 580 581 return result; 582 } 583 584 /** 585 * Add a new SubscriptionInfo to SubscriptionInfo database if needed 586 * @param iccId the IccId of the SIM card 587 * @param slotId the slot which the SIM is inserted 588 * @return the URL of the newly created row or the updated row 589 * @hide 590 */ 591 public Uri addSubscriptionInfoRecord(String iccId, int slotId) { 592 if (VDBG) logd("[addSubscriptionInfoRecord]+ iccId:" + iccId + " slotId:" + slotId); 593 if (iccId == null) { 594 logd("[addSubscriptionInfoRecord]- null iccId"); 595 } 596 if (!isValidSlotId(slotId)) { 597 logd("[addSubscriptionInfoRecord]- invalid slotId"); 598 } 599 600 try { 601 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); 602 if (iSub != null) { 603 // FIXME: This returns 1 on success, 0 on error should should we return it? 604 iSub.addSubInfoRecord(iccId, slotId, mContext.getOpPackageName()); 605 } 606 } catch (RemoteException ex) { 607 // ignore it 608 } 609 610 // FIXME: Always returns null? 611 return null; 612 613 } 614 615 /** 616 * Set SIM icon tint color by simInfo index 617 * @param tint the RGB value of icon tint color of the SIM 618 * @param subId the unique SubInfoRecord index in database 619 * @return the number of records updated 620 * @hide 621 */ 622 public int setIconTint(int tint, int subId) { 623 if (VDBG) logd("[setIconTint]+ tint:" + tint + " subId:" + subId); 624 if (!isValidSubscriptionId(subId)) { 625 logd("[setIconTint]- fail"); 626 return -1; 627 } 628 629 int result = 0; 630 631 try { 632 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); 633 if (iSub != null) { 634 result = iSub.setIconTint(tint, subId, mContext.getOpPackageName()); 635 } 636 } catch (RemoteException ex) { 637 // ignore it 638 } 639 640 return result; 641 642 } 643 644 /** 645 * Set display name by simInfo index 646 * @param displayName the display name of SIM card 647 * @param subId the unique SubscriptionInfo index in database 648 * @return the number of records updated 649 * @hide 650 */ 651 public int setDisplayName(String displayName, int subId) { 652 return setDisplayName(displayName, subId, NAME_SOURCE_UNDEFINDED); 653 } 654 655 /** 656 * Set display name by simInfo index with name source 657 * @param displayName the display name of SIM card 658 * @param subId the unique SubscriptionInfo index in database 659 * @param nameSource 0: NAME_SOURCE_DEFAULT_SOURCE, 1: NAME_SOURCE_SIM_SOURCE, 660 * 2: NAME_SOURCE_USER_INPUT, -1 NAME_SOURCE_UNDEFINED 661 * @return the number of records updated or < 0 if invalid subId 662 * @hide 663 */ 664 public int setDisplayName(String displayName, int subId, long nameSource) { 665 if (VDBG) { 666 logd("[setDisplayName]+ displayName:" + displayName + " subId:" + subId 667 + " nameSource:" + nameSource); 668 } 669 if (!isValidSubscriptionId(subId)) { 670 logd("[setDisplayName]- fail"); 671 return -1; 672 } 673 674 int result = 0; 675 676 try { 677 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); 678 if (iSub != null) { 679 result = iSub.setDisplayNameUsingSrc(displayName, subId, nameSource, 680 mContext.getOpPackageName()); 681 } 682 } catch (RemoteException ex) { 683 // ignore it 684 } 685 686 return result; 687 688 } 689 690 /** 691 * Set phone number by subId 692 * @param number the phone number of the SIM 693 * @param subId the unique SubscriptionInfo index in database 694 * @return the number of records updated 695 * @hide 696 */ 697 public int setDisplayNumber(String number, int subId) { 698 if (number == null || !isValidSubscriptionId(subId)) { 699 logd("[setDisplayNumber]- fail"); 700 return -1; 701 } 702 703 int result = 0; 704 705 try { 706 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); 707 if (iSub != null) { 708 result = iSub.setDisplayNumber(number, subId, mContext.getOpPackageName()); 709 } 710 } catch (RemoteException ex) { 711 // ignore it 712 } 713 714 return result; 715 716 } 717 718 /** 719 * Set data roaming by simInfo index 720 * @param roaming 0:Don't allow data when roaming, 1:Allow data when roaming 721 * @param subId the unique SubscriptionInfo index in database 722 * @return the number of records updated 723 * @hide 724 */ 725 public int setDataRoaming(int roaming, int subId) { 726 if (VDBG) logd("[setDataRoaming]+ roaming:" + roaming + " subId:" + subId); 727 if (roaming < 0 || !isValidSubscriptionId(subId)) { 728 logd("[setDataRoaming]- fail"); 729 return -1; 730 } 731 732 int result = 0; 733 734 try { 735 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); 736 if (iSub != null) { 737 result = iSub.setDataRoaming(roaming, subId, mContext.getOpPackageName()); 738 } 739 } catch (RemoteException ex) { 740 // ignore it 741 } 742 743 return result; 744 } 745 746 /** 747 * Get slotId associated with the subscription. 748 * @return slotId as a positive integer or a negative value if an error either 749 * SIM_NOT_INSERTED or < 0 if an invalid slot index 750 * @hide 751 */ 752 public static int getSlotId(int subId) { 753 if (!isValidSubscriptionId(subId)) { 754 logd("[getSlotId]- fail"); 755 } 756 757 int result = INVALID_SIM_SLOT_INDEX; 758 759 try { 760 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); 761 if (iSub != null) { 762 result = iSub.getSlotId(subId); 763 } 764 } catch (RemoteException ex) { 765 // ignore it 766 } 767 768 return result; 769 770 } 771 772 /** @hide */ 773 public static int[] getSubId(int slotId) { 774 if (!isValidSlotId(slotId)) { 775 logd("[getSubId]- fail"); 776 return null; 777 } 778 779 int[] subId = null; 780 781 try { 782 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); 783 if (iSub != null) { 784 subId = iSub.getSubId(slotId); 785 } 786 } catch (RemoteException ex) { 787 // ignore it 788 } 789 790 return subId; 791 } 792 793 /** @hide */ 794 public static int getPhoneId(int subId) { 795 if (!isValidSubscriptionId(subId)) { 796 logd("[getPhoneId]- fail"); 797 return INVALID_PHONE_INDEX; 798 } 799 800 int result = INVALID_PHONE_INDEX; 801 802 try { 803 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); 804 if (iSub != null) { 805 result = iSub.getPhoneId(subId); 806 } 807 } catch (RemoteException ex) { 808 // ignore it 809 } 810 811 if (VDBG) logd("[getPhoneId]- phoneId=" + result); 812 return result; 813 814 } 815 816 private static void logd(String msg) { 817 Rlog.d(LOG_TAG, msg); 818 } 819 820 /** 821 * @return the "system" defaultSubId on a voice capable device this 822 * will be getDefaultVoiceSubId() and on a data only device it will be 823 * getDefaultDataSubId(). 824 * @hide 825 */ 826 public static int getDefaultSubId() { 827 int subId = INVALID_SUBSCRIPTION_ID; 828 829 try { 830 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); 831 if (iSub != null) { 832 subId = iSub.getDefaultSubId(); 833 } 834 } catch (RemoteException ex) { 835 // ignore it 836 } 837 838 if (VDBG) logd("getDefaultSubId=" + subId); 839 return subId; 840 } 841 842 /** @hide */ 843 public static int getDefaultVoiceSubId() { 844 int subId = INVALID_SUBSCRIPTION_ID; 845 846 try { 847 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); 848 if (iSub != null) { 849 subId = iSub.getDefaultVoiceSubId(); 850 } 851 } catch (RemoteException ex) { 852 // ignore it 853 } 854 855 if (VDBG) logd("getDefaultVoiceSubId, sub id = " + subId); 856 return subId; 857 } 858 859 /** @hide */ 860 public void setDefaultVoiceSubId(int subId) { 861 if (VDBG) logd("setDefaultVoiceSubId sub id = " + subId); 862 try { 863 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); 864 if (iSub != null) { 865 iSub.setDefaultVoiceSubId(subId); 866 } 867 } catch (RemoteException ex) { 868 // ignore it 869 } 870 } 871 872 /** @hide */ 873 public SubscriptionInfo getDefaultVoiceSubscriptionInfo() { 874 return getActiveSubscriptionInfo(getDefaultVoiceSubId()); 875 } 876 877 /** @hide */ 878 public static int getDefaultVoicePhoneId() { 879 return getPhoneId(getDefaultVoiceSubId()); 880 } 881 882 /** 883 * @return subId of the DefaultSms subscription or 884 * a value < 0 if an error. 885 * 886 * @hide 887 */ 888 public static int getDefaultSmsSubId() { 889 int subId = INVALID_SUBSCRIPTION_ID; 890 891 try { 892 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); 893 if (iSub != null) { 894 subId = iSub.getDefaultSmsSubId(); 895 } 896 } catch (RemoteException ex) { 897 // ignore it 898 } 899 900 if (VDBG) logd("getDefaultSmsSubId, sub id = " + subId); 901 return subId; 902 } 903 904 /** @hide */ 905 public void setDefaultSmsSubId(int subId) { 906 if (VDBG) logd("setDefaultSmsSubId sub id = " + subId); 907 try { 908 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); 909 if (iSub != null) { 910 iSub.setDefaultSmsSubId(subId); 911 } 912 } catch (RemoteException ex) { 913 // ignore it 914 } 915 } 916 917 /** @hide */ 918 public SubscriptionInfo getDefaultSmsSubscriptionInfo() { 919 return getActiveSubscriptionInfo(getDefaultSmsSubId()); 920 } 921 922 /** @hide */ 923 public int getDefaultSmsPhoneId() { 924 return getPhoneId(getDefaultSmsSubId()); 925 } 926 927 /** @hide */ 928 public static int getDefaultDataSubId() { 929 int subId = INVALID_SUBSCRIPTION_ID; 930 931 try { 932 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); 933 if (iSub != null) { 934 subId = iSub.getDefaultDataSubId(); 935 } 936 } catch (RemoteException ex) { 937 // ignore it 938 } 939 940 if (VDBG) logd("getDefaultDataSubId, sub id = " + subId); 941 return subId; 942 } 943 944 /** @hide */ 945 public void setDefaultDataSubId(int subId) { 946 if (VDBG) logd("setDataSubscription sub id = " + subId); 947 try { 948 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); 949 if (iSub != null) { 950 iSub.setDefaultDataSubId(subId); 951 } 952 } catch (RemoteException ex) { 953 // ignore it 954 } 955 } 956 957 /** @hide */ 958 public SubscriptionInfo getDefaultDataSubscriptionInfo() { 959 return getActiveSubscriptionInfo(getDefaultDataSubId()); 960 } 961 962 /** @hide */ 963 public int getDefaultDataPhoneId() { 964 return getPhoneId(getDefaultDataSubId()); 965 } 966 967 /** @hide */ 968 public void clearSubscriptionInfo() { 969 try { 970 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); 971 if (iSub != null) { 972 iSub.clearSubInfo(mContext.getOpPackageName()); 973 } 974 } catch (RemoteException ex) { 975 // ignore it 976 } 977 978 return; 979 } 980 981 //FIXME this is vulnerable to race conditions 982 /** @hide */ 983 public boolean allDefaultsSelected() { 984 if (!isValidSubscriptionId(getDefaultDataSubId())) { 985 return false; 986 } 987 if (!isValidSubscriptionId(getDefaultSmsSubId())) { 988 return false; 989 } 990 if (!isValidSubscriptionId(getDefaultVoiceSubId())) { 991 return false; 992 } 993 return true; 994 } 995 996 /** 997 * If a default is set to subscription which is not active, this will reset that default back to 998 * an invalid subscription id, i.e. < 0. 999 * @hide 1000 */ 1001 public void clearDefaultsForInactiveSubIds() { 1002 if (VDBG) logd("clearDefaultsForInactiveSubIds"); 1003 try { 1004 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); 1005 if (iSub != null) { 1006 iSub.clearDefaultsForInactiveSubIds(mContext.getOpPackageName()); 1007 } 1008 } catch (RemoteException ex) { 1009 // ignore it 1010 } 1011 } 1012 1013 /** 1014 * @return true if a valid subId else false 1015 * @hide 1016 */ 1017 public static boolean isValidSubscriptionId(int subId) { 1018 return subId > INVALID_SUBSCRIPTION_ID ; 1019 } 1020 1021 /** 1022 * @return true if subId is an usable subId value else false. A 1023 * usable subId means its neither a INVALID_SUBSCRIPTION_ID nor a DEFAULT_SUB_ID. 1024 * @hide 1025 */ 1026 public static boolean isUsableSubIdValue(int subId) { 1027 return subId >= MIN_SUBSCRIPTION_ID_VALUE && subId <= MAX_SUBSCRIPTION_ID_VALUE; 1028 } 1029 1030 /** @hide */ 1031 public static boolean isValidSlotId(int slotId) { 1032 return slotId >= 0 && slotId < TelephonyManager.getDefault().getSimCount(); 1033 } 1034 1035 /** @hide */ 1036 public static boolean isValidPhoneId(int phoneId) { 1037 return phoneId >= 0 && phoneId < TelephonyManager.getDefault().getPhoneCount(); 1038 } 1039 1040 /** @hide */ 1041 public static void putPhoneIdAndSubIdExtra(Intent intent, int phoneId) { 1042 int[] subIds = SubscriptionManager.getSubId(phoneId); 1043 if (subIds != null && subIds.length > 0) { 1044 putPhoneIdAndSubIdExtra(intent, phoneId, subIds[0]); 1045 } else { 1046 logd("putPhoneIdAndSubIdExtra: no valid subs"); 1047 } 1048 } 1049 1050 /** @hide */ 1051 public static void putPhoneIdAndSubIdExtra(Intent intent, int phoneId, int subId) { 1052 if (VDBG) logd("putPhoneIdAndSubIdExtra: phoneId=" + phoneId + " subId=" + subId); 1053 intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId); 1054 intent.putExtra(PhoneConstants.PHONE_KEY, phoneId); 1055 //FIXME this is using phoneId and slotId interchangeably 1056 //Eventually, this should be removed as it is not the slot id 1057 intent.putExtra(PhoneConstants.SLOT_KEY, phoneId); 1058 } 1059 1060 /** 1061 * @return the list of subId's that are active, 1062 * is never null but the length maybe 0. 1063 * @hide 1064 */ 1065 public @NonNull int[] getActiveSubscriptionIdList() { 1066 int[] subId = null; 1067 1068 try { 1069 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); 1070 if (iSub != null) { 1071 subId = iSub.getActiveSubIdList(); 1072 } 1073 } catch (RemoteException ex) { 1074 // ignore it 1075 } 1076 1077 if (subId == null) { 1078 subId = new int[0]; 1079 } 1080 1081 return subId; 1082 1083 } 1084 1085 /** 1086 * Returns true if the device is considered roaming on the current 1087 * network for a subscription. 1088 * <p> 1089 * Availability: Only when user registered to a network. 1090 * 1091 * @param subId The subscription ID 1092 * @return true if the network for the subscription is roaming, false otherwise 1093 */ 1094 public boolean isNetworkRoaming(int subId) { 1095 final int phoneId = getPhoneId(subId); 1096 if (phoneId < 0) { 1097 // What else can we do? 1098 return false; 1099 } 1100 return TelephonyManager.getDefault().isNetworkRoaming(subId); 1101 } 1102 1103 /** 1104 * Returns a constant indicating the state of sim for the subscription. 1105 * 1106 * @param subId 1107 * 1108 * {@See TelephonyManager#SIM_STATE_UNKNOWN} 1109 * {@See TelephonyManager#SIM_STATE_ABSENT} 1110 * {@See TelephonyManager#SIM_STATE_PIN_REQUIRED} 1111 * {@See TelephonyManager#SIM_STATE_PUK_REQUIRED} 1112 * {@See TelephonyManager#SIM_STATE_NETWORK_LOCKED} 1113 * {@See TelephonyManager#SIM_STATE_READY} 1114 * {@See TelephonyManager#SIM_STATE_NOT_READY} 1115 * {@See TelephonyManager#SIM_STATE_PERM_DISABLED} 1116 * {@See TelephonyManager#SIM_STATE_CARD_IO_ERROR} 1117 * 1118 * {@hide} 1119 */ 1120 public static int getSimStateForSubscriber(int subId) { 1121 int simState; 1122 1123 try { 1124 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); 1125 simState = iSub.getSimStateForSubscriber(subId); 1126 } catch (RemoteException ex) { 1127 simState = TelephonyManager.SIM_STATE_UNKNOWN; 1128 } 1129 logd("getSimStateForSubscriber: simState=" + simState + " subId=" + subId); 1130 return simState; 1131 } 1132} 1133 1134