SubscriptionController.java revision 5f208fd8c2c2ef5036dabffafc72b73b9eb3fc16
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 com.android.internal.telephony; 18 19import android.content.Context; 20import android.os.AsyncResult; 21import android.os.Handler; 22import android.os.Message; 23import android.os.ServiceManager; 24import android.os.UserHandle; 25import android.telephony.Rlog; 26import android.util.Log; 27import android.net.Uri; 28import android.database.Cursor; 29import android.content.Intent; 30import android.provider.BaseColumns; 31import android.provider.Settings; 32import android.content.ContentResolver; 33import android.content.ContentValues; 34 35import com.android.internal.telephony.ISub; 36import com.android.internal.telephony.uicc.SpnOverride; 37 38import android.telephony.SubscriptionManager; 39import android.telephony.SubInfoRecord; 40import android.telephony.TelephonyManager; 41import android.text.format.Time; 42 43import java.io.FileDescriptor; 44import java.io.PrintWriter; 45import java.util.ArrayList; 46import java.util.Iterator; 47import java.util.LinkedList; 48import java.util.List; 49import java.util.HashMap; 50import java.util.Map.Entry; 51import java.util.Set; 52 53/** 54 * SubscriptionController to provide an inter-process communication to 55 * access Sms in Icc. 56 * 57 * Any setters which take subId, slotId or phoneId as a parameter will throw an exception if the 58 * parameter equals the corresponding INVALID_XXX_ID or DEFAULT_XXX_ID. 59 * 60 * All getters will lookup the corresponding default if the parameter is DEFAULT_XXX_ID. Ie calling 61 * getPhoneId(DEFAULT_SUB_ID) will return the same as getPhoneId(getDefaultSubId()). 62 * 63 * Finally, any getters which perform the mapping between subscriptions, slots and phones will 64 * return the corresponding INVALID_XXX_ID if the parameter is INVALID_XXX_ID. All other getters 65 * will fail and return the appropriate error value. Ie calling getSlotId(INVALID_SUB_ID) will 66 * return INVALID_SLOT_ID and calling getSubInfoForSubscriber(INVALID_SUB_ID) will return null. 67 * 68 */ 69public class SubscriptionController extends ISub.Stub { 70 static final String LOG_TAG = "SubController"; 71 static final boolean DBG = true; 72 static final boolean VDBG = false; 73 static final int MAX_LOCAL_LOG_LINES = 500; // TODO: Reduce to 100 when 17678050 is fixed 74 private ScLocalLog mLocalLog = new ScLocalLog(MAX_LOCAL_LOG_LINES); 75 76 /** 77 * Copied from android.util.LocalLog with flush() adding flush and line number 78 * TODO: Update LocalLog 79 */ 80 static class ScLocalLog { 81 82 private LinkedList<String> mLog; 83 private int mMaxLines; 84 private Time mNow; 85 86 public ScLocalLog(int maxLines) { 87 mLog = new LinkedList<String>(); 88 mMaxLines = maxLines; 89 mNow = new Time(); 90 } 91 92 public synchronized void log(String msg) { 93 if (mMaxLines > 0) { 94 int pid = android.os.Process.myPid(); 95 int tid = android.os.Process.myTid(); 96 mNow.setToNow(); 97 mLog.add(mNow.format("%m-%d %H:%M:%S") + " pid=" + pid + " tid=" + tid + " " + msg); 98 while (mLog.size() > mMaxLines) mLog.remove(); 99 } 100 } 101 102 public synchronized void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 103 final int LOOPS_PER_FLUSH = 10; // Flush every N loops. 104 Iterator<String> itr = mLog.listIterator(0); 105 int i = 0; 106 while (itr.hasNext()) { 107 pw.println(Integer.toString(i++) + ": " + itr.next()); 108 // Flush periodically so we don't drop lines 109 if ((i % LOOPS_PER_FLUSH) == 0) pw.flush(); 110 } 111 } 112 } 113 114 protected final Object mLock = new Object(); 115 protected boolean mSuccess; 116 117 /** The singleton instance. */ 118 private static SubscriptionController sInstance = null; 119 protected static PhoneProxy[] sProxyPhones; 120 protected Context mContext; 121 protected CallManager mCM; 122 123 private static final int RES_TYPE_BACKGROUND_DARK = 0; 124 private static final int RES_TYPE_BACKGROUND_LIGHT = 1; 125 126 private static final int[] sSimBackgroundDarkRes = setSimResource(RES_TYPE_BACKGROUND_DARK); 127 private static final int[] sSimBackgroundLightRes = setSimResource(RES_TYPE_BACKGROUND_LIGHT); 128 129 //FIXME this does not allow for multiple subs in a slot 130 private static HashMap<Integer, Integer> mSimInfo = new HashMap<Integer, Integer>(); 131 private static int mDefaultVoiceSubId = SubscriptionManager.INVALID_SUB_ID; 132 private static int mDefaultPhoneId = SubscriptionManager.DEFAULT_PHONE_ID; 133 134 private static final int EVENT_WRITE_MSISDN_DONE = 1; 135 136 protected Handler mHandler = new Handler() { 137 @Override 138 public void handleMessage(Message msg) { 139 AsyncResult ar; 140 141 switch (msg.what) { 142 case EVENT_WRITE_MSISDN_DONE: 143 ar = (AsyncResult) msg.obj; 144 synchronized (mLock) { 145 mSuccess = (ar.exception == null); 146 logd("EVENT_WRITE_MSISDN_DONE, mSuccess = "+mSuccess); 147 mLock.notifyAll(); 148 } 149 break; 150 } 151 } 152 }; 153 154 155 public static SubscriptionController init(Phone phone) { 156 synchronized (SubscriptionController.class) { 157 if (sInstance == null) { 158 sInstance = new SubscriptionController(phone); 159 } else { 160 Log.wtf(LOG_TAG, "init() called multiple times! sInstance = " + sInstance); 161 } 162 return sInstance; 163 } 164 } 165 166 public static SubscriptionController init(Context c, CommandsInterface[] ci) { 167 synchronized (SubscriptionController.class) { 168 if (sInstance == null) { 169 sInstance = new SubscriptionController(c); 170 } else { 171 Log.wtf(LOG_TAG, "init() called multiple times! sInstance = " + sInstance); 172 } 173 return sInstance; 174 } 175 } 176 177 public static SubscriptionController getInstance() { 178 if (sInstance == null) 179 { 180 Log.wtf(LOG_TAG, "getInstance null"); 181 } 182 183 return sInstance; 184 } 185 186 private SubscriptionController(Context c) { 187 mContext = c; 188 mCM = CallManager.getInstance(); 189 190 if(ServiceManager.getService("isub") == null) { 191 ServiceManager.addService("isub", this); 192 } 193 194 logdl("[SubscriptionController] init by Context"); 195 } 196 197 private boolean isSubInfoReady() { 198 return mSimInfo.size() > 0; 199 } 200 201 private SubscriptionController(Phone phone) { 202 mContext = phone.getContext(); 203 mCM = CallManager.getInstance(); 204 205 if(ServiceManager.getService("isub") == null) { 206 ServiceManager.addService("isub", this); 207 } 208 209 logdl("[SubscriptionController] init by Phone"); 210 } 211 212 /** 213 * Make sure the caller has the READ_PHONE_STATE permission. 214 * 215 * @throws SecurityException if the caller does not have the required permission 216 */ 217 private void enforceSubscriptionPermission() { 218 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.READ_PHONE_STATE, 219 "Requires READ_PHONE_STATE"); 220 } 221 222 /** 223 * Broadcast when subinfo settings has chanded 224 * @SubId The unique SubInfoRecord index in database 225 * @param columnName The column that is updated 226 * @param intContent The updated integer value 227 * @param stringContent The updated string value 228 */ 229 private void broadcastSimInfoContentChanged(int subId, 230 String columnName, int intContent, String stringContent) { 231 232 Intent intent = new Intent(TelephonyIntents.ACTION_SUBINFO_CONTENT_CHANGE); 233 intent.putExtra(BaseColumns._ID, subId); 234 intent.putExtra(TelephonyIntents.EXTRA_COLUMN_NAME, columnName); 235 intent.putExtra(TelephonyIntents.EXTRA_INT_CONTENT, intContent); 236 intent.putExtra(TelephonyIntents.EXTRA_STRING_CONTENT, stringContent); 237 if (intContent != SubscriptionManager.DEFAULT_INT_VALUE) { 238 logd("[broadcastSimInfoContentChanged] subId" + subId 239 + " changed, " + columnName + " -> " + intContent); 240 } else { 241 logd("[broadcastSimInfoContentChanged] subId" + subId 242 + " changed, " + columnName + " -> " + stringContent); 243 } 244 mContext.sendBroadcast(intent); 245 } 246 247 248 /** 249 * New SubInfoRecord instance and fill in detail info 250 * @param cursor 251 * @return the query result of desired SubInfoRecord 252 */ 253 private SubInfoRecord getSubInfoRecord(Cursor cursor) { 254 int id = cursor.getInt(cursor.getColumnIndexOrThrow(BaseColumns._ID)); 255 String iccId = cursor.getString(cursor.getColumnIndexOrThrow( 256 SubscriptionManager.ICC_ID)); 257 int simSlotIndex = cursor.getInt(cursor.getColumnIndexOrThrow( 258 SubscriptionManager.SIM_ID)); 259 String displayName = cursor.getString(cursor.getColumnIndexOrThrow( 260 SubscriptionManager.DISPLAY_NAME)); 261 int nameSource = cursor.getInt(cursor.getColumnIndexOrThrow( 262 SubscriptionManager.NAME_SOURCE)); 263 int color = cursor.getInt(cursor.getColumnIndexOrThrow( 264 SubscriptionManager.COLOR)); 265 String number = cursor.getString(cursor.getColumnIndexOrThrow( 266 SubscriptionManager.NUMBER)); 267 int dataRoaming = cursor.getInt(cursor.getColumnIndexOrThrow( 268 SubscriptionManager.DATA_ROAMING)); 269 270 int[] simIconRes = new int[2]; 271 int size = sSimBackgroundDarkRes.length; 272 if (color >= 0 && color < size) { 273 simIconRes[RES_TYPE_BACKGROUND_DARK] = sSimBackgroundDarkRes[color]; 274 simIconRes[RES_TYPE_BACKGROUND_LIGHT] = sSimBackgroundLightRes[color]; 275 } 276 int mcc = cursor.getInt(cursor.getColumnIndexOrThrow( 277 SubscriptionManager.MCC)); 278 int mnc = cursor.getInt(cursor.getColumnIndexOrThrow( 279 SubscriptionManager.MNC)); 280 281 logd("[getSubInfoRecord] id:" + id + " iccid:" + iccId + " simSlotIndex:" + simSlotIndex 282 + " displayName:" + displayName + " color:" + color + " mcc:" + mcc 283 + " mnc:" + mnc); 284 285 return new SubInfoRecord(id, iccId, simSlotIndex, displayName, nameSource, color, 286 number, dataRoaming, simIconRes, mcc, mnc); 287 } 288 289 /** 290 * Query SubInfoRecord(s) from subinfo database 291 * @param selection A filter declaring which rows to return 292 * @param queryKey query key content 293 * @return Array list of queried result from database 294 */ 295 private List<SubInfoRecord> getSubInfo(String selection, Object queryKey) { 296 logd("selection:" + selection + " " + queryKey); 297 String[] selectionArgs = null; 298 if (queryKey != null) { 299 selectionArgs = new String[] {queryKey.toString()}; 300 } 301 ArrayList<SubInfoRecord> subList = null; 302 Cursor cursor = mContext.getContentResolver().query(SubscriptionManager.CONTENT_URI, 303 null, selection, selectionArgs, null); 304 try { 305 if (cursor != null) { 306 while (cursor.moveToNext()) { 307 SubInfoRecord subInfo = getSubInfoRecord(cursor); 308 if (subInfo != null) 309 { 310 if (subList == null) 311 { 312 subList = new ArrayList<SubInfoRecord>(); 313 } 314 subList.add(subInfo); 315 } 316 } 317 } else { 318 logd("Query fail"); 319 } 320 } finally { 321 if (cursor != null) { 322 cursor.close(); 323 } 324 } 325 326 return subList; 327 } 328 329 330 331 /** 332 * Get the SubInfoRecord according to an index 333 * @param subId The unique SubInfoRecord index in database 334 * @return SubInfoRecord, maybe null 335 */ 336 @Override 337 public SubInfoRecord getSubInfoForSubscriber(int subId) { 338 logd("[getSubInfoForSubscriberx]+ subId:" + subId); 339 enforceSubscriptionPermission(); 340 341 if (subId == SubscriptionManager.DEFAULT_SUB_ID) { 342 subId = getDefaultSubId(); 343 } 344 if (!SubscriptionManager.isValidSubId(subId) || !isSubInfoReady()) { 345 logd("[getSubInfoForSubscriberx]- invalid subId or not ready"); 346 return null; 347 } 348 Cursor cursor = mContext.getContentResolver().query(SubscriptionManager.CONTENT_URI, 349 null, BaseColumns._ID + "=?", new String[] {Long.toString(subId)}, null); 350 try { 351 if (cursor != null) { 352 if (cursor.moveToFirst()) { 353 logd("[getSubInfoForSubscriberx]- Info detail:"); 354 return getSubInfoRecord(cursor); 355 } 356 } 357 } finally { 358 if (cursor != null) { 359 cursor.close(); 360 } 361 } 362 logd("[getSubInfoForSubscriber]- null info return"); 363 364 return null; 365 } 366 367 /** 368 * Get the SubInfoRecord according to an IccId 369 * @param iccId the IccId of SIM card 370 * @return SubInfoRecord, maybe null 371 */ 372 @Override 373 public List<SubInfoRecord> getSubInfoUsingIccId(String iccId) { 374 logd("[getSubInfoUsingIccId]+ iccId:" + iccId); 375 enforceSubscriptionPermission(); 376 377 if (iccId == null || !isSubInfoReady()) { 378 logd("[getSubInfoUsingIccId]- null iccid or not ready"); 379 return null; 380 } 381 Cursor cursor = mContext.getContentResolver().query(SubscriptionManager.CONTENT_URI, 382 null, SubscriptionManager.ICC_ID + "=?", new String[] {iccId}, null); 383 ArrayList<SubInfoRecord> subList = null; 384 try { 385 if (cursor != null) { 386 while (cursor.moveToNext()) { 387 SubInfoRecord subInfo = getSubInfoRecord(cursor); 388 if (subInfo != null) 389 { 390 if (subList == null) 391 { 392 subList = new ArrayList<SubInfoRecord>(); 393 } 394 subList.add(subInfo); 395 } 396 } 397 } else { 398 logd("Query fail"); 399 } 400 } finally { 401 if (cursor != null) { 402 cursor.close(); 403 } 404 } 405 406 return subList; 407 } 408 409 /** 410 * Get the SubInfoRecord according to slotId 411 * @param slotId the slot which the SIM is inserted 412 * @return SubInfoRecord, maybe null 413 */ 414 @Override 415 public List<SubInfoRecord> getSubInfoUsingSlotId(int slotId) { 416 return getSubInfoUsingSlotIdWithCheck(slotId, true); 417 } 418 419 /** 420 * Get all the SubInfoRecord(s) in subinfo database 421 * @return Array list of all SubInfoRecords in database, include thsoe that were inserted before 422 */ 423 @Override 424 public List<SubInfoRecord> getAllSubInfoList() { 425 logd("[getAllSubInfoList]+"); 426 enforceSubscriptionPermission(); 427 428 List<SubInfoRecord> subList = null; 429 subList = getSubInfo(null, null); 430 if (subList != null) { 431 logd("[getAllSubInfoList]- " + subList.size() + " infos return"); 432 } else { 433 logd("[getAllSubInfoList]- no info return"); 434 } 435 436 return subList; 437 } 438 439 /** 440 * Get the SubInfoRecord(s) of the currently inserted SIM(s) 441 * @return Array list of currently inserted SubInfoRecord(s) 442 */ 443 @Override 444 public List<SubInfoRecord> getActiveSubInfoList() { 445 enforceSubscriptionPermission(); 446 logdl("[getActiveSubInfoList]+"); 447 448 List<SubInfoRecord> subList = null; 449 450 if (!isSubInfoReady()) { 451 logdl("[getActiveSubInfoList] Sub Controller not ready"); 452 return subList; 453 } 454 455 subList = getSubInfo(SubscriptionManager.SIM_ID 456 + "!=" + SubscriptionManager.INVALID_SLOT_ID, null); 457 if (subList != null) { 458 logdl("[getActiveSubInfoList]- " + subList.size() + " infos return"); 459 } else { 460 logdl("[getActiveSubInfoList]- no info return"); 461 } 462 463 return subList; 464 } 465 466 /** 467 * Get the SUB count of active SUB(s) 468 * @return active SIM count 469 */ 470 @Override 471 public int getActiveSubInfoCount() { 472 logd("[getActiveSubInfoCount]+"); 473 List<SubInfoRecord> records = getActiveSubInfoList(); 474 if (records == null) { 475 logd("[getActiveSubInfoCount] records null"); 476 return 0; 477 } 478 logd("[getActiveSubInfoCount]- count: " + records.size()); 479 return records.size(); 480 } 481 482 /** 483 * Get the SUB count of all SUB(s) in subinfo database 484 * @return all SIM count in database, include what was inserted before 485 */ 486 @Override 487 public int getAllSubInfoCount() { 488 logd("[getAllSubInfoCount]+"); 489 enforceSubscriptionPermission(); 490 491 Cursor cursor = mContext.getContentResolver().query(SubscriptionManager.CONTENT_URI, 492 null, null, null, null); 493 try { 494 if (cursor != null) { 495 int count = cursor.getCount(); 496 logd("[getAllSubInfoCount]- " + count + " SUB(s) in DB"); 497 return count; 498 } 499 } finally { 500 if (cursor != null) { 501 cursor.close(); 502 } 503 } 504 logd("[getAllSubInfoCount]- no SUB in DB"); 505 506 return 0; 507 } 508 509 /** 510 * Add a new SubInfoRecord to subinfo database if needed 511 * @param iccId the IccId of the SIM card 512 * @param slotId the slot which the SIM is inserted 513 * @return the URL of the newly created row or the updated row 514 */ 515 @Override 516 public int addSubInfoRecord(String iccId, int slotId) { 517 logdl("[addSubInfoRecord]+ iccId:" + iccId + " slotId:" + slotId); 518 enforceSubscriptionPermission(); 519 520 if (iccId == null) { 521 logdl("[addSubInfoRecord]- null iccId"); 522 } 523 524 int[] subIds = getSubId(slotId); 525 if (subIds == null || subIds.length == 0) { 526 logdl("[addSubInfoRecord]- getSubId fail"); 527 return 0; 528 } 529 530 String nameToSet; 531 SpnOverride mSpnOverride = new SpnOverride(); 532 533 String CarrierName = TelephonyManager.getDefault().getSimOperator(subIds[0]); 534 logdl("[addSubInfoRecord] CarrierName = " + CarrierName); 535 536 if (mSpnOverride.containsCarrier(CarrierName)) { 537 nameToSet = mSpnOverride.getSpn(CarrierName) + " 0" + Integer.toString(slotId + 1); 538 logdl("[addSubInfoRecord] SpnOverride set name=" + nameToSet); 539 } else { 540 nameToSet = ""; 541 logdl("[addSubInfoRecord] no SpnOverride"); 542 } 543 544 ContentResolver resolver = mContext.getContentResolver(); 545 Cursor cursor = resolver.query(SubscriptionManager.CONTENT_URI, 546 new String[] {BaseColumns._ID, SubscriptionManager.SIM_ID, 547 SubscriptionManager.NAME_SOURCE}, SubscriptionManager.ICC_ID + "=?", 548 new String[] {iccId}, null); 549 550 try { 551 if (cursor == null || !cursor.moveToFirst()) { 552 ContentValues value = new ContentValues(); 553 value.put(SubscriptionManager.ICC_ID, iccId); 554 // default SIM color differs between slots 555 value.put(SubscriptionManager.COLOR, slotId); 556 value.put(SubscriptionManager.SIM_ID, slotId); 557 value.put(SubscriptionManager.DISPLAY_NAME, nameToSet); 558 Uri uri = resolver.insert(SubscriptionManager.CONTENT_URI, value); 559 logdl("[addSubInfoRecord]- New record created: " + uri); 560 } else { 561 int subId = cursor.getInt(0); 562 int oldSimInfoId = cursor.getInt(1); 563 int nameSource = cursor.getInt(2); 564 ContentValues value = new ContentValues(); 565 566 if (slotId != oldSimInfoId) { 567 value.put(SubscriptionManager.SIM_ID, slotId); 568 } 569 570 if (nameSource != SubscriptionManager.NAME_SOURCE_USER_INPUT) { 571 value.put(SubscriptionManager.DISPLAY_NAME, nameToSet); 572 } 573 574 if (value.size() > 0) { 575 resolver.update(SubscriptionManager.CONTENT_URI, value, 576 BaseColumns._ID + "=" + Long.toString(subId), null); 577 } 578 579 logdl("[addSubInfoRecord]- Record already exist"); 580 } 581 } finally { 582 if (cursor != null) { 583 cursor.close(); 584 } 585 } 586 587 cursor = resolver.query(SubscriptionManager.CONTENT_URI, null, 588 SubscriptionManager.SIM_ID + "=?", new String[] {String.valueOf(slotId)}, null); 589 590 try { 591 if (cursor != null && cursor.moveToFirst()) { 592 do { 593 int subId = cursor.getInt(cursor.getColumnIndexOrThrow(BaseColumns._ID)); 594 // If mSimInfo already has a valid subId for a slotId/phoneId, 595 // do not add another subId for same slotId/phoneId. 596 Integer currentSubId = mSimInfo.get(slotId); 597 if (currentSubId == null || !SubscriptionManager.isValidSubId(currentSubId)) { 598 // TODO While two subs active, if user deactivats first 599 // one, need to update the default subId with second one. 600 601 // FIXME: Currently we assume phoneId and slotId may not be true 602 // when we cross map modem or when multiple subs per slot. 603 // But is true at the moment. 604 mSimInfo.put(slotId, subId); 605 int simCount = TelephonyManager.getDefault().getSimCount(); 606 int defaultSubId = getDefaultSubId(); 607 logdl("[addSubInfoRecord] mSimInfo.size=" + mSimInfo.size() 608 + " slotId=" + slotId + " subId=" + subId 609 + " defaultSubId=" + defaultSubId + " simCount=" + simCount); 610 611 // Set the default sub if not set or if single sim device 612 if (!SubscriptionManager.isValidSubId(defaultSubId) || simCount == 1) { 613 setDefaultSubId(subId); 614 } 615 // If single sim device, set this subscription as the default for everything 616 if (simCount == 1) { 617 logdl("[addSubInfoRecord] one sim set defaults to subId=" + subId); 618 setDefaultDataSubId(subId); 619 setDefaultSmsSubId(subId); 620 setDefaultVoiceSubId(subId); 621 } 622 } else { 623 logdl("[addSubInfoRecord] currentSubId != null && currentSubId is valid, IGNORE"); 624 } 625 logdl("[addSubInfoRecord]- hashmap("+slotId+","+subId+")"); 626 } while (cursor.moveToNext()); 627 } 628 } finally { 629 if (cursor != null) { 630 cursor.close(); 631 } 632 } 633 634 int size = mSimInfo.size(); 635 logdl("[addSubInfoRecord]- info size="+size); 636 637 // Once the records are loaded, notify DcTracker 638 updateAllDataConnectionTrackers(); 639 640 // FIXME this does not match the javadoc 641 return 1; 642 } 643 644 /** 645 * Set SIM color by simInfo index 646 * @param color the color of the SIM 647 * @param subId the unique SubInfoRecord index in database 648 * @return the number of records updated 649 */ 650 @Override 651 public int setColor(int color, int subId) { 652 logd("[setColor]+ color:" + color + " subId:" + subId); 653 enforceSubscriptionPermission(); 654 655 validateSubId(subId); 656 int size = sSimBackgroundDarkRes.length; 657 ContentValues value = new ContentValues(1); 658 value.put(SubscriptionManager.COLOR, color); 659 logd("[setColor]- color:" + color + " set"); 660 661 int result = mContext.getContentResolver().update(SubscriptionManager.CONTENT_URI, value, 662 BaseColumns._ID + "=" + Long.toString(subId), null); 663 broadcastSimInfoContentChanged(subId, SubscriptionManager.COLOR, 664 color, SubscriptionManager.DEFAULT_STRING_VALUE); 665 666 return result; 667 } 668 669 /** 670 * Set display name by simInfo index 671 * @param displayName the display name of SIM card 672 * @param subId the unique SubInfoRecord index in database 673 * @return the number of records updated 674 */ 675 @Override 676 public int setDisplayName(String displayName, int subId) { 677 return setDisplayNameUsingSrc(displayName, subId, -1); 678 } 679 680 /** 681 * Set display name by simInfo index with name source 682 * @param displayName the display name of SIM card 683 * @param subId the unique SubInfoRecord index in database 684 * @param nameSource 0: NAME_SOURCE_DEFAULT_SOURCE, 1: NAME_SOURCE_SIM_SOURCE, 685 * 2: NAME_SOURCE_USER_INPUT, -1 NAME_SOURCE_UNDEFINED 686 * @return the number of records updated 687 */ 688 @Override 689 public int setDisplayNameUsingSrc(String displayName, int subId, long nameSource) { 690 logd("[setDisplayName]+ displayName:" + displayName + " subId:" + subId 691 + " nameSource:" + nameSource); 692 enforceSubscriptionPermission(); 693 694 validateSubId(subId); 695 String nameToSet; 696 if (displayName == null) { 697 nameToSet = mContext.getString(SubscriptionManager.DEFAULT_NAME_RES); 698 } else { 699 nameToSet = displayName; 700 } 701 ContentValues value = new ContentValues(1); 702 value.put(SubscriptionManager.DISPLAY_NAME, nameToSet); 703 if (nameSource >= SubscriptionManager.NAME_SOURCE_DEFAULT_SOURCE) { 704 logd("Set nameSource=" + nameSource); 705 value.put(SubscriptionManager.NAME_SOURCE, nameSource); 706 } 707 logd("[setDisplayName]- mDisplayName:" + nameToSet + " set"); 708 709 int result = mContext.getContentResolver().update(SubscriptionManager.CONTENT_URI, value, 710 BaseColumns._ID + "=" + Long.toString(subId), null); 711 broadcastSimInfoContentChanged(subId, SubscriptionManager.DISPLAY_NAME, 712 SubscriptionManager.DEFAULT_INT_VALUE, nameToSet); 713 714 return result; 715 } 716 717 /** 718 * Set phone number by subId 719 * @param number the phone number of the SIM 720 * @param subId the unique SubInfoRecord index in database 721 * @return the number of records updated 722 */ 723 @Override 724 public int setDisplayNumber(String number, int subId) { 725 logd("[setDisplayNumber]+ number:" + number + " subId:" + subId); 726 enforceSubscriptionPermission(); 727 728 validateSubId(subId); 729 int result = 0; 730 int phoneId = getPhoneId(subId); 731 732 if (number == null || phoneId < 0 || 733 phoneId >= TelephonyManager.getDefault().getPhoneCount()) { 734 logd("[setDispalyNumber]- fail"); 735 return -1; 736 } 737 ContentValues value = new ContentValues(1); 738 value.put(SubscriptionManager.NUMBER, number); 739 logd("[setDisplayNumber]- number:" + number + " set"); 740 741 Phone phone = sProxyPhones[phoneId]; 742 String alphaTag = TelephonyManager.getDefault().getLine1AlphaTagForSubscriber(subId); 743 744 synchronized(mLock) { 745 mSuccess = false; 746 Message response = mHandler.obtainMessage(EVENT_WRITE_MSISDN_DONE); 747 748 phone.setLine1Number(alphaTag, number, response); 749 750 try { 751 mLock.wait(); 752 } catch (InterruptedException e) { 753 loge("interrupted while trying to write MSISDN"); 754 } 755 } 756 757 if (mSuccess) { 758 result = mContext.getContentResolver().update(SubscriptionManager.CONTENT_URI, value, 759 BaseColumns._ID + "=" + Long.toString(subId), null); 760 logd("[setDisplayNumber]- update result :" + result); 761 broadcastSimInfoContentChanged(subId, SubscriptionManager.NUMBER, 762 SubscriptionManager.DEFAULT_INT_VALUE, number); 763 } 764 765 return result; 766 } 767 768 /** 769 * Set number display format. 0: none, 1: the first four digits, 2: the last four digits 770 * @param format the display format of phone number 771 * @param subId the unique SubInfoRecord index in database 772 * @return the number of records updated 773 */ 774 @Override 775 public int setDisplayNumberFormat(int format, int subId) { 776 logd("[setDisplayNumberFormat]+ format:" + format + " subId:" + subId); 777 enforceSubscriptionPermission(); 778 779 validateSubId(subId); 780 if (format < 0) { 781 logd("[setDisplayNumberFormat]- fail, return -1"); 782 return -1; 783 } 784 ContentValues value = new ContentValues(1); 785 value.put(SubscriptionManager.DISPLAY_NUMBER_FORMAT, format); 786 logd("[setDisplayNumberFormat]- format:" + format + " set"); 787 788 int result = mContext.getContentResolver().update(SubscriptionManager.CONTENT_URI, value, 789 BaseColumns._ID + "=" + Long.toString(subId), null); 790 broadcastSimInfoContentChanged(subId, SubscriptionManager.DISPLAY_NUMBER_FORMAT, 791 format, SubscriptionManager.DEFAULT_STRING_VALUE); 792 793 return result; 794 } 795 796 /** 797 * Set data roaming by simInfo index 798 * @param roaming 0:Don't allow data when roaming, 1:Allow data when roaming 799 * @param subId the unique SubInfoRecord index in database 800 * @return the number of records updated 801 */ 802 @Override 803 public int setDataRoaming(int roaming, int subId) { 804 logd("[setDataRoaming]+ roaming:" + roaming + " subId:" + subId); 805 enforceSubscriptionPermission(); 806 807 validateSubId(subId); 808 if (roaming < 0) { 809 logd("[setDataRoaming]- fail"); 810 return -1; 811 } 812 ContentValues value = new ContentValues(1); 813 value.put(SubscriptionManager.DATA_ROAMING, roaming); 814 logd("[setDataRoaming]- roaming:" + roaming + " set"); 815 816 int result = mContext.getContentResolver().update(SubscriptionManager.CONTENT_URI, value, 817 BaseColumns._ID + "=" + Long.toString(subId), null); 818 broadcastSimInfoContentChanged(subId, SubscriptionManager.DATA_ROAMING, 819 roaming, SubscriptionManager.DEFAULT_STRING_VALUE); 820 821 return result; 822 } 823 824 /** 825 * Set MCC/MNC by subscription ID 826 * @param mccMnc MCC/MNC associated with the subscription 827 * @param subId the unique SubInfoRecord index in database 828 * @return the number of records updated 829 */ 830 public int setMccMnc(String mccMnc, int subId) { 831 int mcc = 0; 832 int mnc = 0; 833 try { 834 mcc = Integer.parseInt(mccMnc.substring(0,3)); 835 mnc = Integer.parseInt(mccMnc.substring(3)); 836 } catch (NumberFormatException e) { 837 logd("[setMccMnc] - couldn't parse mcc/mnc: " + mccMnc); 838 } 839 logd("[setMccMnc]+ mcc/mnc:" + mcc + "/" + mnc + " subId:" + subId); 840 ContentValues value = new ContentValues(2); 841 value.put(SubscriptionManager.MCC, mcc); 842 value.put(SubscriptionManager.MNC, mnc); 843 844 int result = mContext.getContentResolver().update(SubscriptionManager.CONTENT_URI, value, 845 BaseColumns._ID + "=" + Long.toString(subId), null); 846 broadcastSimInfoContentChanged(subId, SubscriptionManager.MCC, mcc, null); 847 848 return result; 849 } 850 851 852 @Override 853 public int getSlotId(int subId) { 854 if (VDBG) printStackTrace("[getSlotId] subId=" + subId); 855 856 if (subId == SubscriptionManager.DEFAULT_SUB_ID) { 857 subId = getDefaultSubId(); 858 } 859 if (!SubscriptionManager.isValidSubId(subId)) { 860 logd("[getSlotId]- subId invalid"); 861 return SubscriptionManager.INVALID_SLOT_ID; 862 } 863 864 int size = mSimInfo.size(); 865 866 if (size == 0) 867 { 868 logd("[getSlotId]- size == 0, return SIM_NOT_INSERTED instead"); 869 return SubscriptionManager.SIM_NOT_INSERTED; 870 } 871 872 for (Entry<Integer, Integer> entry: mSimInfo.entrySet()) { 873 int sim = entry.getKey(); 874 int sub = entry.getValue(); 875 876 if (subId == sub) 877 { 878 if (VDBG) logv("[getSlotId]- return = " + sim); 879 return sim; 880 } 881 } 882 883 logd("[getSlotId]- return fail"); 884 return SubscriptionManager.INVALID_SLOT_ID; 885 } 886 887 /** 888 * Return the subId for specified slot Id. 889 * @deprecated 890 */ 891 @Override 892 @Deprecated 893 public int[] getSubId(int slotId) { 894 if (VDBG) printStackTrace("[getSubId] slotId=" + slotId); 895 896 if (slotId == SubscriptionManager.DEFAULT_SLOT_ID) { 897 logd("[getSubId]- default slotId"); 898 slotId = getSlotId(getDefaultSubId()); 899 } 900 901 //FIXME remove this 902 final int[] DUMMY_VALUES = {-1 - slotId, -1 - slotId}; 903 904 if (!SubscriptionManager.isValidSlotId(slotId)) { 905 logd("[getSubId]- invalid slotId"); 906 return null; 907 } 908 909 //FIXME remove this 910 if (slotId < 0) { 911 logd("[getSubId]- slotId < 0, return dummy instead"); 912 return DUMMY_VALUES; 913 } 914 915 int size = mSimInfo.size(); 916 917 if (size == 0) { 918 logd("[getSubId]- size == 0, return dummy instead"); 919 //FIXME return null 920 return DUMMY_VALUES; 921 } 922 923 ArrayList<Integer> subIds = new ArrayList<Integer>(); 924 for (Entry<Integer, Integer> entry: mSimInfo.entrySet()) { 925 int slot = entry.getKey(); 926 int sub = entry.getValue(); 927 if (slotId == slot) { 928 subIds.add(sub); 929 } 930 } 931 932 if (VDBG) logd("[getSubId]-, subIds = " + subIds); 933 int numSubIds = subIds.size(); 934 935 if (numSubIds == 0) { 936 logd("[getSubId]- numSubIds == 0, return dummy instead"); 937 return DUMMY_VALUES; 938 } 939 940 int[] subIdArr = new int[numSubIds]; 941 for (int i = 0; i < numSubIds; i++) { 942 subIdArr[i] = subIds.get(i); 943 } 944 945 return subIdArr; 946 } 947 948 @Override 949 public int getPhoneId(int subId) { 950 if (VDBG) printStackTrace("[getPhoneId] subId=" + subId); 951 int phoneId; 952 953 if (subId == SubscriptionManager.DEFAULT_SUB_ID) { 954 subId = getDefaultSubId(); 955 logdl("[getPhoneId] asked for default subId=" + subId); 956 } 957 958 if (!SubscriptionManager.isValidSubId(subId)) { 959 logdl("[getPhoneId]- invalid subId return=" + SubscriptionManager.INVALID_PHONE_ID); 960 return SubscriptionManager.INVALID_PHONE_ID; 961 } 962 963 //FIXME remove this 964 if (subId < 0) { 965 phoneId = (int) (-1 - subId); 966 if (VDBG) logdl("[getPhoneId]- map subId=" + subId + " phoneId=" + phoneId); 967 return phoneId; 968 } 969 970 int size = mSimInfo.size(); 971 972 if (size == 0) { 973 phoneId = mDefaultPhoneId; 974 logdl("[getPhoneId]- no sims, returning default phoneId=" + phoneId); 975 return phoneId; 976 } 977 978 // FIXME: Assumes phoneId == slotId 979 for (Entry<Integer, Integer> entry: mSimInfo.entrySet()) { 980 int sim = entry.getKey(); 981 int sub = entry.getValue(); 982 983 if (subId == sub) { 984 if (VDBG) logdl("[getPhoneId]- found subId=" + subId + " phoneId=" + sim); 985 return sim; 986 } 987 } 988 989 phoneId = mDefaultPhoneId; 990 logdl("[getPhoneId]- subId=" + subId + " not found return default phoneId=" + phoneId); 991 return phoneId; 992 993 } 994 995 /** 996 * @return the number of records cleared 997 */ 998 @Override 999 public int clearSubInfo() { 1000 enforceSubscriptionPermission(); 1001 logd("[clearSubInfo]+"); 1002 1003 int size = mSimInfo.size(); 1004 1005 if (size == 0) { 1006 logdl("[clearSubInfo]- no simInfo size=" + size); 1007 return 0; 1008 } 1009 1010 mSimInfo.clear(); 1011 logdl("[clearSubInfo]- clear size=" + size); 1012 return size; 1013 } 1014 1015 private static int[] setSimResource(int type) { 1016 int[] simResource = null; 1017 1018 switch (type) { 1019 case RES_TYPE_BACKGROUND_DARK: 1020 simResource = new int[] { 1021 com.android.internal.R.drawable.sim_dark_blue, 1022 com.android.internal.R.drawable.sim_dark_orange, 1023 com.android.internal.R.drawable.sim_dark_green, 1024 com.android.internal.R.drawable.sim_dark_purple 1025 }; 1026 break; 1027 case RES_TYPE_BACKGROUND_LIGHT: 1028 simResource = new int[] { 1029 com.android.internal.R.drawable.sim_light_blue, 1030 com.android.internal.R.drawable.sim_light_orange, 1031 com.android.internal.R.drawable.sim_light_green, 1032 com.android.internal.R.drawable.sim_light_purple 1033 }; 1034 break; 1035 } 1036 1037 return simResource; 1038 } 1039 1040 private void logvl(String msg) { 1041 logv(msg); 1042 mLocalLog.log(msg); 1043 } 1044 1045 private void logv(String msg) { 1046 Rlog.v(LOG_TAG, msg); 1047 } 1048 1049 private void logdl(String msg) { 1050 logd(msg); 1051 mLocalLog.log(msg); 1052 } 1053 1054 private static void slogd(String msg) { 1055 Rlog.d(LOG_TAG, msg); 1056 } 1057 1058 private void logd(String msg) { 1059 Rlog.d(LOG_TAG, msg); 1060 } 1061 1062 private void logel(String msg) { 1063 loge(msg); 1064 mLocalLog.log(msg); 1065 } 1066 1067 private void loge(String msg) { 1068 Rlog.e(LOG_TAG, msg); 1069 } 1070 1071 @Override 1072 public int getDefaultSubId() { 1073 //FIXME: Make this smarter, need to handle data only and voice devices 1074 int subId = mDefaultVoiceSubId; 1075 if (VDBG) logv("[getDefaultSubId] value = " + subId); 1076 return subId; 1077 } 1078 1079 @Override 1080 public void setDefaultSmsSubId(int subId) { 1081 if (subId == SubscriptionManager.DEFAULT_SUB_ID) { 1082 throw new RuntimeException("setDefaultSmsSubId called with DEFAULT_SUB_ID"); 1083 } 1084 logdl("[setDefaultSmsSubId] subId=" + subId); 1085 Settings.Global.putInt(mContext.getContentResolver(), 1086 Settings.Global.MULTI_SIM_SMS_SUBSCRIPTION, subId); 1087 broadcastDefaultSmsSubIdChanged(subId); 1088 } 1089 1090 private void broadcastDefaultSmsSubIdChanged(int subId) { 1091 // Broadcast an Intent for default sms sub change 1092 logdl("[broadcastDefaultSmsSubIdChanged] subId=" + subId); 1093 Intent intent = new Intent(TelephonyIntents.ACTION_DEFAULT_SMS_SUBSCRIPTION_CHANGED); 1094 intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING); 1095 intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId); 1096 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); 1097 } 1098 1099 @Override 1100 public int getDefaultSmsSubId() { 1101 int subId = Settings.Global.getInt(mContext.getContentResolver(), 1102 Settings.Global.MULTI_SIM_SMS_SUBSCRIPTION, 1103 SubscriptionManager.INVALID_SUB_ID); 1104 if (VDBG) logd("[getDefaultSmsSubId] subId=" + subId); 1105 return subId; 1106 } 1107 1108 @Override 1109 public void setDefaultVoiceSubId(int subId) { 1110 if (subId == SubscriptionManager.DEFAULT_SUB_ID) { 1111 throw new RuntimeException("setDefaultVoiceSubId called with DEFAULT_SUB_ID"); 1112 } 1113 logdl("[setDefaultVoiceSubId] subId=" + subId); 1114 Settings.Global.putInt(mContext.getContentResolver(), 1115 Settings.Global.MULTI_SIM_VOICE_CALL_SUBSCRIPTION, subId); 1116 broadcastDefaultVoiceSubIdChanged(subId); 1117 } 1118 1119 private void broadcastDefaultVoiceSubIdChanged(int subId) { 1120 // Broadcast an Intent for default voice sub change 1121 logdl("[broadcastDefaultVoiceSubIdChanged] subId=" + subId); 1122 Intent intent = new Intent(TelephonyIntents.ACTION_DEFAULT_VOICE_SUBSCRIPTION_CHANGED); 1123 intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING); 1124 intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId); 1125 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); 1126 } 1127 1128 @Override 1129 public int getDefaultVoiceSubId() { 1130 int subId = Settings.Global.getInt(mContext.getContentResolver(), 1131 Settings.Global.MULTI_SIM_VOICE_CALL_SUBSCRIPTION, 1132 SubscriptionManager.INVALID_SUB_ID); 1133 if (VDBG) logd("[getDefaultVoiceSubId] subId=" + subId); 1134 return subId; 1135 } 1136 1137 @Override 1138 public int getDefaultDataSubId() { 1139 int subId = Settings.Global.getInt(mContext.getContentResolver(), 1140 Settings.Global.MULTI_SIM_DATA_CALL_SUBSCRIPTION, 1141 SubscriptionManager.INVALID_SUB_ID); 1142 if (VDBG) logd("[getDefaultDataSubId] subId= " + subId); 1143 return subId; 1144 } 1145 1146 @Override 1147 public void setDefaultDataSubId(int subId) { 1148 if (subId == SubscriptionManager.DEFAULT_SUB_ID) { 1149 throw new RuntimeException("setDefaultDataSubId called with DEFAULT_SUB_ID"); 1150 } 1151 logdl("[setDefaultDataSubId] subId=" + subId); 1152 1153 Settings.Global.putInt(mContext.getContentResolver(), 1154 Settings.Global.MULTI_SIM_DATA_CALL_SUBSCRIPTION, subId); 1155 broadcastDefaultDataSubIdChanged(subId); 1156 1157 // FIXME is this still needed? 1158 updateAllDataConnectionTrackers(); 1159 } 1160 1161 private void updateAllDataConnectionTrackers() { 1162 // Tell Phone Proxies to update data connection tracker 1163 int len = sProxyPhones.length; 1164 logdl("[updateAllDataConnectionTrackers] sProxyPhones.length=" + len); 1165 for (int phoneId = 0; phoneId < len; phoneId++) { 1166 logdl("[updateAllDataConnectionTrackers] phoneId=" + phoneId); 1167 sProxyPhones[phoneId].updateDataConnectionTracker(); 1168 } 1169 } 1170 1171 private void broadcastDefaultDataSubIdChanged(int subId) { 1172 // Broadcast an Intent for default data sub change 1173 logdl("[broadcastDefaultDataSubIdChanged] subId=" + subId); 1174 Intent intent = new Intent(TelephonyIntents.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED); 1175 intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING); 1176 intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId); 1177 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); 1178 } 1179 1180 /* Sets the default subscription. If only one sub is active that 1181 * sub is set as default subId. If two or more sub's are active 1182 * the first sub is set as default subscription 1183 */ 1184 // FIXME 1185 public void setDefaultSubId(int subId) { 1186 if (subId == SubscriptionManager.DEFAULT_SUB_ID) { 1187 throw new RuntimeException("setDefaultSubId called with DEFAULT_SUB_ID"); 1188 } 1189 logdl("[setDefaultSubId] subId=" + subId); 1190 if (SubscriptionManager.isValidSubId(subId)) { 1191 int phoneId = getPhoneId(subId); 1192 if (phoneId >= 0 && (phoneId < TelephonyManager.getDefault().getPhoneCount() 1193 || TelephonyManager.getDefault().getSimCount() == 1)) { 1194 logdl("[setDefaultSubId] set mDefaultVoiceSubId=" + subId); 1195 mDefaultVoiceSubId = subId; 1196 // Update MCC MNC device configuration information 1197 String defaultMccMnc = TelephonyManager.getDefault().getSimOperator(phoneId); 1198 MccTable.updateMccMncConfiguration(mContext, defaultMccMnc, false); 1199 1200 // Broadcast an Intent for default sub change 1201 Intent intent = new Intent(TelephonyIntents.ACTION_DEFAULT_SUBSCRIPTION_CHANGED); 1202 intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING); 1203 SubscriptionManager.putPhoneIdAndSubIdExtra(intent, phoneId, subId); 1204 if (VDBG) { 1205 logdl("[setDefaultSubId] broadcast default subId changed phoneId=" + phoneId 1206 + " subId=" + subId); 1207 } 1208 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); 1209 } else { 1210 if (VDBG) { 1211 logdl("[setDefaultSubId] not set invalid phoneId=" + phoneId + " subId=" + subId); 1212 } 1213 } 1214 } 1215 } 1216 1217 @Override 1218 public void clearDefaultsForInactiveSubIds() { 1219 final List<SubInfoRecord> records = getActiveSubInfoList(); 1220 logdl("[clearDefaultsForInactiveSubIds] records: " + records); 1221 if (shouldDefaultBeCleared(records, getDefaultDataSubId())) { 1222 logd("[clearDefaultsForInactiveSubIds] clearing default data sub id"); 1223 setDefaultDataSubId(SubscriptionManager.INVALID_SUB_ID); 1224 } 1225 if (shouldDefaultBeCleared(records, getDefaultSmsSubId())) { 1226 logdl("[clearDefaultsForInactiveSubIds] clearing default sms sub id"); 1227 setDefaultSmsSubId(SubscriptionManager.INVALID_SUB_ID); 1228 } 1229 if (shouldDefaultBeCleared(records, getDefaultVoiceSubId())) { 1230 logdl("[clearDefaultsForInactiveSubIds] clearing default voice sub id"); 1231 setDefaultVoiceSubId(SubscriptionManager.INVALID_SUB_ID); 1232 } 1233 } 1234 1235 private boolean shouldDefaultBeCleared(List<SubInfoRecord> records, int subId) { 1236 logdl("[shouldDefaultBeCleared: subId] " + subId); 1237 if (records == null) { 1238 logdl("[shouldDefaultBeCleared] return true no records subId=" + subId); 1239 return true; 1240 } 1241 if (subId == SubscriptionManager.ASK_USER_SUB_ID && records.size() > 1) { 1242 // Only allow ASK_USER_SUB_ID if there is more than 1 subscription. 1243 logdl("[shouldDefaultBeCleared] return false only one subId, subId=" + subId); 1244 return false; 1245 } 1246 for (SubInfoRecord record : records) { 1247 int id = record.getSubscriptionId(); 1248 logdl("[shouldDefaultBeCleared] Record.id: " + id); 1249 if (id == subId) { 1250 logdl("[shouldDefaultBeCleared] return false subId is active, subId=" + subId); 1251 return false; 1252 } 1253 } 1254 logdl("[shouldDefaultBeCleared] return true not active subId=" + subId); 1255 return true; 1256 } 1257 1258 // FIXME: We need we should not be assuming phoneId == slotId as it will not be true 1259 // when there are multiple subscriptions per sim and probably for other reasons. 1260 public int getSubIdUsingPhoneId(int phoneId) { 1261 int[] subIds = getSubId(phoneId); 1262 if (subIds == null || subIds.length == 0) { 1263 return SubscriptionManager.INVALID_SUB_ID; 1264 } 1265 return subIds[0]; 1266 } 1267 1268 public int[] getSubIdUsingSlotId(int slotId) { 1269 return getSubId(slotId); 1270 } 1271 1272 public List<SubInfoRecord> getSubInfoUsingSlotIdWithCheck(int slotId, boolean needCheck) { 1273 logd("[getSubInfoUsingSlotIdWithCheck]+ slotId:" + slotId); 1274 enforceSubscriptionPermission(); 1275 1276 if (slotId == SubscriptionManager.DEFAULT_SLOT_ID) { 1277 slotId = getSlotId(getDefaultSubId()); 1278 } 1279 if (!SubscriptionManager.isValidSlotId(slotId)) { 1280 logd("[getSubInfoUsingSlotIdWithCheck]- invalid slotId"); 1281 return null; 1282 } 1283 1284 if (needCheck && !isSubInfoReady()) { 1285 logd("[getSubInfoUsingSlotIdWithCheck]- not ready"); 1286 return null; 1287 } 1288 1289 Cursor cursor = mContext.getContentResolver().query(SubscriptionManager.CONTENT_URI, 1290 null, SubscriptionManager.SIM_ID + "=?", new String[] {String.valueOf(slotId)}, null); 1291 ArrayList<SubInfoRecord> subList = null; 1292 try { 1293 if (cursor != null) { 1294 while (cursor.moveToNext()) { 1295 SubInfoRecord subInfo = getSubInfoRecord(cursor); 1296 if (subInfo != null) 1297 { 1298 if (subList == null) 1299 { 1300 subList = new ArrayList<SubInfoRecord>(); 1301 } 1302 subList.add(subInfo); 1303 } 1304 } 1305 } 1306 } finally { 1307 if (cursor != null) { 1308 cursor.close(); 1309 } 1310 } 1311 logd("[getSubInfoUsingSlotId]- null info return"); 1312 1313 return subList; 1314 } 1315 1316 private void validateSubId(int subId) { 1317 logd("validateSubId subId: " + subId); 1318 if (!SubscriptionManager.isValidSubId(subId)) { 1319 throw new RuntimeException("Invalid sub id passed as parameter"); 1320 } else if (subId == SubscriptionManager.DEFAULT_SUB_ID) { 1321 throw new RuntimeException("Default sub id passed as parameter"); 1322 } 1323 } 1324 1325 public void updatePhonesAvailability(PhoneProxy[] phones) { 1326 sProxyPhones = phones; 1327 } 1328 1329 /** 1330 * @return the list of subId's that are active, is never null but the length maybe 0. 1331 */ 1332 @Override 1333 public int[] getActiveSubIdList() { 1334 Set<Entry<Integer, Integer>> simInfoSet = mSimInfo.entrySet(); 1335 logdl("[getActiveSubIdList] simInfoSet=" + simInfoSet); 1336 1337 int[] subIdArr = new int[simInfoSet.size()]; 1338 int i = 0; 1339 for (Entry<Integer, Integer> entry: simInfoSet) { 1340 int sub = entry.getValue(); 1341 subIdArr[i] = sub; 1342 i++; 1343 } 1344 1345 logdl("[getActiveSubIdList] X subIdArr.length=" + subIdArr.length); 1346 return subIdArr; 1347 } 1348 1349 private static void printStackTrace(String msg) { 1350 RuntimeException re = new RuntimeException(); 1351 slogd("StackTrace - " + msg); 1352 StackTraceElement[] st = re.getStackTrace(); 1353 boolean first = true; 1354 for (StackTraceElement ste : st) { 1355 if (first) { 1356 first = false; 1357 } else { 1358 slogd(ste.toString()); 1359 } 1360 } 1361 } 1362 1363 @Override 1364 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 1365 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, 1366 "Requires DUMP"); 1367 pw.println("SubscriptionController:"); 1368 pw.println(" defaultSubId=" + getDefaultSubId()); 1369 pw.println(" defaultDataSubId=" + getDefaultDataSubId()); 1370 pw.println(" defaultVoiceSubId=" + getDefaultVoiceSubId()); 1371 pw.println(" defaultSmsSubId=" + getDefaultSmsSubId()); 1372 1373 pw.println(" defaultDataPhoneId=" + SubscriptionManager.getDefaultDataPhoneId()); 1374 pw.println(" defaultVoicePhoneId=" + SubscriptionManager.getDefaultVoicePhoneId()); 1375 pw.println(" defaultSmsPhoneId=" + SubscriptionManager.getDefaultSmsPhoneId()); 1376 pw.flush(); 1377 1378 for (Entry<Integer, Integer> entry : mSimInfo.entrySet()) { 1379 pw.println(" mSimInfo[" + entry.getKey() + "]: subId=" + entry.getValue()); 1380 } 1381 pw.flush(); 1382 pw.println("++++++++++++++++++++++++++++++++"); 1383 1384 List<SubInfoRecord> sirl = getActiveSubInfoList(); 1385 if (sirl != null) { 1386 pw.println(" ActiveSubInfoList:"); 1387 for (SubInfoRecord entry : sirl) { 1388 pw.println(" " + entry.toString()); 1389 } 1390 } else { 1391 pw.println(" ActiveSubInfoList: is null"); 1392 } 1393 pw.flush(); 1394 pw.println("++++++++++++++++++++++++++++++++"); 1395 1396 sirl = getAllSubInfoList(); 1397 if (sirl != null) { 1398 pw.println(" AllSubInfoList:"); 1399 for (SubInfoRecord entry : sirl) { 1400 pw.println(" " + entry.toString()); 1401 } 1402 } else { 1403 pw.println(" AllSubInfoList: is null"); 1404 } 1405 pw.flush(); 1406 pw.println("++++++++++++++++++++++++++++++++"); 1407 1408 mLocalLog.dump(fd, pw, args); 1409 pw.flush(); 1410 pw.println("++++++++++++++++++++++++++++++++"); 1411 pw.flush(); 1412 } 1413} 1414