OSDN Git Service

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