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.support.v7.preference.Preference; 38 import android.support.v7.preference.Preference.OnPreferenceClickListener; 39 import android.support.v7.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.MetricsProto.MetricsEvent; 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.InstalledAppDetails; 57 import com.android.settings.applications.LayoutPreference; 58 import com.android.settings.bluetooth.BluetoothSettings; 59 import com.android.settings.location.LocationSettings; 60 import com.android.settings.wifi.WifiSettings; 61 62 import java.io.PrintWriter; 63 import java.io.StringWriter; 64 import java.io.Writer; 65 66 public class PowerUsageDetail extends PowerUsageBase implements Button.OnClickListener { 67 68 // Note: Must match the sequence of the DrainType 69 private static int[] sDrainTypeDesciptions = new int[] { 70 R.string.battery_desc_standby, 71 R.string.battery_desc_radio, 72 R.string.battery_desc_voice, 73 R.string.battery_desc_wifi, 74 R.string.battery_desc_bluetooth, 75 R.string.battery_desc_flashlight, 76 R.string.battery_desc_display, 77 R.string.battery_desc_apps, 78 R.string.battery_desc_users, 79 R.string.battery_desc_unaccounted, 80 R.string.battery_desc_overcounted, 81 R.string.battery_desc_camera, 82 }; 83 84 public static void startBatteryDetailPage( 85 SettingsActivity caller, BatteryStatsHelper helper, int statsType, BatteryEntry entry, 86 boolean showLocationButton, boolean includeAppInfo) { 87 // Initialize mStats if necessary. 88 helper.getStats(); 89 90 final int dischargeAmount = helper.getStats().getDischargeAmount(statsType); 91 Bundle args = new Bundle(); 92 args.putString(PowerUsageDetail.EXTRA_TITLE, entry.name); 93 args.putInt(PowerUsageDetail.EXTRA_PERCENT, (int) 94 ((entry.sipper.totalPowerMah * dischargeAmount / helper.getTotalPower()) + .5)); 95 args.putInt(PowerUsageDetail.EXTRA_GAUGE, (int) 96 Math.ceil(entry.sipper.totalPowerMah * 100 / helper.getMaxPower())); 97 args.putLong(PowerUsageDetail.EXTRA_USAGE_DURATION, helper.getStatsPeriod()); 98 args.putString(PowerUsageDetail.EXTRA_ICON_PACKAGE, entry.defaultPackageName); 99 args.putInt(PowerUsageDetail.EXTRA_ICON_ID, entry.iconId); 100 args.putDouble(PowerUsageDetail.EXTRA_NO_COVERAGE, entry.sipper.noCoveragePercent); 101 if (entry.sipper.uidObj != null) { 102 args.putInt(PowerUsageDetail.EXTRA_UID, entry.sipper.uidObj.getUid()); 103 } 104 args.putSerializable(PowerUsageDetail.EXTRA_DRAIN_TYPE, entry.sipper.drainType); 105 args.putBoolean(PowerUsageDetail.EXTRA_SHOW_LOCATION_BUTTON, showLocationButton); 106 args.putBoolean(AppHeader.EXTRA_HIDE_INFO_BUTTON, !includeAppInfo); 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 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 362 protected int getMetricsCategory() { 363 return MetricsEvent.FUELGAUGE_POWER_USAGE_DETAIL; 364 } 365 366 @Override 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 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 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 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 int uid = -1; 466 final PackageManager pm = getActivity().getPackageManager(); 467 468 if (!TextUtils.isEmpty(pkg)) { 469 try { 470 ApplicationInfo ai = pm.getPackageInfo(pkg, 0).applicationInfo; 471 if (ai != null) { 472 appIcon = ai.loadIcon(pm); 473 uid = ai.uid; 474 } 475 } catch (NameNotFoundException nnfe) { 476 // Use default icon 477 } 478 } else if (iconId != 0) { 479 appIcon = getActivity().getDrawable(iconId); 480 } 481 if (appIcon == null) { 482 appIcon = getActivity().getPackageManager().getDefaultActivityIcon(); 483 } 484 485 if (pkg == null && mPackages != null) { 486 pkg = mPackages[0]; 487 } 488 AppHeader.createAppHeader(this, appIcon, title, pkg, uid, 489 mDrainType != DrainType.APP ? android.R.color.white : 0); 490 } 491 492 public void onClick(View v) { 493 doAction((Integer) v.getTag()); 494 } 495 496 // utility method used to start sub activity 497 private void startApplicationDetailsActivity() { 498 // start new fragment to display extended information 499 Bundle args = new Bundle(); 500 args.putString(InstalledAppDetails.ARG_PACKAGE_NAME, mPackages[0]); 501 502 SettingsActivity sa = (SettingsActivity) getActivity(); 503 sa.startPreferencePanel(InstalledAppDetails.class.getName(), args, 504 R.string.application_info_label, null, null, 0); 505 } 506 507 private void doAction(int action) { 508 SettingsActivity sa = (SettingsActivity)getActivity(); 509 switch (action) { 510 case ACTION_DISPLAY_SETTINGS: 511 sa.startPreferencePanel(DisplaySettings.class.getName(), null, 512 R.string.display_settings_title, null, null, 0); 513 break; 514 case ACTION_WIFI_SETTINGS: 515 sa.startPreferencePanel(WifiSettings.class.getName(), null, 516 R.string.wifi_settings, null, null, 0); 517 break; 518 case ACTION_BLUETOOTH_SETTINGS: 519 sa.startPreferencePanel(BluetoothSettings.class.getName(), null, 520 R.string.bluetooth_settings, null, null, 0); 521 break; 522 case ACTION_WIRELESS_SETTINGS: 523 sa.startPreferencePanel(WirelessSettings.class.getName(), null, 524 R.string.radio_controls_title, null, null, 0); 525 break; 526 case ACTION_APP_DETAILS: 527 startApplicationDetailsActivity(); 528 break; 529 case ACTION_LOCATION_SETTINGS: 530 sa.startPreferencePanel(LocationSettings.class.getName(), null, 531 R.string.location_settings_title, null, null, 0); 532 break; 533 case ACTION_FORCE_STOP: 534 killProcesses(); 535 break; 536 case ACTION_REPORT: 537 reportBatteryUse(); 538 break; 539 } 540 } 541 542 private void fillDetailsSection() { 543 if (mTypes != null && mValues != null) { 544 for (int i = 0; i < mTypes.length; i++) { 545 // Only add an item if the time is greater than zero 546 if (mValues[i] <= 0) continue; 547 final String label = getString(mTypes[i]); 548 String value = null; 549 switch (mTypes[i]) { 550 case R.string.usage_type_data_recv: 551 case R.string.usage_type_data_send: 552 case R.string.usage_type_data_wifi_recv: 553 case R.string.usage_type_data_wifi_send: 554 final long packets = (long) (mValues[i]); 555 value = Long.toString(packets); 556 break; 557 case R.string.usage_type_no_coverage: 558 final int percentage = (int) Math.floor(mValues[i]); 559 value = Utils.formatPercentage(percentage); 560 break; 561 case R.string.usage_type_total_battery_capacity: 562 case R.string.usage_type_computed_power: 563 case R.string.usage_type_actual_power: 564 value = getActivity().getString(R.string.mah, (long)(mValues[i])); 565 break; 566 case R.string.usage_type_gps: 567 mUsesGps = true; 568 // Fall through 569 default: 570 value = Utils.formatElapsedTime(getActivity(), mValues[i], true); 571 } 572 addHorizontalPreference(mDetailsParent, label, value); 573 } 574 } 575 } 576 577 private void addHorizontalPreference(PreferenceCategory parent, CharSequence title, 578 CharSequence summary) { 579 Preference pref = new Preference(getPrefContext()); 580 pref.setLayoutResource(R.layout.horizontal_preference); 581 pref.setTitle(title); 582 pref.setSummary(summary); 583 pref.setSelectable(false); 584 parent.addPreference(pref); 585 } 586 587 private void fillControlsSection(int uid) { 588 PackageManager pm = getActivity().getPackageManager(); 589 String[] packages = pm.getPackagesForUid(uid); 590 PackageInfo pi = null; 591 try { 592 pi = packages != null ? pm.getPackageInfo(packages[0], 0) : null; 593 } catch (NameNotFoundException nnfe) { /* Nothing */ } 594 ApplicationInfo ai = pi != null? pi.applicationInfo : null; 595 596 boolean removeHeader = true; 597 switch (mDrainType) { 598 case APP: 599 // If it is a Java application and only one package is associated with the Uid 600 if (packages != null && packages.length == 1) { 601 addControl(R.string.battery_action_app_details, 602 R.string.battery_sugg_apps_info, ACTION_APP_DETAILS); 603 removeHeader = false; 604 // If the application has a settings screen, jump to that 605 // TODO: 606 } 607 // If power usage detail page is launched from location page, suppress "Location" 608 // button to prevent circular loops. 609 if (mUsesGps && mShowLocationButton) { 610 addControl(R.string.location_settings_title, 611 R.string.battery_sugg_apps_gps, ACTION_LOCATION_SETTINGS); 612 removeHeader = false; 613 } 614 break; 615 case SCREEN: 616 addControl(R.string.display_settings, 617 R.string.battery_sugg_display, 618 ACTION_DISPLAY_SETTINGS); 619 removeHeader = false; 620 break; 621 case WIFI: 622 addControl(R.string.wifi_settings, 623 R.string.battery_sugg_wifi, 624 ACTION_WIFI_SETTINGS); 625 removeHeader = false; 626 break; 627 case BLUETOOTH: 628 addControl(R.string.bluetooth_settings, 629 R.string.battery_sugg_bluetooth_basic, 630 ACTION_BLUETOOTH_SETTINGS); 631 removeHeader = false; 632 break; 633 case CELL: 634 if (mNoCoverage > 10) { 635 addControl(R.string.radio_controls_title, 636 R.string.battery_sugg_radio, 637 ACTION_WIRELESS_SETTINGS); 638 removeHeader = false; 639 } 640 break; 641 } 642 if (removeHeader) { 643 mControlsParent.setTitle(null); 644 } 645 } 646 647 private void addControl(int pageSummary, int actionTitle, final int action) { 648 Preference pref = new Preference(getPrefContext()); 649 pref.setTitle(actionTitle); 650 pref.setLayoutResource(R.layout.horizontal_preference); 651 pref.setOnPreferenceClickListener(new OnPreferenceClickListener() { 652 @Override 653 public boolean onPreferenceClick(Preference preference) { 654 doAction(action); 655 return true; 656 } 657 }); 658 mControlsParent.addPreference(pref); 659 } 660 661 private void fillMessagesSection(int uid) { 662 boolean removeHeader = true; 663 switch (mDrainType) { 664 case UNACCOUNTED: 665 addMessage(R.string.battery_msg_unaccounted); 666 removeHeader = false; 667 break; 668 } 669 if (removeHeader) { 670 mMessagesParent.setTitle(null); 671 } 672 } 673 674 private void addMessage(int message) { 675 addHorizontalPreference(mMessagesParent, getString(message), null); 676 } 677 678 private void removePackagesSection() { 679 getPreferenceScreen().removePreference(mPackagesParent); 680 } 681 682 private void killProcesses() { 683 if (mPackages == null) return; 684 ActivityManager am = (ActivityManager)getActivity().getSystemService( 685 Context.ACTIVITY_SERVICE); 686 final int userId = UserHandle.getUserId(mUid); 687 for (int i = 0; i < mPackages.length; i++) { 688 am.forceStopPackageAsUser(mPackages[i], userId); 689 } 690 checkForceStop(); 691 } 692 693 private final BroadcastReceiver mCheckKillProcessesReceiver = new BroadcastReceiver() { 694 @Override 695 public void onReceive(Context context, Intent intent) { 696 mForceStopButton.setEnabled(getResultCode() != Activity.RESULT_CANCELED); 697 } 698 }; 699 700 private void checkForceStop() { 701 if (mPackages == null || mUid < Process.FIRST_APPLICATION_UID) { 702 mForceStopButton.setEnabled(false); 703 return; 704 } 705 for (int i = 0; i < mPackages.length; i++) { 706 if (mDpm.packageHasActiveAdmins(mPackages[i])) { 707 mForceStopButton.setEnabled(false); 708 return; 709 } 710 } 711 for (int i = 0; i < mPackages.length; i++) { 712 try { 713 ApplicationInfo info = mPm.getApplicationInfo(mPackages[i], 0); 714 if ((info.flags&ApplicationInfo.FLAG_STOPPED) == 0) { 715 mForceStopButton.setEnabled(true); 716 break; 717 } 718 } catch (PackageManager.NameNotFoundException e) { 719 } 720 } 721 Intent intent = new Intent(Intent.ACTION_QUERY_PACKAGE_RESTART, 722 Uri.fromParts("package", mPackages[0], null)); 723 intent.putExtra(Intent.EXTRA_PACKAGES, mPackages); 724 intent.putExtra(Intent.EXTRA_UID, mUid); 725 intent.putExtra(Intent.EXTRA_USER_HANDLE, UserHandle.getUserId(mUid)); 726 getActivity().sendOrderedBroadcast(intent, null, mCheckKillProcessesReceiver, null, 727 Activity.RESULT_CANCELED, null, null); 728 } 729 730 private void reportBatteryUse() { 731 if (mPackages == null) return; 732 733 ApplicationErrorReport report = new ApplicationErrorReport(); 734 report.type = ApplicationErrorReport.TYPE_BATTERY; 735 report.packageName = mPackages[0]; 736 report.installerPackageName = mInstaller.getPackageName(); 737 report.processName = mPackages[0]; 738 report.time = System.currentTimeMillis(); 739 report.systemApp = (mApp.flags & ApplicationInfo.FLAG_SYSTEM) != 0; 740 741 final Bundle args = getArguments(); 742 ApplicationErrorReport.BatteryInfo batteryInfo = new ApplicationErrorReport.BatteryInfo(); 743 batteryInfo.usagePercent = args.getInt(EXTRA_PERCENT, 1); 744 batteryInfo.durationMicros = args.getLong(EXTRA_USAGE_DURATION, 0); 745 batteryInfo.usageDetails = args.getString(EXTRA_REPORT_DETAILS); 746 batteryInfo.checkinDetails = args.getString(EXTRA_REPORT_CHECKIN_DETAILS); 747 report.batteryInfo = batteryInfo; 748 749 Intent result = new Intent(Intent.ACTION_APP_ERROR); 750 result.setComponent(mInstaller); 751 result.putExtra(Intent.EXTRA_BUG_REPORT, report); 752 result.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 753 startActivity(result); 754 } 755 756 private void fillPackagesSection(int uid) { 757 if (uid < 1) { 758 removePackagesSection(); 759 return; 760 } 761 if (mPackages == null || mPackages.length < 2) { 762 removePackagesSection(); 763 return; 764 } 765 766 PackageManager pm = getPackageManager(); 767 // Convert package names to user-facing labels where possible 768 for (int i = 0; i < mPackages.length; i++) { 769 try { 770 ApplicationInfo ai = pm.getApplicationInfo(mPackages[i], 0); 771 CharSequence label = ai.loadLabel(pm); 772 if (label != null) { 773 mPackages[i] = label.toString(); 774 } 775 addHorizontalPreference(mPackagesParent, mPackages[i], null); 776 } catch (NameNotFoundException e) { 777 } 778 } 779 } 780 } 781