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