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