SubscriptionManager.java revision fb40dd4d00bd3361b2535bc866e6c21eadc52558
1/* 2* Copyright (C) 2011-2014 MediaTek Inc. 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 static android.Manifest.permission.READ_PHONE_STATE; 20 21import android.app.ActivityManagerNative; 22import android.content.ContentResolver; 23import android.content.ContentUris; 24import android.content.ContentValues; 25import android.content.Context; 26import android.content.Intent; 27import android.database.Cursor; 28import android.os.UserHandle; 29import android.net.Uri; 30import android.provider.BaseColumns; 31import android.telephony.Rlog; 32import android.os.ServiceManager; 33import android.os.RemoteException; 34 35import com.android.internal.telephony.ISub; 36import com.android.internal.telephony.PhoneConstants; 37import com.android.internal.telephony.TelephonyIntents; 38 39import java.util.ArrayList; 40import java.util.List; 41import java.util.HashMap; 42import java.util.Iterator; 43import java.util.Map.Entry; 44 45/** 46 *@hide 47 */ 48public class SubscriptionManager implements BaseColumns { 49 private static final String LOG_TAG = "SUB"; 50 private static final boolean DBG = true; 51 private static final boolean VDBG = false; 52 53 // An invalid subscription identifier 54 public static final long INVALID_SUB_ID = Long.MAX_VALUE; 55 56 // The default subscription identifier 57 public static final long DEFAULT_SUB_ID = Long.MAX_VALUE - 1; 58 59 public static final Uri CONTENT_URI = Uri.parse("content://telephony/siminfo"); 60 61 public static final int DEFAULT_INT_VALUE = -100; 62 63 public static final String DEFAULT_STRING_VALUE = "N/A"; 64 65 public static final int EXTRA_VALUE_NEW_SIM = 1; 66 public static final int EXTRA_VALUE_REMOVE_SIM = 2; 67 public static final int EXTRA_VALUE_REPOSITION_SIM = 3; 68 public static final int EXTRA_VALUE_NOCHANGE = 4; 69 70 public static final String INTENT_KEY_DETECT_STATUS = "simDetectStatus"; 71 public static final String INTENT_KEY_SIM_COUNT = "simCount"; 72 public static final String INTENT_KEY_NEW_SIM_SLOT = "newSIMSlot"; 73 public static final String INTENT_KEY_NEW_SIM_STATUS = "newSIMStatus"; 74 75 /** 76 * The ICC ID of a SIM. 77 * <P>Type: TEXT (String)</P> 78 */ 79 public static final String ICC_ID = "icc_id"; 80 81 /** 82 * <P>Type: INTEGER (int)</P> 83 */ 84 public static final String SIM_ID = "sim_id"; 85 86 public static final int SIM_NOT_INSERTED = -1; 87 88 /** 89 * The display name of a SIM. 90 * <P>Type: TEXT (String)</P> 91 */ 92 public static final String DISPLAY_NAME = "display_name"; 93 94 public static final int DEFAULT_NAME_RES = com.android.internal.R.string.unknownName; 95 96 /** 97 * The display name source of a SIM. 98 * <P>Type: INT (int)</P> 99 */ 100 public static final String NAME_SOURCE = "name_source"; 101 102 public static final int DEFAULT_SOURCE = 0; 103 104 public static final int SIM_SOURCE = 1; 105 106 public static final int USER_INPUT = 2; 107 108 /** 109 * The color of a SIM. 110 * <P>Type: INTEGER (int)</P> 111 */ 112 public static final String COLOR = "color"; 113 114 public static final int COLOR_1 = 0; 115 116 public static final int COLOR_2 = 1; 117 118 public static final int COLOR_3 = 2; 119 120 public static final int COLOR_4 = 3; 121 122 public static final int COLOR_DEFAULT = COLOR_1; 123 124 /** 125 * The phone number of a SIM. 126 * <P>Type: TEXT (String)</P> 127 */ 128 public static final String NUMBER = "number"; 129 130 /** 131 * The number display format of a SIM. 132 * <P>Type: INTEGER (int)</P> 133 */ 134 public static final String DISPLAY_NUMBER_FORMAT = "display_number_format"; 135 136 public static final int DISPALY_NUMBER_NONE = 0; 137 138 public static final int DISPLAY_NUMBER_FIRST = 1; 139 140 public static final int DISPLAY_NUMBER_LAST = 2; 141 142 public static final int DISLPAY_NUMBER_DEFAULT = DISPLAY_NUMBER_FIRST; 143 144 /** 145 * Permission for data roaming of a SIM. 146 * <P>Type: INTEGER (int)</P> 147 */ 148 public static final String DATA_ROAMING = "data_roaming"; 149 150 public static final int DATA_ROAMING_ENABLE = 1; 151 152 public static final int DATA_ROAMING_DISABLE = 0; 153 154 public static final int DATA_ROAMING_DEFAULT = DATA_ROAMING_DISABLE; 155 156 private static final int RES_TYPE_BACKGROUND_DARK = 0; 157 158 private static final int RES_TYPE_BACKGROUND_LIGHT = 1; 159 160 private static final int[] sSimBackgroundDarkRes = setSimResource(RES_TYPE_BACKGROUND_DARK); 161 162 private static final int[] sSimBackgroundLightRes = setSimResource(RES_TYPE_BACKGROUND_LIGHT); 163 164 private static HashMap<Integer, Long> mSimInfo = new HashMap<Integer, Long>(); 165 166 public SubscriptionManager() { 167 if (DBG) logd("SubscriptionManager created"); 168 } 169 170 /** 171 * Get the SubInfoRecord according to an index 172 * @param context Context provided by caller 173 * @param subId The unique SubInfoRecord index in database 174 * @return SubInfoRecord, maybe null 175 */ 176 public static SubInfoRecord getSubInfoUsingSubId(Context context, long subId) { 177 if (VDBG) logd("[getSubInfoUsingSubIdx]+ subId:" + subId); 178 if (subId <= 0) { 179 if (VDBG) logd("[getSubInfoUsingSubIdx]- subId <= 0"); 180 return null; 181 } 182 183 SubInfoRecord subInfo = null; 184 185 try { 186 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); 187 if (iSub != null) { 188 subInfo = iSub.getSubInfoUsingSubId(subId); 189 } 190 } catch (RemoteException ex) { 191 // ignore it 192 } 193 194 return subInfo; 195 196 } 197 198 /** 199 * Get the SubInfoRecord according to an IccId 200 * @param context Context provided by caller 201 * @param iccId the IccId of SIM card 202 * @return SubInfoRecord, maybe null 203 */ 204 public static List<SubInfoRecord> getSubInfoUsingIccId(Context context, String iccId) { 205 if (VDBG) logd("[getSubInfoUsingIccId]+ iccId=" + iccId); 206 if (iccId == null) { 207 logd("[getSubInfoUsingIccId]- null iccid"); 208 return null; 209 } 210 211 List<SubInfoRecord> result = null; 212 213 try { 214 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); 215 if (iSub != null) { 216 result = iSub.getSubInfoUsingIccId(iccId); 217 } 218 } catch (RemoteException ex) { 219 // ignore it 220 } 221 222 return result; 223 } 224 225 /** 226 * Get the SubInfoRecord according to slotId 227 * @param context Context provided by caller 228 * @param slotId the slot which the SIM is inserted 229 * @return SubInfoRecord, maybe null 230 */ 231 public static List<SubInfoRecord> getSubInfoUsingSlotId(Context context, int slotId) { 232 if (VDBG) logd("[getSubInfoUsingSlotId]- slotId=" + slotId); 233 if (slotId < 0) { 234 logd("[getSubInfoUsingSlotId]- return null, slotId < 0"); 235 return null; 236 } 237 238 List<SubInfoRecord> result = null; 239 240 try { 241 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); 242 if (iSub != null) { 243 result = iSub.getSubInfoUsingSlotId(slotId); 244 } 245 } catch (RemoteException ex) { 246 // ignore it 247 } 248 249 return result; 250 } 251 252 /** 253 * Get all the SubInfoRecord(s) in subinfo database 254 * @param context Context provided by caller 255 * @return Array list of all SubInfoRecords in database, include thsoe that were inserted before 256 */ 257 public static List<SubInfoRecord> getAllSubInfoList(Context context) { 258 if (VDBG) logd("[getAllSubInfoList]+"); 259 260 List<SubInfoRecord> result = null; 261 262 try { 263 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); 264 if (iSub != null) { 265 result = iSub.getAllSubInfoList(); 266 } 267 } catch (RemoteException ex) { 268 // ignore it 269 } 270 271 return result; 272 } 273 274 /** 275 * Get the SubInfoRecord(s) of the currently inserted SIM(s) 276 * @param context Context provided by caller 277 * @return Array list of currently inserted SubInfoRecord(s) 278 */ 279 public static List<SubInfoRecord> getActivatedSubInfoList(Context context) { 280 if (VDBG) logd("[getActivatedSubInfoList]+"); 281 282 List<SubInfoRecord> result = null; 283 284 try { 285 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); 286 if (iSub != null) { 287 result = iSub.getActivatedSubInfoList(); 288 } 289 } catch (RemoteException ex) { 290 // ignore it 291 } 292 293 return result; 294 } 295 296 /** 297 * Get the SUB count of all SUB(s) in subinfo database 298 * @param context Context provided by caller 299 * @return all SIM count in database, include what was inserted before 300 */ 301 public static int getAllSubInfoCount(Context context) { 302 if (VDBG) logd("[getAllSubInfoCount]+"); 303 304 int result = 0; 305 306 try { 307 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); 308 if (iSub != null) { 309 result = iSub.getAllSubInfoCount(); 310 } 311 } catch (RemoteException ex) { 312 // ignore it 313 } 314 315 return result; 316 } 317 318 /** 319 * Add a new SubInfoRecord to subinfo database if needed 320 * @param context Context provided by caller 321 * @param iccId the IccId of the SIM card 322 * @param slotId the slot which the SIM is inserted 323 * @return the URL of the newly created row or the updated row 324 */ 325 public static Uri addSubInfoRecord(Context context, String iccId, int slotId) { 326 if (VDBG) logd("[addSubInfoRecord]+ iccId:" + iccId + " slotId:" + slotId); 327 if (iccId == null) { 328 logd("[addSubInfoRecord]- null iccId"); 329 } 330 331 try { 332 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); 333 if (iSub != null) { 334 // FIXME: This returns 1 on success, 0 on error should should we return it? 335 iSub.addSubInfoRecord(iccId, slotId); 336 } 337 } catch (RemoteException ex) { 338 // ignore it 339 } 340 341 // FIXME: Always returns null? 342 return null; 343 344 } 345 346 /** 347 * Set SIM color by simInfo index 348 * @param context Context provided by caller 349 * @param color the color of the SIM 350 * @param subId the unique SubInfoRecord index in database 351 * @return the number of records updated 352 */ 353 public static int setColor(Context context, int color, long subId) { 354 if (VDBG) logd("[setColor]+ color:" + color + " subId:" + subId); 355 int size = sSimBackgroundDarkRes.length; 356 if (subId <= 0 || color < 0 || color >= size) { 357 logd("[setColor]- fail"); 358 return -1; 359 } 360 361 int result = 0; 362 363 try { 364 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); 365 if (iSub != null) { 366 result = iSub.setColor(color, subId); 367 } 368 } catch (RemoteException ex) { 369 // ignore it 370 } 371 372 return result; 373 374 } 375 376 /** 377 * Set display name by simInfo index 378 * @param context Context provided by caller 379 * @param displayName the display name of SIM card 380 * @param subId the unique SubInfoRecord index in database 381 * @return the number of records updated 382 */ 383 public static int setDisplayName(Context context, String displayName, long subId) { 384 return setDisplayName(context, displayName, subId, -1); 385 } 386 387 /** 388 * Set display name by simInfo index with name source 389 * @param context Context provided by caller 390 * @param displayName the display name of SIM card 391 * @param subId the unique SubInfoRecord index in database 392 * @param nameSource, 0: DEFAULT_SOURCE, 1: SIM_SOURCE, 2: USER_INPUT 393 * @return the number of records updated 394 */ 395 public static int setDisplayName(Context context, String displayName, long subId, long nameSource) { 396 if (VDBG) logd("[setDisplayName]+ displayName:" + displayName + " subId:" + subId + " nameSource:" + nameSource); 397 if (subId <= 0) { 398 logd("[setDisplayName]- fail"); 399 return -1; 400 } 401 402 int result = 0; 403 404 try { 405 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); 406 if (iSub != null) { 407 result = iSub.setDisplayNameUsingSrc(displayName, subId, nameSource); 408 } 409 } catch (RemoteException ex) { 410 // ignore it 411 } 412 413 return result; 414 415 } 416 417 /** 418 * Set phone number by subId 419 * @param context Context provided by caller 420 * @param number the phone number of the SIM 421 * @param subId the unique SubInfoRecord index in database 422 * @return the number of records updated 423 */ 424 public static int setDispalyNumber(Context context, String number, long subId) { 425 if (VDBG) logd("[setDispalyNumber]+ number:" + number + " subId:" + subId); 426 if (number == null || subId <= 0) { 427 logd("[setDispalyNumber]- fail"); 428 return -1; 429 } 430 431 int result = 0; 432 433 try { 434 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); 435 if (iSub != null) { 436 result = iSub.setDispalyNumber(number, subId); 437 } 438 } catch (RemoteException ex) { 439 // ignore it 440 } 441 442 return result; 443 444 } 445 446 /** 447 * Set number display format. 0: none, 1: the first four digits, 2: the last four digits 448 * @param context Context provided by caller 449 * @param format the display format of phone number 450 * @param subId the unique SubInfoRecord index in database 451 * @return the number of records updated 452 */ 453 public static int setDisplayNumberFormat(Context context, int format, long subId) { 454 if (VDBG) logd("[setDisplayNumberFormat]+ format:" + format + " subId:" + subId); 455 if (format < 0 || subId <= 0) { 456 logd("[setDisplayNumberFormat]- fail, return -1"); 457 return -1; 458 } 459 460 int result = 0; 461 462 try { 463 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); 464 if (iSub != null) { 465 result = iSub.setDisplayNumberFormat(format, subId); 466 } 467 } catch (RemoteException ex) { 468 // ignore it 469 } 470 471 return result; 472 473 } 474 475 /** 476 * Set data roaming by simInfo index 477 * @param context Context provided by caller 478 * @param roaming 0:Don't allow data when roaming, 1:Allow data when roaming 479 * @param subId the unique SubInfoRecord index in database 480 * @return the number of records updated 481 */ 482 public static int setDataRoaming(Context context, int roaming, long subId) { 483 if (VDBG) logd("[setDataRoaming]+ roaming:" + roaming + " subId:" + subId); 484 if (roaming < 0 || subId <= 0) { 485 logd("[setDataRoaming]- fail"); 486 return -1; 487 } 488 489 int result = 0; 490 491 try { 492 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); 493 if (iSub != null) { 494 result = iSub.setDataRoaming(roaming, subId); 495 } 496 } catch (RemoteException ex) { 497 // ignore it 498 } 499 500 return result; 501 } 502 503 public static int getSlotId(long subId) { 504 if (VDBG) logd("[getSlotId]+ subId:" + subId); 505 506 int result = 0; 507 508 try { 509 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); 510 if (iSub != null) { 511 result = iSub.getSlotId(subId); 512 } 513 } catch (RemoteException ex) { 514 // ignore it 515 } 516 517 return result; 518 519 } 520 521 public static long[] getSubId(int slotId) { 522 if (VDBG) logd("[getSubId]+ slotId:" + slotId); 523 524 long[] subId = null; 525 526 try { 527 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); 528 if (iSub != null) { 529 subId = iSub.getSubId(slotId); 530 } 531 } catch (RemoteException ex) { 532 // ignore it 533 } 534 535 return subId; 536 } 537 538 public static int getPhoneId(long subId) { 539 if (VDBG) logd("[getPhoneId]+ subId=" + subId); 540 541 int result = 0; 542 543 try { 544 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); 545 if (iSub != null) { 546 result = iSub.getPhoneId(subId); 547 } 548 } catch (RemoteException ex) { 549 // ignore it 550 } 551 552 if (VDBG) logd("[getPhoneId]- phonId=" + result); 553 return result; 554 555 } 556 557 private static int[] setSimResource(int type) { 558 int[] simResource = null; 559 560 switch (type) { 561 case RES_TYPE_BACKGROUND_DARK: 562 simResource = new int[] { 563 com.android.internal.R.drawable.sim_dark_blue, 564 com.android.internal.R.drawable.sim_dark_orange, 565 com.android.internal.R.drawable.sim_dark_green, 566 com.android.internal.R.drawable.sim_dark_purple 567 }; 568 break; 569 case RES_TYPE_BACKGROUND_LIGHT: 570 simResource = new int[] { 571 com.android.internal.R.drawable.sim_light_blue, 572 com.android.internal.R.drawable.sim_light_orange, 573 com.android.internal.R.drawable.sim_light_green, 574 com.android.internal.R.drawable.sim_light_purple 575 }; 576 break; 577 } 578 579 return simResource; 580 } 581 582 private static void logd(String msg) { 583 Rlog.d(LOG_TAG, "[SubManager] " + msg); 584 } 585 586 public static long normalizeSubId(long subId) { 587 long retVal = (subId == DEFAULT_SUB_ID) ? getDefaultSubId() : subId; 588 Rlog.d(LOG_TAG, "[SubManager] normalizeSubId subId=" + retVal); 589 return retVal; 590 } 591 592 public static boolean validSubId(long subId) { 593 return (subId != DEFAULT_SUB_ID) && (subId != -1); 594 } 595 596 /** 597 * @return the "system" defaultSubId on a voice capable device this 598 * will be getDefaultVoiceSubId() and on a data only device it will be 599 * getDefaultDataSubId(). 600 */ 601 public static long getDefaultSubId() { 602 long subId = 1; 603 604 try { 605 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); 606 if (iSub != null) { 607 subId = iSub.getDefaultSubId(); 608 } 609 } catch (RemoteException ex) { 610 // ignore it 611 } 612 613 if (VDBG) logd("getDefaultSubId=" + subId); 614 return subId; 615 } 616 617 public static long getDefaultVoiceSubId() { 618 long subId = 1; 619 620 try { 621 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); 622 if (iSub != null) { 623 subId = iSub.getDefaultVoiceSubId(); 624 } 625 } catch (RemoteException ex) { 626 // ignore it 627 } 628 629 if (VDBG) logd("getDefaultSubId, sub id = " + subId); 630 return subId; 631 } 632 633 public static void setDefaultVoiceSubId(long subId) { 634 if (VDBG) logd("setDefaultVoiceSubId sub id = " + subId); 635 try { 636 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); 637 if (iSub != null) { 638 iSub.setDefaultVoiceSubId(subId); 639 } 640 } catch (RemoteException ex) { 641 // ignore it 642 } 643 } 644 645 public static long getPreferredSmsSubId() { 646 // FIXME add framework support to get the preferred sub 647 return getDefaultSubId(); 648 } 649 650 public static long getPreferredDataSubId() { 651 // FIXME add framework support to get the preferred sub 652 return getDefaultSubId(); 653 } 654 655 public static long getDefaultDataSubId() { 656 657 try { 658 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); 659 if (iSub != null) { 660 return iSub.getDefaultDataSubId(); 661 } else { 662 return -1; 663 } 664 } catch (RemoteException ex) { 665 return -1; 666 } 667 } 668 669 public static void setDefaultDataSubId(long subId) { 670 if (VDBG) logd("setDataSubscription sub id = " + subId); 671 try { 672 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); 673 if (iSub != null) { 674 iSub.setDefaultDataSubId(subId); 675 } 676 } catch (RemoteException ex) { 677 // ignore it 678 } 679 } 680 681 public static void clearSubInfo() 682 { 683 if (VDBG) logd("[clearSubInfo]+"); 684 685 try { 686 ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); 687 if (iSub != null) { 688 iSub.clearSubInfo(); 689 } 690 } catch (RemoteException ex) { 691 // ignore it 692 } 693 694 return; 695 } 696 697 public static void putPhoneIdAndSubIdExtra(Intent intent, int phoneId) { 698 long [] subId = SubscriptionManager.getSubId(phoneId); 699 if ((subId != null) && (subId.length >= 1)) { 700 if (VDBG) logd("putPhoneIdAndSubIdExtra: phoneId=" + phoneId + " subId=" + subId); 701 intent.putExtra(PhoneConstants.SLOT_KEY, phoneId); //FIXME: RENAME TO PHONE_ID_KEY ?? 702 intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId[0]); 703 } else { 704 logd("putPhoneIdAndSubIdExtra: no valid subs"); 705 } 706 } 707} 708 709