1 /* 2 * Copyright (C) 2006 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 17 package com.android.internal.telephony; 18 19 import android.annotation.Nullable; 20 import android.annotation.UnsupportedAppUsage; 21 import android.content.ComponentName; 22 import android.content.Context; 23 import android.content.SharedPreferences; 24 import android.content.pm.PackageManager; 25 import android.net.LocalServerSocket; 26 import android.os.Looper; 27 import android.os.ServiceManager; 28 import android.preference.PreferenceManager; 29 import android.provider.Settings; 30 import android.provider.Settings.SettingNotFoundException; 31 import android.telephony.AnomalyReporter; 32 import android.telephony.Rlog; 33 import android.telephony.SubscriptionManager; 34 import android.telephony.TelephonyManager; 35 import android.util.LocalLog; 36 37 import com.android.internal.os.BackgroundThread; 38 import com.android.internal.telephony.cdma.CdmaSubscriptionSourceManager; 39 import com.android.internal.telephony.dataconnection.TelephonyNetworkFactory; 40 import com.android.internal.telephony.euicc.EuiccCardController; 41 import com.android.internal.telephony.euicc.EuiccController; 42 import com.android.internal.telephony.ims.ImsResolver; 43 import com.android.internal.telephony.imsphone.ImsPhone; 44 import com.android.internal.telephony.imsphone.ImsPhoneFactory; 45 import com.android.internal.telephony.sip.SipPhone; 46 import com.android.internal.telephony.sip.SipPhoneFactory; 47 import com.android.internal.telephony.uicc.UiccController; 48 import com.android.internal.telephony.util.NotificationChannelController; 49 import com.android.internal.util.IndentingPrintWriter; 50 51 import java.io.FileDescriptor; 52 import java.io.PrintWriter; 53 import java.util.HashMap; 54 import java.util.Map; 55 56 /** 57 * {@hide} 58 */ 59 public class PhoneFactory { 60 static final String LOG_TAG = "PhoneFactory"; 61 static final int SOCKET_OPEN_RETRY_MILLIS = 2 * 1000; 62 static final int SOCKET_OPEN_MAX_RETRY = 3; 63 static final boolean DBG = false; 64 65 //***** Class Variables 66 67 // lock sLockProxyPhones protects sPhones, sPhone and sTelephonyNetworkFactories 68 final static Object sLockProxyPhones = new Object(); 69 static private Phone[] sPhones = null; 70 static private Phone sPhone = null; 71 72 static private CommandsInterface[] sCommandsInterfaces = null; 73 74 static private ProxyController sProxyController; 75 static private UiccController sUiccController; 76 private static IntentBroadcaster sIntentBroadcaster; 77 private static @Nullable EuiccController sEuiccController; 78 private static @Nullable EuiccCardController sEuiccCardController; 79 80 @UnsupportedAppUsage 81 static private CommandsInterface sCommandsInterface = null; 82 static private SubscriptionInfoUpdater sSubInfoRecordUpdater = null; 83 84 @UnsupportedAppUsage 85 static private boolean sMadeDefaults = false; 86 @UnsupportedAppUsage 87 static private PhoneNotifier sPhoneNotifier; 88 @UnsupportedAppUsage 89 static private Context sContext; 90 static private PhoneConfigurationManager sPhoneConfigurationManager; 91 static private PhoneSwitcher sPhoneSwitcher; 92 static private SubscriptionMonitor sSubscriptionMonitor; 93 static private TelephonyNetworkFactory[] sTelephonyNetworkFactories; 94 static private ImsResolver sImsResolver; 95 static private NotificationChannelController sNotificationChannelController; 96 static private CellularNetworkValidator sCellularNetworkValidator; 97 98 static private final HashMap<String, LocalLog>sLocalLogs = new HashMap<String, LocalLog>(); 99 100 //***** Class Methods 101 makeDefaultPhones(Context context)102 public static void makeDefaultPhones(Context context) { 103 makeDefaultPhone(context); 104 } 105 106 /** 107 * FIXME replace this with some other way of making these 108 * instances 109 */ 110 @UnsupportedAppUsage makeDefaultPhone(Context context)111 public static void makeDefaultPhone(Context context) { 112 synchronized (sLockProxyPhones) { 113 if (!sMadeDefaults) { 114 sContext = context; 115 // create the telephony device controller. 116 TelephonyDevController.create(); 117 118 int retryCount = 0; 119 for(;;) { 120 boolean hasException = false; 121 retryCount ++; 122 123 try { 124 // use UNIX domain socket to 125 // prevent subsequent initialization 126 new LocalServerSocket("com.android.internal.telephony"); 127 } catch (java.io.IOException ex) { 128 hasException = true; 129 } 130 131 if ( !hasException ) { 132 break; 133 } else if (retryCount > SOCKET_OPEN_MAX_RETRY) { 134 throw new RuntimeException("PhoneFactory probably already running"); 135 } else { 136 try { 137 Thread.sleep(SOCKET_OPEN_RETRY_MILLIS); 138 } catch (InterruptedException er) { 139 } 140 } 141 } 142 143 sPhoneNotifier = new DefaultPhoneNotifier(); 144 145 int cdmaSubscription = CdmaSubscriptionSourceManager.getDefault(context); 146 Rlog.i(LOG_TAG, "Cdma Subscription set to " + cdmaSubscription); 147 148 /* In case of multi SIM mode two instances of Phone, RIL are created, 149 where as in single SIM mode only instance. isMultiSimEnabled() function checks 150 whether it is single SIM or multi SIM mode */ 151 TelephonyManager tm = (TelephonyManager) context.getSystemService( 152 Context.TELEPHONY_SERVICE); 153 int numPhones = tm.getPhoneCount(); 154 155 int[] networkModes = new int[numPhones]; 156 sPhones = new Phone[numPhones]; 157 sCommandsInterfaces = new RIL[numPhones]; 158 sTelephonyNetworkFactories = new TelephonyNetworkFactory[numPhones]; 159 160 for (int i = 0; i < numPhones; i++) { 161 // reads the system properties and makes commandsinterface 162 // Get preferred network type. 163 networkModes[i] = RILConstants.PREFERRED_NETWORK_MODE; 164 165 Rlog.i(LOG_TAG, "Network Mode set to " + Integer.toString(networkModes[i])); 166 sCommandsInterfaces[i] = new RIL(context, networkModes[i], 167 cdmaSubscription, i); 168 } 169 170 // Instantiate UiccController so that all other classes can just 171 // call getInstance() 172 sUiccController = UiccController.make(context, sCommandsInterfaces); 173 174 Rlog.i(LOG_TAG, "Creating SubscriptionController"); 175 SubscriptionController.init(context, sCommandsInterfaces); 176 MultiSimSettingController.init(context, SubscriptionController.getInstance()); 177 178 if (context.getPackageManager().hasSystemFeature( 179 PackageManager.FEATURE_TELEPHONY_EUICC)) { 180 sEuiccController = EuiccController.init(context); 181 sEuiccCardController = EuiccCardController.init(context); 182 } 183 184 for (int i = 0; i < numPhones; i++) { 185 Phone phone = null; 186 int phoneType = TelephonyManager.getPhoneType(networkModes[i]); 187 if (phoneType == PhoneConstants.PHONE_TYPE_GSM) { 188 phone = new GsmCdmaPhone(context, 189 sCommandsInterfaces[i], sPhoneNotifier, i, 190 PhoneConstants.PHONE_TYPE_GSM, 191 TelephonyComponentFactory.getInstance()); 192 } else if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) { 193 phone = new GsmCdmaPhone(context, 194 sCommandsInterfaces[i], sPhoneNotifier, i, 195 PhoneConstants.PHONE_TYPE_CDMA_LTE, 196 TelephonyComponentFactory.getInstance()); 197 } 198 Rlog.i(LOG_TAG, "Creating Phone with type = " + phoneType + " sub = " + i); 199 200 sPhones[i] = phone; 201 } 202 203 // Set the default phone in base class. 204 // FIXME: This is a first best guess at what the defaults will be. It 205 // FIXME: needs to be done in a more controlled manner in the future. 206 if (numPhones > 0) { 207 sPhone = sPhones[0]; 208 sCommandsInterface = sCommandsInterfaces[0]; 209 } 210 211 // Ensure that we have a default SMS app. Requesting the app with 212 // updateIfNeeded set to true is enough to configure a default SMS app. 213 ComponentName componentName = 214 SmsApplication.getDefaultSmsApplication(context, true /* updateIfNeeded */); 215 String packageName = "NONE"; 216 if (componentName != null) { 217 packageName = componentName.getPackageName(); 218 } 219 Rlog.i(LOG_TAG, "defaultSmsApplication: " + packageName); 220 221 // Set up monitor to watch for changes to SMS packages 222 SmsApplication.initSmsPackageMonitor(context); 223 224 sMadeDefaults = true; 225 226 Rlog.i(LOG_TAG, "Creating SubInfoRecordUpdater "); 227 sSubInfoRecordUpdater = new SubscriptionInfoUpdater( 228 BackgroundThread.get().getLooper(), context, sPhones, sCommandsInterfaces); 229 SubscriptionController.getInstance().updatePhonesAvailability(sPhones); 230 231 232 // Only bring up IMS if the device supports having an IMS stack. 233 if (context.getPackageManager().hasSystemFeature( 234 PackageManager.FEATURE_TELEPHONY_IMS)) { 235 // Return whether or not the device should use dynamic binding or the static 236 // implementation (deprecated) 237 boolean isDynamicBinding = sContext.getResources().getBoolean( 238 com.android.internal.R.bool.config_dynamic_bind_ims); 239 // Get the package name of the default IMS implementation. 240 String defaultImsPackage = sContext.getResources().getString( 241 com.android.internal.R.string.config_ims_package); 242 // Start ImsResolver and bind to ImsServices. 243 Rlog.i(LOG_TAG, "ImsResolver: defaultImsPackage: " + defaultImsPackage); 244 sImsResolver = new ImsResolver(sContext, defaultImsPackage, numPhones, 245 isDynamicBinding); 246 sImsResolver.initPopulateCacheAndStartBind(); 247 // Start monitoring after defaults have been made. 248 // Default phone must be ready before ImsPhone is created because ImsService 249 // might need it when it is being opened. This should initialize multiple 250 // ImsPhones for ImsResolver implementations of ImsService. 251 for (int i = 0; i < numPhones; i++) { 252 sPhones[i].startMonitoringImsService(); 253 } 254 } else { 255 Rlog.i(LOG_TAG, "IMS is not supported on this device, skipping ImsResolver."); 256 } 257 258 ITelephonyRegistry tr = ITelephonyRegistry.Stub.asInterface( 259 ServiceManager.getService("telephony.registry")); 260 SubscriptionController sc = SubscriptionController.getInstance(); 261 262 sSubscriptionMonitor = new SubscriptionMonitor(tr, sContext, sc, numPhones); 263 264 sPhoneConfigurationManager = PhoneConfigurationManager.init(sContext); 265 266 sCellularNetworkValidator = CellularNetworkValidator.make(sContext); 267 268 int maxActivePhones = sPhoneConfigurationManager 269 .getNumberOfModemsWithSimultaneousDataConnections(); 270 271 sPhoneSwitcher = PhoneSwitcher.make(maxActivePhones, numPhones, 272 sContext, sc, Looper.myLooper(), tr, sCommandsInterfaces, 273 sPhones); 274 275 sProxyController = ProxyController.getInstance(context, sPhones, 276 sUiccController, sCommandsInterfaces, sPhoneSwitcher); 277 278 sIntentBroadcaster = IntentBroadcaster.getInstance(context); 279 280 sNotificationChannelController = new NotificationChannelController(context); 281 282 sTelephonyNetworkFactories = new TelephonyNetworkFactory[numPhones]; 283 for (int i = 0; i < numPhones; i++) { 284 sTelephonyNetworkFactories[i] = new TelephonyNetworkFactory( 285 sSubscriptionMonitor, Looper.myLooper(), sPhones[i]); 286 } 287 } 288 } 289 } 290 291 @UnsupportedAppUsage getDefaultPhone()292 public static Phone getDefaultPhone() { 293 synchronized (sLockProxyPhones) { 294 if (!sMadeDefaults) { 295 throw new IllegalStateException("Default phones haven't been made yet!"); 296 } 297 return sPhone; 298 } 299 } 300 301 @UnsupportedAppUsage getPhone(int phoneId)302 public static Phone getPhone(int phoneId) { 303 Phone phone; 304 String dbgInfo = ""; 305 306 synchronized (sLockProxyPhones) { 307 if (!sMadeDefaults) { 308 throw new IllegalStateException("Default phones haven't been made yet!"); 309 // CAF_MSIM FIXME need to introduce default phone id ? 310 } else if (phoneId == SubscriptionManager.DEFAULT_PHONE_INDEX) { 311 if (DBG) { 312 dbgInfo = "phoneId == DEFAULT_PHONE_ID return sPhone"; 313 } 314 phone = sPhone; 315 } else { 316 if (DBG) { 317 dbgInfo = "phoneId != DEFAULT_PHONE_ID return sPhones[phoneId]"; 318 } 319 phone = (phoneId >= 0 && phoneId < sPhones.length) 320 ? sPhones[phoneId] : null; 321 } 322 if (DBG) { 323 Rlog.d(LOG_TAG, "getPhone:- " + dbgInfo + " phoneId=" + phoneId + 324 " phone=" + phone); 325 } 326 return phone; 327 } 328 } 329 330 @UnsupportedAppUsage getPhones()331 public static Phone[] getPhones() { 332 synchronized (sLockProxyPhones) { 333 if (!sMadeDefaults) { 334 throw new IllegalStateException("Default phones haven't been made yet!"); 335 } 336 return sPhones; 337 } 338 } 339 getSubscriptionInfoUpdater()340 public static SubscriptionInfoUpdater getSubscriptionInfoUpdater() { 341 return sSubInfoRecordUpdater; 342 } 343 344 /** 345 * @return The ImsResolver instance or null if IMS is not supported 346 * (FEATURE_TELEPHONY_IMS is not defined). 347 */ getImsResolver()348 public static @Nullable ImsResolver getImsResolver() { 349 return sImsResolver; 350 } 351 352 /** 353 * Get the network factory associated with a given phone ID. 354 * @param phoneId the phone id 355 * @return a factory for this phone ID, or null if none. 356 */ getNetworkFactory(int phoneId)357 public static TelephonyNetworkFactory getNetworkFactory(int phoneId) { 358 synchronized (sLockProxyPhones) { 359 if (!sMadeDefaults) { 360 throw new IllegalStateException("Default phones haven't been made yet!"); 361 } 362 final String dbgInfo; 363 if (phoneId == SubscriptionManager.DEFAULT_PHONE_INDEX) { 364 dbgInfo = "getNetworkFactory with DEFAULT_PHONE_ID => factory for sPhone"; 365 phoneId = sPhone.getSubId(); 366 } else { 367 dbgInfo = "getNetworkFactory with non-default, return factory for passed id"; 368 } 369 // sTelephonyNetworkFactories is null in tests because in tests makeDefaultPhones() 370 // is not called. 371 final TelephonyNetworkFactory factory = (sTelephonyNetworkFactories != null 372 && (phoneId >= 0 && phoneId < sTelephonyNetworkFactories.length)) 373 ? sTelephonyNetworkFactories[phoneId] : null; 374 if (DBG) { 375 Rlog.d(LOG_TAG, "getNetworkFactory:-" + dbgInfo + " phoneId=" + phoneId 376 + " factory=" + factory); 377 } 378 return factory; 379 } 380 } 381 382 /** 383 * Makes a {@link SipPhone} object. 384 * @param sipUri the local SIP URI the phone runs on 385 * @return the {@code SipPhone} object or null if the SIP URI is not valid 386 */ makeSipPhone(String sipUri)387 public static SipPhone makeSipPhone(String sipUri) { 388 return SipPhoneFactory.makePhone(sipUri, sContext, sPhoneNotifier); 389 } 390 391 /** 392 * Returns the preferred network type that should be set in the modem. 393 * 394 * @param context The current {@link Context}. 395 * @return the preferred network mode that should be set. 396 */ 397 // TODO: Fix when we "properly" have TelephonyDevController/SubscriptionController .. 398 @UnsupportedAppUsage calculatePreferredNetworkType(Context context, int phoneSubId)399 public static int calculatePreferredNetworkType(Context context, int phoneSubId) { 400 int networkType = android.provider.Settings.Global.getInt(context.getContentResolver(), 401 android.provider.Settings.Global.PREFERRED_NETWORK_MODE + phoneSubId, 402 -1 /* invalid network mode */); 403 Rlog.d(LOG_TAG, "calculatePreferredNetworkType: phoneSubId = " + phoneSubId + 404 " networkType = " + networkType); 405 406 if (networkType == -1) { 407 networkType = RILConstants.PREFERRED_NETWORK_MODE; 408 try { 409 networkType = TelephonyManager.getIntAtIndex(context.getContentResolver(), 410 android.provider.Settings.Global.PREFERRED_NETWORK_MODE, 411 SubscriptionController.getInstance().getPhoneId(phoneSubId)); 412 } catch (SettingNotFoundException retrySnfe) { 413 Rlog.e(LOG_TAG, "Settings Exception Reading Value At Index for " 414 + "Settings.Global.PREFERRED_NETWORK_MODE"); 415 } 416 } 417 418 return networkType; 419 } 420 421 /* Gets the default subscription */ 422 @UnsupportedAppUsage getDefaultSubscription()423 public static int getDefaultSubscription() { 424 return SubscriptionController.getInstance().getDefaultSubId(); 425 } 426 427 /* Returns User SMS Prompt property, enabled or not */ isSMSPromptEnabled()428 public static boolean isSMSPromptEnabled() { 429 boolean prompt = false; 430 int value = 0; 431 try { 432 value = Settings.Global.getInt(sContext.getContentResolver(), 433 Settings.Global.MULTI_SIM_SMS_PROMPT); 434 } catch (SettingNotFoundException snfe) { 435 Rlog.e(LOG_TAG, "Settings Exception Reading Dual Sim SMS Prompt Values"); 436 } 437 prompt = (value == 0) ? false : true ; 438 Rlog.d(LOG_TAG, "SMS Prompt option:" + prompt); 439 440 return prompt; 441 } 442 443 /** 444 * Makes a {@link ImsPhone} object. 445 * @return the {@code ImsPhone} object or null if the exception occured 446 */ makeImsPhone(PhoneNotifier phoneNotifier, Phone defaultPhone)447 public static Phone makeImsPhone(PhoneNotifier phoneNotifier, Phone defaultPhone) { 448 return ImsPhoneFactory.makePhone(sContext, phoneNotifier, defaultPhone); 449 } 450 451 /** 452 * Request a refresh of the embedded subscription list. 453 * 454 * @param cardId the card ID of the eUICC. 455 * @param callback Optional callback to execute after the refresh completes. Must terminate 456 * quickly as it will be called from SubscriptionInfoUpdater's handler thread. 457 */ requestEmbeddedSubscriptionInfoListRefresh( int cardId, @Nullable Runnable callback)458 public static void requestEmbeddedSubscriptionInfoListRefresh( 459 int cardId, @Nullable Runnable callback) { 460 sSubInfoRecordUpdater.requestEmbeddedSubscriptionInfoListRefresh(cardId, callback); 461 } 462 463 /** 464 * Get a the SmsController. 465 */ getSmsController()466 public static SmsController getSmsController() { 467 synchronized (sLockProxyPhones) { 468 if (!sMadeDefaults) { 469 throw new IllegalStateException("Default phones haven't been made yet!"); 470 } 471 return sProxyController.getSmsController(); 472 } 473 } 474 475 /** 476 * Adds a local log category. 477 * 478 * Only used within the telephony process. Use localLog to add log entries. 479 * 480 * TODO - is there a better way to do this? Think about design when we have a minute. 481 * 482 * @param key the name of the category - will be the header in the service dump. 483 * @param size the number of lines to maintain in this category 484 */ addLocalLog(String key, int size)485 public static void addLocalLog(String key, int size) { 486 synchronized(sLocalLogs) { 487 if (sLocalLogs.containsKey(key)) { 488 throw new IllegalArgumentException("key " + key + " already present"); 489 } 490 sLocalLogs.put(key, new LocalLog(size)); 491 } 492 } 493 494 /** 495 * Add a line to the named Local Log. 496 * 497 * This will appear in the TelephonyDebugService dump. 498 * 499 * @param key the name of the log category to put this in. Must be created 500 * via addLocalLog. 501 * @param log the string to add to the log. 502 */ localLog(String key, String log)503 public static void localLog(String key, String log) { 504 synchronized(sLocalLogs) { 505 if (sLocalLogs.containsKey(key) == false) { 506 throw new IllegalArgumentException("key " + key + " not found"); 507 } 508 sLocalLogs.get(key).log(log); 509 } 510 } 511 dump(FileDescriptor fd, PrintWriter printwriter, String[] args)512 public static void dump(FileDescriptor fd, PrintWriter printwriter, String[] args) { 513 IndentingPrintWriter pw = new IndentingPrintWriter(printwriter, " "); 514 pw.println("PhoneFactory:"); 515 pw.println(" sMadeDefaults=" + sMadeDefaults); 516 517 sPhoneSwitcher.dump(fd, pw, args); 518 pw.println(); 519 520 Phone[] phones = (Phone[])PhoneFactory.getPhones(); 521 for (int i = 0; i < phones.length; i++) { 522 pw.increaseIndent(); 523 Phone phone = phones[i]; 524 525 try { 526 phone.dump(fd, pw, args); 527 } catch (Exception e) { 528 pw.println("Telephony DebugService: Could not get Phone[" + i + "] e=" + e); 529 continue; 530 } 531 532 pw.flush(); 533 pw.println("++++++++++++++++++++++++++++++++"); 534 535 sTelephonyNetworkFactories[i].dump(fd, pw, args); 536 537 pw.flush(); 538 pw.decreaseIndent(); 539 pw.println("++++++++++++++++++++++++++++++++"); 540 } 541 542 pw.println("SubscriptionMonitor:"); 543 pw.increaseIndent(); 544 try { 545 sSubscriptionMonitor.dump(fd, pw, args); 546 } catch (Exception e) { 547 e.printStackTrace(); 548 } 549 pw.decreaseIndent(); 550 pw.println("++++++++++++++++++++++++++++++++"); 551 552 pw.println("UiccController:"); 553 pw.increaseIndent(); 554 try { 555 sUiccController.dump(fd, pw, args); 556 } catch (Exception e) { 557 e.printStackTrace(); 558 } 559 pw.flush(); 560 pw.decreaseIndent(); 561 pw.println("++++++++++++++++++++++++++++++++"); 562 563 if (sEuiccController != null) { 564 pw.println("EuiccController:"); 565 pw.increaseIndent(); 566 try { 567 sEuiccController.dump(fd, pw, args); 568 sEuiccCardController.dump(fd, pw, args); 569 } catch (Exception e) { 570 e.printStackTrace(); 571 } 572 pw.flush(); 573 pw.decreaseIndent(); 574 pw.println("++++++++++++++++++++++++++++++++"); 575 } 576 577 pw.println("SubscriptionController:"); 578 pw.increaseIndent(); 579 try { 580 SubscriptionController.getInstance().dump(fd, pw, args); 581 } catch (Exception e) { 582 e.printStackTrace(); 583 } 584 pw.flush(); 585 pw.decreaseIndent(); 586 pw.println("++++++++++++++++++++++++++++++++"); 587 588 pw.println("SubInfoRecordUpdater:"); 589 pw.increaseIndent(); 590 try { 591 sSubInfoRecordUpdater.dump(fd, pw, args); 592 } catch (Exception e) { 593 e.printStackTrace(); 594 } 595 pw.flush(); 596 pw.decreaseIndent(); 597 pw.println("++++++++++++++++++++++++++++++++"); 598 599 pw.println("LocalLogs:"); 600 pw.increaseIndent(); 601 synchronized (sLocalLogs) { 602 for (String key : sLocalLogs.keySet()) { 603 pw.println(key); 604 pw.increaseIndent(); 605 sLocalLogs.get(key).dump(fd, pw, args); 606 pw.decreaseIndent(); 607 } 608 pw.flush(); 609 } 610 pw.decreaseIndent(); 611 pw.println("++++++++++++++++++++++++++++++++"); 612 613 pw.println("SharedPreferences:"); 614 pw.increaseIndent(); 615 try { 616 if (sContext != null) { 617 SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(sContext); 618 Map spValues = sp.getAll(); 619 for (Object key : spValues.keySet()) { 620 pw.println(key + " : " + spValues.get(key)); 621 } 622 } 623 } catch (Exception e) { 624 e.printStackTrace(); 625 } 626 pw.decreaseIndent(); 627 pw.println("++++++++++++++++++++++++++++++++"); 628 pw.println("DebugEvents:"); 629 pw.increaseIndent(); 630 try { 631 AnomalyReporter.dump(fd, pw, args); 632 } catch (Exception e) { 633 e.printStackTrace(); 634 } 635 636 pw.flush(); 637 pw.decreaseIndent(); 638 } 639 } 640