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