1 /* 2 * Copyright (C) 2009 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.settings.fuelgauge; 18 19 import android.app.Activity; 20 import android.app.ActivityManager; 21 import android.app.ApplicationErrorReport; 22 import android.app.admin.DevicePolicyManager; 23 import android.content.BroadcastReceiver; 24 import android.content.ComponentName; 25 import android.content.Context; 26 import android.content.Intent; 27 import android.content.pm.ApplicationInfo; 28 import android.content.pm.PackageInfo; 29 import android.content.pm.PackageManager; 30 import android.content.pm.PackageManager.NameNotFoundException; 31 import android.graphics.drawable.Drawable; 32 import android.net.Uri; 33 import android.os.BatteryStats; 34 import android.os.Bundle; 35 import android.os.Process; 36 import android.os.UserHandle; 37 import android.preference.Preference; 38 import android.preference.Preference.OnPreferenceClickListener; 39 import android.preference.PreferenceCategory; 40 import android.text.TextUtils; 41 import android.util.Log; 42 import android.view.View; 43 import android.widget.Button; 44 45 import com.android.internal.logging.MetricsLogger; 46 import com.android.internal.os.BatterySipper; 47 import com.android.internal.os.BatterySipper.DrainType; 48 import com.android.internal.os.BatteryStatsHelper; 49 import com.android.internal.util.FastPrintWriter; 50 import com.android.settings.AppHeader; 51 import com.android.settings.DisplaySettings; 52 import com.android.settings.R; 53 import com.android.settings.SettingsActivity; 54 import com.android.settings.Utils; 55 import com.android.settings.WirelessSettings; 56 import com.android.settings.applications.AppInfoWithHeader; 57 import com.android.settings.applications.InstalledAppDetails; 58 import com.android.settings.applications.LayoutPreference; 59 import com.android.settings.bluetooth.BluetoothSettings; 60 import com.android.settings.location.LocationSettings; 61 import com.android.settings.wifi.WifiSettings; 62 63 import java.io.PrintWriter; 64 import java.io.StringWriter; 65 import java.io.Writer; 66 67 public class PowerUsageDetail extends PowerUsageBase implements Button.OnClickListener { 68 69 // Note: Must match the sequence of the DrainType 70 private static int[] sDrainTypeDesciptions = new int[] { 71 R.string.battery_desc_standby, 72 R.string.battery_desc_radio, 73 R.string.battery_desc_voice, 74 R.string.battery_desc_wifi, 75 R.string.battery_desc_bluetooth, 76 R.string.battery_desc_flashlight, 77 R.string.battery_desc_display, 78 R.string.battery_desc_apps, 79 R.string.battery_desc_users, 80 R.string.battery_desc_unaccounted, 81 R.string.battery_desc_overcounted, 82 R.string.battery_desc_camera, 83 }; 84 startBatteryDetailPage( SettingsActivity caller, BatteryStatsHelper helper, int statsType, BatteryEntry entry, boolean showLocationButton)85 public static void startBatteryDetailPage( 86 SettingsActivity caller, BatteryStatsHelper helper, int statsType, BatteryEntry entry, 87 boolean showLocationButton) { 88 // Initialize mStats if necessary. 89 helper.getStats(); 90 91 final int dischargeAmount = helper.getStats().getDischargeAmount(statsType); 92 Bundle args = new Bundle(); 93 args.putString(PowerUsageDetail.EXTRA_TITLE, entry.name); 94 args.putInt(PowerUsageDetail.EXTRA_PERCENT, (int) 95 ((entry.sipper.totalPowerMah * dischargeAmount / helper.getTotalPower()) + .5)); 96 args.putInt(PowerUsageDetail.EXTRA_GAUGE, (int) 97 Math.ceil(entry.sipper.totalPowerMah * 100 / helper.getMaxPower())); 98 args.putLong(PowerUsageDetail.EXTRA_USAGE_DURATION, helper.getStatsPeriod()); 99 args.putString(PowerUsageDetail.EXTRA_ICON_PACKAGE, entry.defaultPackageName); 100 args.putInt(PowerUsageDetail.EXTRA_ICON_ID, entry.iconId); 101 args.putDouble(PowerUsageDetail.EXTRA_NO_COVERAGE, entry.sipper.noCoveragePercent); 102 if (entry.sipper.uidObj != null) { 103 args.putInt(PowerUsageDetail.EXTRA_UID, entry.sipper.uidObj.getUid()); 104 } 105 args.putSerializable(PowerUsageDetail.EXTRA_DRAIN_TYPE, entry.sipper.drainType); 106 args.putBoolean(PowerUsageDetail.EXTRA_SHOW_LOCATION_BUTTON, showLocationButton); 107 108 int userId = UserHandle.myUserId(); 109 int[] types; 110 double[] values; 111 switch (entry.sipper.drainType) { 112 case APP: 113 case USER: 114 { 115 BatteryStats.Uid uid = entry.sipper.uidObj; 116 types = new int[] { 117 R.string.usage_type_cpu, 118 R.string.usage_type_cpu_foreground, 119 R.string.usage_type_wake_lock, 120 R.string.usage_type_gps, 121 R.string.usage_type_wifi_running, 122 R.string.usage_type_data_recv, 123 R.string.usage_type_data_send, 124 R.string.usage_type_radio_active, 125 R.string.usage_type_data_wifi_recv, 126 R.string.usage_type_data_wifi_send, 127 R.string.usage_type_audio, 128 R.string.usage_type_video, 129 R.string.usage_type_camera, 130 R.string.usage_type_flashlight, 131 R.string.usage_type_computed_power, 132 }; 133 values = new double[] { 134 entry.sipper.cpuTimeMs, 135 entry.sipper.cpuFgTimeMs, 136 entry.sipper.wakeLockTimeMs, 137 entry.sipper.gpsTimeMs, 138 entry.sipper.wifiRunningTimeMs, 139 entry.sipper.mobileRxPackets, 140 entry.sipper.mobileTxPackets, 141 entry.sipper.mobileActive, 142 entry.sipper.wifiRxPackets, 143 entry.sipper.wifiTxPackets, 144 0, 145 0, 146 entry.sipper.cameraTimeMs, 147 entry.sipper.flashlightTimeMs, 148 entry.sipper.totalPowerMah, 149 }; 150 151 if (entry.sipper.drainType == BatterySipper.DrainType.APP) { 152 Writer result = new StringWriter(); 153 PrintWriter printWriter = new FastPrintWriter(result, false, 1024); 154 helper.getStats().dumpLocked(caller, printWriter, "", helper.getStatsType(), 155 uid.getUid()); 156 printWriter.flush(); 157 args.putString(PowerUsageDetail.EXTRA_REPORT_DETAILS, result.toString()); 158 159 result = new StringWriter(); 160 printWriter = new FastPrintWriter(result, false, 1024); 161 helper.getStats().dumpCheckinLocked(caller, printWriter, helper.getStatsType(), 162 uid.getUid()); 163 printWriter.flush(); 164 args.putString(PowerUsageDetail.EXTRA_REPORT_CHECKIN_DETAILS, 165 result.toString()); 166 if (uid.getUid() != 0) { 167 userId = UserHandle.getUserId(uid.getUid()); 168 } 169 } 170 } 171 break; 172 case CELL: 173 { 174 types = new int[] { 175 R.string.usage_type_on_time, 176 R.string.usage_type_no_coverage, 177 R.string.usage_type_radio_active, 178 R.string.usage_type_computed_power, 179 }; 180 values = new double[] { 181 entry.sipper.usageTimeMs, 182 entry.sipper.noCoveragePercent, 183 entry.sipper.mobileActive, 184 entry.sipper.totalPowerMah, 185 }; 186 } 187 break; 188 case WIFI: 189 { 190 types = new int[] { 191 R.string.usage_type_wifi_running, 192 R.string.usage_type_cpu, 193 R.string.usage_type_cpu_foreground, 194 R.string.usage_type_wake_lock, 195 R.string.usage_type_data_recv, 196 R.string.usage_type_data_send, 197 R.string.usage_type_data_wifi_recv, 198 R.string.usage_type_data_wifi_send, 199 R.string.usage_type_computed_power, 200 }; 201 values = new double[] { 202 entry.sipper.wifiRunningTimeMs, 203 entry.sipper.cpuTimeMs, 204 entry.sipper.cpuFgTimeMs, 205 entry.sipper.wakeLockTimeMs, 206 entry.sipper.mobileRxPackets, 207 entry.sipper.mobileTxPackets, 208 entry.sipper.wifiRxPackets, 209 entry.sipper.wifiTxPackets, 210 entry.sipper.totalPowerMah, 211 }; 212 } break; 213 case BLUETOOTH: 214 { 215 types = new int[] { 216 R.string.usage_type_on_time, 217 R.string.usage_type_cpu, 218 R.string.usage_type_cpu_foreground, 219 R.string.usage_type_wake_lock, 220 R.string.usage_type_data_recv, 221 R.string.usage_type_data_send, 222 R.string.usage_type_data_wifi_recv, 223 R.string.usage_type_data_wifi_send, 224 R.string.usage_type_computed_power, 225 }; 226 values = new double[] { 227 entry.sipper.usageTimeMs, 228 entry.sipper.cpuTimeMs, 229 entry.sipper.cpuFgTimeMs, 230 entry.sipper.wakeLockTimeMs, 231 entry.sipper.mobileRxPackets, 232 entry.sipper.mobileTxPackets, 233 entry.sipper.wifiRxPackets, 234 entry.sipper.wifiTxPackets, 235 entry.sipper.totalPowerMah, 236 }; 237 } break; 238 case UNACCOUNTED: 239 { 240 types = new int[] { 241 R.string.usage_type_total_battery_capacity, 242 R.string.usage_type_computed_power, 243 R.string.usage_type_actual_power, 244 }; 245 values = new double[] { 246 helper.getPowerProfile().getBatteryCapacity(), 247 helper.getComputedPower(), 248 helper.getMinDrainedPower(), 249 }; 250 } break; 251 case OVERCOUNTED: 252 { 253 types = new int[] { 254 R.string.usage_type_total_battery_capacity, 255 R.string.usage_type_computed_power, 256 R.string.usage_type_actual_power, 257 }; 258 values = new double[] { 259 helper.getPowerProfile().getBatteryCapacity(), 260 helper.getComputedPower(), 261 helper.getMaxDrainedPower(), 262 }; 263 } break; 264 default: 265 { 266 types = new int[] { 267 R.string.usage_type_on_time, 268 R.string.usage_type_computed_power, 269 }; 270 values = new double[] { 271 entry.sipper.usageTimeMs, 272 entry.sipper.totalPowerMah, 273 }; 274 } 275 } 276 args.putIntArray(PowerUsageDetail.EXTRA_DETAIL_TYPES, types); 277 args.putDoubleArray(PowerUsageDetail.EXTRA_DETAIL_VALUES, values); 278 279 caller.startPreferencePanelAsUser(PowerUsageDetail.class.getName(), args, 280 R.string.details_title, null, new UserHandle(userId)); 281 } 282 283 public static final int ACTION_DISPLAY_SETTINGS = 1; 284 public static final int ACTION_WIFI_SETTINGS = 2; 285 public static final int ACTION_BLUETOOTH_SETTINGS = 3; 286 public static final int ACTION_WIRELESS_SETTINGS = 4; 287 public static final int ACTION_APP_DETAILS = 5; 288 public static final int ACTION_LOCATION_SETTINGS = 6; 289 public static final int ACTION_FORCE_STOP = 7; 290 public static final int ACTION_REPORT = 8; 291 292 public static final int USAGE_SINCE_UNPLUGGED = 1; 293 public static final int USAGE_SINCE_RESET = 2; 294 295 public static final String EXTRA_TITLE = "title"; 296 public static final String EXTRA_PERCENT = "percent"; 297 public static final String EXTRA_GAUGE = "gauge"; 298 public static final String EXTRA_UID = "uid"; 299 public static final String EXTRA_USAGE_SINCE = "since"; 300 public static final String EXTRA_USAGE_DURATION = "duration"; 301 public static final String EXTRA_REPORT_DETAILS = "report_details"; 302 public static final String EXTRA_REPORT_CHECKIN_DETAILS = "report_checkin_details"; 303 public static final String EXTRA_DETAIL_TYPES = "types"; // Array of usage types (cpu, gps, etc) 304 public static final String EXTRA_DETAIL_VALUES = "values"; // Array of doubles 305 public static final String EXTRA_DRAIN_TYPE = "drainType"; // DrainType 306 public static final String EXTRA_ICON_PACKAGE = "iconPackage"; // String 307 public static final String EXTRA_NO_COVERAGE = "noCoverage"; 308 public static final String EXTRA_ICON_ID = "iconId"; // Int 309 public static final String EXTRA_SHOW_LOCATION_BUTTON = "showLocationButton"; // Boolean 310 311 private static final String TAG = "PowerUsageDetail"; 312 313 private static final String KEY_DETAILS_PARENT = "details_parent"; 314 private static final String KEY_CONTROLS_PARENT = "controls_parent"; 315 private static final String KEY_MESSAGES_PARENT = "messages_parent"; 316 private static final String KEY_PACKAGES_PARENT = "packages_parent"; 317 private static final String KEY_TWO_BUTTONS = "two_buttons"; 318 private static final String KEY_HIGH_POWER = "high_power"; 319 320 private PackageManager mPm; 321 private DevicePolicyManager mDpm; 322 private int mUsageSince; 323 private int[] mTypes; 324 private int mUid; 325 private double[] mValues; 326 private Button mForceStopButton; 327 private Button mReportButton; 328 private long mStartTime; 329 private BatterySipper.DrainType mDrainType; 330 private double mNoCoverage; // Percentage of time that there was no coverage 331 332 private PreferenceCategory mDetailsParent; 333 private PreferenceCategory mControlsParent; 334 private PreferenceCategory mMessagesParent; 335 private PreferenceCategory mPackagesParent; 336 337 private boolean mUsesGps; 338 private boolean mShowLocationButton; 339 340 private String[] mPackages; 341 342 ApplicationInfo mApp; 343 ComponentName mInstaller; 344 private Preference mHighPower; 345 346 @Override onCreate(Bundle icicle)347 public void onCreate(Bundle icicle) { 348 super.onCreate(icicle); 349 mPm = getActivity().getPackageManager(); 350 mDpm = (DevicePolicyManager)getActivity().getSystemService(Context.DEVICE_POLICY_SERVICE); 351 352 addPreferencesFromResource(R.xml.power_usage_details); 353 mDetailsParent = (PreferenceCategory) findPreference(KEY_DETAILS_PARENT); 354 mControlsParent = (PreferenceCategory) findPreference(KEY_CONTROLS_PARENT); 355 mMessagesParent = (PreferenceCategory) findPreference(KEY_MESSAGES_PARENT); 356 mPackagesParent = (PreferenceCategory) findPreference(KEY_PACKAGES_PARENT); 357 358 createDetails(); 359 } 360 361 @Override getMetricsCategory()362 protected int getMetricsCategory() { 363 return MetricsLogger.FUELGAUGE_POWER_USAGE_DETAIL; 364 } 365 366 @Override onResume()367 public void onResume() { 368 super.onResume(); 369 mStartTime = android.os.Process.getElapsedCpuTime(); 370 checkForceStop(); 371 if (mHighPower != null) { 372 mHighPower.setSummary(HighPowerDetail.getSummary(getActivity(), mApp.packageName)); 373 } 374 375 setupHeader(); 376 } 377 378 @Override onActivityResult(int requestCode, int resultCode, Intent data)379 public void onActivityResult(int requestCode, int resultCode, Intent data) { 380 super.onActivityResult(requestCode, resultCode, data); 381 if (mHighPower != null) { 382 mHighPower.setSummary(HighPowerDetail.getSummary(getActivity(), mApp.packageName)); 383 } 384 } 385 createDetails()386 private void createDetails() { 387 final Bundle args = getArguments(); 388 Context context = getActivity(); 389 mUsageSince = args.getInt(EXTRA_USAGE_SINCE, USAGE_SINCE_UNPLUGGED); 390 mUid = args.getInt(EXTRA_UID, 0); 391 mPackages = context.getPackageManager().getPackagesForUid(mUid); 392 mDrainType = (BatterySipper.DrainType) args.getSerializable(EXTRA_DRAIN_TYPE); 393 mNoCoverage = args.getDouble(EXTRA_NO_COVERAGE, 0); 394 mShowLocationButton = args.getBoolean(EXTRA_SHOW_LOCATION_BUTTON); 395 396 mTypes = args.getIntArray(EXTRA_DETAIL_TYPES); 397 mValues = args.getDoubleArray(EXTRA_DETAIL_VALUES); 398 399 LayoutPreference twoButtons = (LayoutPreference) findPreference(KEY_TWO_BUTTONS); 400 mForceStopButton = (Button) twoButtons.findViewById(R.id.left_button); 401 mReportButton = (Button) twoButtons.findViewById(R.id.right_button); 402 mForceStopButton.setEnabled(false); 403 404 if (mUid >= Process.FIRST_APPLICATION_UID) { 405 mForceStopButton.setText(R.string.force_stop); 406 mForceStopButton.setTag(ACTION_FORCE_STOP); 407 mForceStopButton.setOnClickListener(this); 408 mReportButton.setText(com.android.internal.R.string.report); 409 mReportButton.setTag(ACTION_REPORT); 410 mReportButton.setOnClickListener(this); 411 412 if (mPackages != null && mPackages.length > 0) { 413 try { 414 mApp = context.getPackageManager().getApplicationInfo( 415 mPackages[0], 0); 416 } catch (NameNotFoundException e) { 417 } 418 } else { 419 Log.d(TAG, "No packages!!"); 420 } 421 // check if error reporting is enabled in secure settings 422 int enabled = android.provider.Settings.Global.getInt(context.getContentResolver(), 423 android.provider.Settings.Global.SEND_ACTION_APP_ERROR, 0); 424 if (enabled != 0) { 425 if (mApp != null) { 426 mInstaller = ApplicationErrorReport.getErrorReportReceiver( 427 context, mPackages[0], mApp.flags); 428 } 429 mReportButton.setEnabled(mInstaller != null); 430 } else { 431 removePreference(KEY_TWO_BUTTONS); 432 } 433 if (mApp != null 434 && PowerWhitelistBackend.getInstance().isWhitelisted(mApp.packageName)) { 435 mHighPower = findPreference(KEY_HIGH_POWER); 436 mHighPower.setOnPreferenceClickListener(new OnPreferenceClickListener() { 437 @Override 438 public boolean onPreferenceClick(Preference preference) { 439 HighPowerDetail.show(PowerUsageDetail.this, mApp.packageName, 0, false); 440 return true; 441 } 442 }); 443 } else { 444 mControlsParent.removePreference(findPreference(KEY_HIGH_POWER)); 445 } 446 } else { 447 removePreference(KEY_TWO_BUTTONS); 448 mControlsParent.removePreference(findPreference(KEY_HIGH_POWER)); 449 } 450 451 refreshStats(); 452 453 fillDetailsSection(); 454 fillPackagesSection(mUid); 455 fillControlsSection(mUid); 456 fillMessagesSection(mUid); 457 } 458 setupHeader()459 private void setupHeader() { 460 final Bundle args = getArguments(); 461 String title = args.getString(EXTRA_TITLE); 462 String pkg = args.getString(EXTRA_ICON_PACKAGE); 463 int iconId = args.getInt(EXTRA_ICON_ID, 0); 464 Drawable appIcon = null; 465 466 if (!TextUtils.isEmpty(pkg)) { 467 try { 468 final PackageManager pm = getActivity().getPackageManager(); 469 ApplicationInfo ai = pm.getPackageInfo(pkg, 0).applicationInfo; 470 if (ai != null) { 471 appIcon = ai.loadIcon(pm); 472 } 473 } catch (NameNotFoundException nnfe) { 474 // Use default icon 475 } 476 } else if (iconId != 0) { 477 appIcon = getActivity().getDrawable(iconId); 478 } 479 if (appIcon == null) { 480 appIcon = getActivity().getPackageManager().getDefaultActivityIcon(); 481 } 482 483 if (pkg == null && mPackages != null) { 484 pkg = mPackages[0]; 485 } 486 AppHeader.createAppHeader(this, appIcon, title, 487 pkg != null ? AppInfoWithHeader.getInfoIntent(this, pkg) : null, 488 mDrainType != DrainType.APP ? android.R.color.white : 0); 489 } 490 onClick(View v)491 public void onClick(View v) { 492 doAction((Integer) v.getTag()); 493 } 494 495 // utility method used to start sub activity startApplicationDetailsActivity()496 private void startApplicationDetailsActivity() { 497 // start new fragment to display extended information 498 Bundle args = new Bundle(); 499 args.putString(InstalledAppDetails.ARG_PACKAGE_NAME, mPackages[0]); 500 501 SettingsActivity sa = (SettingsActivity) getActivity(); 502 sa.startPreferencePanel(InstalledAppDetails.class.getName(), args, 503 R.string.application_info_label, null, null, 0); 504 } 505 doAction(int action)506 private void doAction(int action) { 507 SettingsActivity sa = (SettingsActivity)getActivity(); 508 switch (action) { 509 case ACTION_DISPLAY_SETTINGS: 510 sa.startPreferencePanel(DisplaySettings.class.getName(), null, 511 R.string.display_settings_title, null, null, 0); 512 break; 513 case ACTION_WIFI_SETTINGS: 514 sa.startPreferencePanel(WifiSettings.class.getName(), null, 515 R.string.wifi_settings, null, null, 0); 516 break; 517 case ACTION_BLUETOOTH_SETTINGS: 518 sa.startPreferencePanel(BluetoothSettings.class.getName(), null, 519 R.string.bluetooth_settings, null, null, 0); 520 break; 521 case ACTION_WIRELESS_SETTINGS: 522 sa.startPreferencePanel(WirelessSettings.class.getName(), null, 523 R.string.radio_controls_title, null, null, 0); 524 break; 525 case ACTION_APP_DETAILS: 526 startApplicationDetailsActivity(); 527 break; 528 case ACTION_LOCATION_SETTINGS: 529 sa.startPreferencePanel(LocationSettings.class.getName(), null, 530 R.string.location_settings_title, null, null, 0); 531 break; 532 case ACTION_FORCE_STOP: 533 killProcesses(); 534 break; 535 case ACTION_REPORT: 536 reportBatteryUse(); 537 break; 538 } 539 } 540 fillDetailsSection()541 private void fillDetailsSection() { 542 if (mTypes != null && mValues != null) { 543 for (int i = 0; i < mTypes.length; i++) { 544 // Only add an item if the time is greater than zero 545 if (mValues[i] <= 0) continue; 546 final String label = getString(mTypes[i]); 547 String value = null; 548 switch (mTypes[i]) { 549 case R.string.usage_type_data_recv: 550 case R.string.usage_type_data_send: 551 case R.string.usage_type_data_wifi_recv: 552 case R.string.usage_type_data_wifi_send: 553 final long packets = (long) (mValues[i]); 554 value = Long.toString(packets); 555 break; 556 case R.string.usage_type_no_coverage: 557 final int percentage = (int) Math.floor(mValues[i]); 558 value = Utils.formatPercentage(percentage); 559 break; 560 case R.string.usage_type_total_battery_capacity: 561 case R.string.usage_type_computed_power: 562 case R.string.usage_type_actual_power: 563 value = getActivity().getString(R.string.mah, (long)(mValues[i])); 564 break; 565 case R.string.usage_type_gps: 566 mUsesGps = true; 567 // Fall through 568 default: 569 value = Utils.formatElapsedTime(getActivity(), mValues[i], true); 570 } 571 addHorizontalPreference(mDetailsParent, label, value); 572 } 573 } 574 } 575 addHorizontalPreference(PreferenceCategory parent, CharSequence title, CharSequence summary)576 private void addHorizontalPreference(PreferenceCategory parent, CharSequence title, 577 CharSequence summary) { 578 Preference pref = new Preference(getActivity()); 579 pref.setLayoutResource(R.layout.horizontal_preference); 580 pref.setTitle(title); 581 pref.setSummary(summary); 582 pref.setSelectable(false); 583 parent.addPreference(pref); 584 } 585 fillControlsSection(int uid)586 private void fillControlsSection(int uid) { 587 PackageManager pm = getActivity().getPackageManager(); 588 String[] packages = pm.getPackagesForUid(uid); 589 PackageInfo pi = null; 590 try { 591 pi = packages != null ? pm.getPackageInfo(packages[0], 0) : null; 592 } catch (NameNotFoundException nnfe) { /* Nothing */ } 593 ApplicationInfo ai = pi != null? pi.applicationInfo : null; 594 595 boolean removeHeader = true; 596 switch (mDrainType) { 597 case APP: 598 // If it is a Java application and only one package is associated with the Uid 599 if (packages != null && packages.length == 1) { 600 addControl(R.string.battery_action_app_details, 601 R.string.battery_sugg_apps_info, ACTION_APP_DETAILS); 602 removeHeader = false; 603 // If the application has a settings screen, jump to that 604 // TODO: 605 } 606 // If power usage detail page is launched from location page, suppress "Location" 607 // button to prevent circular loops. 608 if (mUsesGps && mShowLocationButton) { 609 addControl(R.string.location_settings_title, 610 R.string.battery_sugg_apps_gps, ACTION_LOCATION_SETTINGS); 611 removeHeader = false; 612 } 613 break; 614 case SCREEN: 615 addControl(R.string.display_settings, 616 R.string.battery_sugg_display, 617 ACTION_DISPLAY_SETTINGS); 618 removeHeader = false; 619 break; 620 case WIFI: 621 addControl(R.string.wifi_settings, 622 R.string.battery_sugg_wifi, 623 ACTION_WIFI_SETTINGS); 624 removeHeader = false; 625 break; 626 case BLUETOOTH: 627 addControl(R.string.bluetooth_settings, 628 R.string.battery_sugg_bluetooth_basic, 629 ACTION_BLUETOOTH_SETTINGS); 630 removeHeader = false; 631 break; 632 case CELL: 633 if (mNoCoverage > 10) { 634 addControl(R.string.radio_controls_title, 635 R.string.battery_sugg_radio, 636 ACTION_WIRELESS_SETTINGS); 637 removeHeader = false; 638 } 639 break; 640 } 641 if (removeHeader) { 642 mControlsParent.setTitle(null); 643 } 644 } 645 addControl(int pageSummary, int actionTitle, final int action)646 private void addControl(int pageSummary, int actionTitle, final int action) { 647 Preference pref = new Preference(getActivity()); 648 pref.setTitle(actionTitle); 649 pref.setLayoutResource(R.layout.horizontal_preference); 650 pref.setOnPreferenceClickListener(new OnPreferenceClickListener() { 651 @Override 652 public boolean onPreferenceClick(Preference preference) { 653 doAction(action); 654 return true; 655 } 656 }); 657 mControlsParent.addPreference(pref); 658 } 659 fillMessagesSection(int uid)660 private void fillMessagesSection(int uid) { 661 boolean removeHeader = true; 662 switch (mDrainType) { 663 case UNACCOUNTED: 664 addMessage(R.string.battery_msg_unaccounted); 665 removeHeader = false; 666 break; 667 } 668 if (removeHeader) { 669 mMessagesParent.setTitle(null); 670 } 671 } 672 addMessage(int message)673 private void addMessage(int message) { 674 addHorizontalPreference(mMessagesParent, getString(message), null); 675 } 676 removePackagesSection()677 private void removePackagesSection() { 678 getPreferenceScreen().removePreference(mPackagesParent); 679 } 680 killProcesses()681 private void killProcesses() { 682 if (mPackages == null) return; 683 ActivityManager am = (ActivityManager)getActivity().getSystemService( 684 Context.ACTIVITY_SERVICE); 685 final int userId = UserHandle.getUserId(mUid); 686 for (int i = 0; i < mPackages.length; i++) { 687 am.forceStopPackageAsUser(mPackages[i], userId); 688 } 689 checkForceStop(); 690 } 691 692 private final BroadcastReceiver mCheckKillProcessesReceiver = new BroadcastReceiver() { 693 @Override 694 public void onReceive(Context context, Intent intent) { 695 mForceStopButton.setEnabled(getResultCode() != Activity.RESULT_CANCELED); 696 } 697 }; 698 checkForceStop()699 private void checkForceStop() { 700 if (mPackages == null || mUid < Process.FIRST_APPLICATION_UID) { 701 mForceStopButton.setEnabled(false); 702 return; 703 } 704 for (int i = 0; i < mPackages.length; i++) { 705 if (mDpm.packageHasActiveAdmins(mPackages[i])) { 706 mForceStopButton.setEnabled(false); 707 return; 708 } 709 } 710 for (int i = 0; i < mPackages.length; i++) { 711 try { 712 ApplicationInfo info = mPm.getApplicationInfo(mPackages[i], 0); 713 if ((info.flags&ApplicationInfo.FLAG_STOPPED) == 0) { 714 mForceStopButton.setEnabled(true); 715 break; 716 } 717 } catch (PackageManager.NameNotFoundException e) { 718 } 719 } 720 Intent intent = new Intent(Intent.ACTION_QUERY_PACKAGE_RESTART, 721 Uri.fromParts("package", mPackages[0], null)); 722 intent.putExtra(Intent.EXTRA_PACKAGES, mPackages); 723 intent.putExtra(Intent.EXTRA_UID, mUid); 724 intent.putExtra(Intent.EXTRA_USER_HANDLE, UserHandle.getUserId(mUid)); 725 getActivity().sendOrderedBroadcast(intent, null, mCheckKillProcessesReceiver, null, 726 Activity.RESULT_CANCELED, null, null); 727 } 728 reportBatteryUse()729 private void reportBatteryUse() { 730 if (mPackages == null) return; 731 732 ApplicationErrorReport report = new ApplicationErrorReport(); 733 report.type = ApplicationErrorReport.TYPE_BATTERY; 734 report.packageName = mPackages[0]; 735 report.installerPackageName = mInstaller.getPackageName(); 736 report.processName = mPackages[0]; 737 report.time = System.currentTimeMillis(); 738 report.systemApp = (mApp.flags & ApplicationInfo.FLAG_SYSTEM) != 0; 739 740 final Bundle args = getArguments(); 741 ApplicationErrorReport.BatteryInfo batteryInfo = new ApplicationErrorReport.BatteryInfo(); 742 batteryInfo.usagePercent = args.getInt(EXTRA_PERCENT, 1); 743 batteryInfo.durationMicros = args.getLong(EXTRA_USAGE_DURATION, 0); 744 batteryInfo.usageDetails = args.getString(EXTRA_REPORT_DETAILS); 745 batteryInfo.checkinDetails = args.getString(EXTRA_REPORT_CHECKIN_DETAILS); 746 report.batteryInfo = batteryInfo; 747 748 Intent result = new Intent(Intent.ACTION_APP_ERROR); 749 result.setComponent(mInstaller); 750 result.putExtra(Intent.EXTRA_BUG_REPORT, report); 751 result.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 752 startActivity(result); 753 } 754 fillPackagesSection(int uid)755 private void fillPackagesSection(int uid) { 756 if (uid < 1) { 757 removePackagesSection(); 758 return; 759 } 760 if (mPackages == null || mPackages.length < 2) { 761 removePackagesSection(); 762 return; 763 } 764 765 PackageManager pm = getPackageManager(); 766 // Convert package names to user-facing labels where possible 767 for (int i = 0; i < mPackages.length; i++) { 768 try { 769 ApplicationInfo ai = pm.getApplicationInfo(mPackages[i], 0); 770 CharSequence label = ai.loadLabel(pm); 771 if (label != null) { 772 mPackages[i] = label.toString(); 773 } 774 addHorizontalPreference(mPackagesParent, mPackages[i], null); 775 } catch (NameNotFoundException e) { 776 } 777 } 778 } 779 } 780