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