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