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