OSDN Git Service

Merge tag 'android-6.0.1_r74' into HEAD
[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.graphics.PorterDuff;
33 import android.net.Uri;
34 import android.os.BatteryStats;
35 import android.os.Bundle;
36 import android.os.Process;
37 import android.os.UserHandle;
38 import android.preference.Preference;
39 import android.preference.Preference.OnPreferenceClickListener;
40 import android.preference.PreferenceCategory;
41 import android.text.TextUtils;
42 import android.util.Log;
43 import android.view.View;
44 import android.widget.Button;
45
46 import com.android.internal.logging.MetricsLogger;
47 import com.android.internal.os.BatterySipper;
48 import com.android.internal.os.BatterySipper.DrainType;
49 import com.android.internal.os.BatteryStatsHelper;
50 import com.android.internal.util.FastPrintWriter;
51 import com.android.settings.AppHeader;
52 import com.android.settings.DisplaySettings;
53 import com.android.settings.R;
54 import com.android.settings.SettingsActivity;
55 import com.android.settings.Utils;
56 import com.android.settings.WirelessSettings;
57 import com.android.settings.applications.AppInfoWithHeader;
58 import com.android.settings.applications.InstalledAppDetails;
59 import com.android.settings.applications.LayoutPreference;
60 import com.android.settings.bluetooth.BluetoothSettings;
61 import com.android.settings.location.LocationSettings;
62 import com.android.settings.wifi.WifiSettings;
63
64 import java.io.PrintWriter;
65 import java.io.StringWriter;
66 import java.io.Writer;
67
68 public class PowerUsageDetail extends PowerUsageBase implements Button.OnClickListener {
69
70     // Note: Must match the sequence of the DrainType
71     private static int[] sDrainTypeDesciptions = new int[] {
72         R.string.battery_desc_standby,
73         R.string.battery_desc_radio,
74         R.string.battery_desc_voice,
75         R.string.battery_desc_wifi,
76         R.string.battery_desc_bluetooth,
77         R.string.battery_desc_flashlight,
78         R.string.battery_desc_display,
79         R.string.battery_desc_apps,
80         R.string.battery_desc_users,
81         R.string.battery_desc_unaccounted,
82         R.string.battery_desc_overcounted,
83         R.string.battery_desc_camera,
84     };
85
86     public static void startBatteryDetailPage(
87             SettingsActivity caller, BatteryStatsHelper helper, int statsType, BatteryEntry entry,
88             boolean showLocationButton) {
89         // Initialize mStats if necessary.
90         final BatteryStats stats = helper.getStats();
91         helper.getDockStats();
92
93         final int dischargeAmount = stats.getDischargeAmount(statsType);
94         Bundle args = new Bundle();
95         args.putString(PowerUsageDetail.EXTRA_TITLE, entry.name);
96         args.putInt(PowerUsageDetail.EXTRA_PERCENT, (int)
97                 ((entry.sipper.totalPowerMah * dischargeAmount / helper.getTotalPower()) + .5));
98         args.putInt(PowerUsageDetail.EXTRA_GAUGE, (int)
99                 Math.ceil(entry.sipper.totalPowerMah * 100 / helper.getMaxPower()));
100         args.putLong(PowerUsageDetail.EXTRA_USAGE_DURATION, helper.getStatsPeriod());
101         args.putString(PowerUsageDetail.EXTRA_ICON_PACKAGE, entry.defaultPackageName);
102         args.putInt(PowerUsageDetail.EXTRA_ICON_ID, entry.iconId);
103         args.putDouble(PowerUsageDetail.EXTRA_NO_COVERAGE, entry.sipper.noCoveragePercent);
104         if (entry.sipper.uidObj != null) {
105             args.putInt(PowerUsageDetail.EXTRA_UID, entry.sipper.uidObj.getUid());
106         }
107         args.putSerializable(PowerUsageDetail.EXTRA_DRAIN_TYPE, entry.sipper.drainType);
108         args.putBoolean(PowerUsageDetail.EXTRA_SHOW_LOCATION_BUTTON, showLocationButton);
109
110         int userId = UserHandle.myUserId();
111         int[] types;
112         double[] values;
113         switch (entry.sipper.drainType) {
114             case APP:
115             case USER:
116             {
117                 BatteryStats.Uid uid = entry.sipper.uidObj;
118                 types = new int[] {
119                     R.string.usage_type_cpu,
120                     R.string.usage_type_cpu_foreground,
121                     R.string.usage_type_wake_lock,
122                     R.string.usage_type_gps,
123                     R.string.usage_type_wifi_running,
124                     R.string.usage_type_data_recv,
125                     R.string.usage_type_data_send,
126                     R.string.usage_type_radio_active,
127                     R.string.usage_type_data_wifi_recv,
128                     R.string.usage_type_data_wifi_send,
129                     R.string.usage_type_audio,
130                     R.string.usage_type_video,
131                     R.string.usage_type_camera,
132                     R.string.usage_type_flashlight,
133                     R.string.usage_type_computed_power,
134                 };
135                 values = new double[] {
136                     entry.sipper.cpuTimeMs,
137                     entry.sipper.cpuFgTimeMs,
138                     entry.sipper.wakeLockTimeMs,
139                     entry.sipper.gpsTimeMs,
140                     entry.sipper.wifiRunningTimeMs,
141                     entry.sipper.mobileRxPackets,
142                     entry.sipper.mobileTxPackets,
143                     entry.sipper.mobileActive,
144                     entry.sipper.wifiRxPackets,
145                     entry.sipper.wifiTxPackets,
146                     0,
147                     0,
148                     entry.sipper.cameraTimeMs,
149                     entry.sipper.flashlightTimeMs,
150                     entry.sipper.totalPowerMah,
151                 };
152
153                 if (entry.sipper.drainType == BatterySipper.DrainType.APP) {
154                     Writer result = new StringWriter();
155                     PrintWriter printWriter = new FastPrintWriter(result, false, 1024);
156                     stats.dumpLocked(caller, printWriter, "", helper.getStatsType(), uid.getUid());
157                     printWriter.flush();
158                     args.putString(PowerUsageDetail.EXTRA_REPORT_DETAILS, result.toString());
159
160                     result = new StringWriter();
161                     printWriter = new FastPrintWriter(result, false, 1024);
162                     stats.dumpCheckinLocked(caller, printWriter, helper.getStatsType(), 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         hideRefreshButton(true);
358
359         createDetails();
360     }
361
362     @Override
363     protected int getMetricsCategory() {
364         return MetricsLogger.FUELGAUGE_POWER_USAGE_DETAIL;
365     }
366
367     @Override
368     public void onResume() {
369         super.onResume();
370         mStartTime = android.os.Process.getElapsedCpuTime();
371         checkForceStop();
372         if (mHighPower != null) {
373             mHighPower.setSummary(HighPowerDetail.getSummary(getActivity(), mApp.packageName));
374         }
375
376         setupHeader();
377     }
378
379     @Override
380     public void onActivityResult(int requestCode, int resultCode, Intent data) {
381         super.onActivityResult(requestCode, resultCode, data);
382         if (mHighPower != null) {
383             mHighPower.setSummary(HighPowerDetail.getSummary(getActivity(), mApp.packageName));
384         }
385     }
386
387     private void createDetails() {
388         final Bundle args = getArguments();
389         Context context = getActivity();
390         mUsageSince = args.getInt(EXTRA_USAGE_SINCE, USAGE_SINCE_UNPLUGGED);
391         mUid = args.getInt(EXTRA_UID, 0);
392         mPackages = context.getPackageManager().getPackagesForUid(mUid);
393         mDrainType = (BatterySipper.DrainType) args.getSerializable(EXTRA_DRAIN_TYPE);
394         mNoCoverage = args.getDouble(EXTRA_NO_COVERAGE, 0);
395         mShowLocationButton = args.getBoolean(EXTRA_SHOW_LOCATION_BUTTON);
396
397         mTypes = args.getIntArray(EXTRA_DETAIL_TYPES);
398         mValues = args.getDoubleArray(EXTRA_DETAIL_VALUES);
399
400         LayoutPreference twoButtons = (LayoutPreference) findPreference(KEY_TWO_BUTTONS);
401         mForceStopButton = (Button) twoButtons.findViewById(R.id.left_button);
402         mReportButton = (Button) twoButtons.findViewById(R.id.right_button);
403         mForceStopButton.setEnabled(false);
404
405         if (mUid >= Process.FIRST_APPLICATION_UID) {
406             mForceStopButton.setText(R.string.force_stop);
407             mForceStopButton.setTag(ACTION_FORCE_STOP);
408             mForceStopButton.setOnClickListener(this);
409             mReportButton.setText(com.android.internal.R.string.report);
410             mReportButton.setTag(ACTION_REPORT);
411             mReportButton.setOnClickListener(this);
412
413             if (mPackages != null && mPackages.length > 0) {
414                 try {
415                     mApp = context.getPackageManager().getApplicationInfo(
416                             mPackages[0], 0);
417                 } catch (NameNotFoundException e) {
418                 }
419             } else {
420                 Log.d(TAG, "No packages!!");
421             }
422             // check if error reporting is enabled in secure settings
423             int enabled = android.provider.Settings.Global.getInt(context.getContentResolver(),
424                     android.provider.Settings.Global.SEND_ACTION_APP_ERROR, 0);
425             if (enabled != 0) {
426                 if (mApp != null) {
427                     mInstaller = ApplicationErrorReport.getErrorReportReceiver(
428                             context, mPackages[0], mApp.flags);
429                 }
430                 mReportButton.setEnabled(mInstaller != null);
431             } else {
432                 removePreference(KEY_TWO_BUTTONS);
433             }
434             if (mApp != null
435                     && PowerWhitelistBackend.getInstance().isWhitelisted(mApp.packageName)) {
436                 mHighPower = findPreference(KEY_HIGH_POWER);
437                 mHighPower.setOnPreferenceClickListener(new OnPreferenceClickListener() {
438                     @Override
439                     public boolean onPreferenceClick(Preference preference) {
440                         HighPowerDetail.show(PowerUsageDetail.this, mApp.packageName, 0, false);
441                         return true;
442                     }
443                 });
444             } else {
445                 mControlsParent.removePreference(findPreference(KEY_HIGH_POWER));
446             }
447         } else {
448             removePreference(KEY_TWO_BUTTONS);
449             mControlsParent.removePreference(findPreference(KEY_HIGH_POWER));
450         }
451
452         refreshStats();
453
454         fillDetailsSection();
455         fillPackagesSection(mUid);
456         fillControlsSection(mUid);
457         fillMessagesSection(mUid);
458     }
459
460     private void setupHeader() {
461         final Bundle args = getArguments();
462         String title = args.getString(EXTRA_TITLE);
463         String pkg = args.getString(EXTRA_ICON_PACKAGE);
464         int iconId = args.getInt(EXTRA_ICON_ID, 0);
465         Drawable appIcon = null;
466
467         if (!TextUtils.isEmpty(pkg)) {
468             try {
469                 final PackageManager pm = getActivity().getPackageManager();
470                 ApplicationInfo ai = pm.getPackageInfo(pkg, 0).applicationInfo;
471                 if (ai != null) {
472                     appIcon = ai.loadIcon(pm);
473                 }
474             } catch (NameNotFoundException nnfe) {
475                 // Use default icon
476             }
477         } else if (iconId != 0) {
478             appIcon = getActivity().getDrawable(iconId);
479         }
480         if (appIcon == null) {
481             appIcon = getActivity().getPackageManager().getDefaultActivityIcon();
482         }
483         if (appIcon != null) {
484             appIcon.setTintMode(PorterDuff.Mode.SRC_ATOP);
485         }
486         if (pkg == null && mPackages != null) {
487             pkg = mPackages[0];
488         }
489         AppHeader.createAppHeader(this, appIcon, title,
490                 pkg != null ? AppInfoWithHeader.getInfoIntent(this, pkg) : null,
491                 mDrainType != DrainType.APP ? R.color.power_usage_ab_icon_tint : 0);
492     }
493
494     public void onClick(View v) {
495         doAction((Integer) v.getTag());
496     }
497
498     // utility method used to start sub activity
499     private void startApplicationDetailsActivity() {
500         // start new fragment to display extended information
501         Bundle args = new Bundle();
502         args.putString(InstalledAppDetails.ARG_PACKAGE_NAME, mPackages[0]);
503
504         SettingsActivity sa = (SettingsActivity) getActivity();
505         sa.startPreferencePanel(InstalledAppDetails.class.getName(), args,
506                 R.string.application_info_label, null, null, 0);
507     }
508
509     private void doAction(int action) {
510         SettingsActivity sa = (SettingsActivity)getActivity();
511         switch (action) {
512             case ACTION_DISPLAY_SETTINGS:
513                 sa.startPreferencePanel(DisplaySettings.class.getName(), null,
514                         R.string.display_settings_title, null, null, 0);
515                 break;
516             case ACTION_WIFI_SETTINGS:
517                 sa.startPreferencePanel(WifiSettings.class.getName(), null,
518                         R.string.wifi_settings, null, null, 0);
519                 break;
520             case ACTION_BLUETOOTH_SETTINGS:
521                 sa.startPreferencePanel(BluetoothSettings.class.getName(), null,
522                         R.string.bluetooth_settings, null, null, 0);
523                 break;
524             case ACTION_WIRELESS_SETTINGS:
525                 sa.startPreferencePanel(WirelessSettings.class.getName(), null,
526                         R.string.radio_controls_title, null, null, 0);
527                 break;
528             case ACTION_APP_DETAILS:
529                 startApplicationDetailsActivity();
530                 break;
531             case ACTION_LOCATION_SETTINGS:
532                 sa.startPreferencePanel(LocationSettings.class.getName(), null,
533                         R.string.location_settings_title, null, null, 0);
534                 break;
535             case ACTION_FORCE_STOP:
536                 killProcesses();
537                 break;
538             case ACTION_REPORT:
539                 reportBatteryUse();
540                 break;
541         }
542     }
543
544     private void fillDetailsSection() {
545         if (mTypes != null && mValues != null) {
546             for (int i = 0; i < mTypes.length; i++) {
547                 // Only add an item if the time is greater than zero
548                 if (mValues[i] <= 0) continue;
549                 final String label = getString(mTypes[i]);
550                 String value = null;
551                 switch (mTypes[i]) {
552                     case R.string.usage_type_data_recv:
553                     case R.string.usage_type_data_send:
554                     case R.string.usage_type_data_wifi_recv:
555                     case R.string.usage_type_data_wifi_send:
556                         final long packets = (long) (mValues[i]);
557                         value = Long.toString(packets);
558                         break;
559                     case R.string.usage_type_no_coverage:
560                         final int percentage = (int) Math.floor(mValues[i]);
561                         value = Utils.formatPercentage(percentage);
562                         break;
563                     case R.string.usage_type_total_battery_capacity:
564                     case R.string.usage_type_computed_power:
565                     case R.string.usage_type_actual_power:
566                         value = getActivity().getString(R.string.mah, (long)(mValues[i]));
567                         break;
568                     case R.string.usage_type_gps:
569                         mUsesGps = true;
570                         // Fall through
571                     default:
572                         value = Utils.formatElapsedTime(getActivity(), mValues[i], true);
573                 }
574                 addHorizontalPreference(mDetailsParent, label, value);
575             }
576         }
577     }
578
579     private void addHorizontalPreference(PreferenceCategory parent, CharSequence title,
580             CharSequence summary) {
581         Preference pref = new Preference(getActivity());
582         pref.setLayoutResource(R.layout.horizontal_preference);
583         pref.setTitle(title);
584         pref.setSummary(summary);
585         pref.setSelectable(false);
586         parent.addPreference(pref);
587     }
588
589     private void fillControlsSection(int uid) {
590         PackageManager pm = getActivity().getPackageManager();
591         String[] packages = pm.getPackagesForUid(uid);
592         PackageInfo pi = null;
593         try {
594             pi = packages != null ? pm.getPackageInfo(packages[0], 0) : null;
595         } catch (NameNotFoundException nnfe) { /* Nothing */ }
596         ApplicationInfo ai = pi != null? pi.applicationInfo : null;
597
598         boolean removeHeader = true;
599         switch (mDrainType) {
600             case APP:
601                 // If it is a Java application and only one package is associated with the Uid
602                 if (packages != null && packages.length == 1) {
603                     addControl(R.string.battery_action_app_details,
604                             R.string.battery_sugg_apps_info, ACTION_APP_DETAILS);
605                     removeHeader = false;
606                     // If the application has a settings screen, jump to  that
607                     // TODO:
608                 }
609                 // If power usage detail page is launched from location page, suppress "Location"
610                 // button to prevent circular loops.
611                 if (mUsesGps && mShowLocationButton) {
612                     addControl(R.string.location_settings_title,
613                             R.string.battery_sugg_apps_gps, ACTION_LOCATION_SETTINGS);
614                     removeHeader = false;
615                 }
616                 break;
617             case SCREEN:
618                 addControl(R.string.display_settings,
619                         R.string.battery_sugg_display,
620                         ACTION_DISPLAY_SETTINGS);
621                 removeHeader = false;
622                 break;
623             case WIFI:
624                 addControl(R.string.wifi_settings,
625                         R.string.battery_sugg_wifi,
626                         ACTION_WIFI_SETTINGS);
627                 removeHeader = false;
628                 break;
629             case BLUETOOTH:
630                 addControl(R.string.bluetooth_settings,
631                         R.string.battery_sugg_bluetooth_basic,
632                         ACTION_BLUETOOTH_SETTINGS);
633                 removeHeader = false;
634                 break;
635             case CELL:
636                 if (mNoCoverage > 10) {
637                     addControl(R.string.radio_controls_title,
638                             R.string.battery_sugg_radio,
639                             ACTION_WIRELESS_SETTINGS);
640                     removeHeader = false;
641                 }
642                 break;
643         }
644         if (removeHeader) {
645             mControlsParent.setTitle(null);
646         }
647     }
648
649     private void addControl(int pageSummary, int actionTitle, final int action) {
650         Preference pref = new Preference(getActivity());
651         pref.setTitle(actionTitle);
652         pref.setLayoutResource(R.layout.horizontal_preference);
653         pref.setOnPreferenceClickListener(new OnPreferenceClickListener() {
654             @Override
655             public boolean onPreferenceClick(Preference preference) {
656                 doAction(action);
657                 return true;
658             }
659         });
660         mControlsParent.addPreference(pref);
661     }
662
663     private void fillMessagesSection(int uid) {
664         boolean removeHeader = true;
665         switch (mDrainType) {
666             case UNACCOUNTED:
667                 addMessage(R.string.battery_msg_unaccounted);
668                 removeHeader = false;
669                 break;
670         }
671         if (removeHeader) {
672             mMessagesParent.setTitle(null);
673         }
674     }
675
676     private void addMessage(int message) {
677         addHorizontalPreference(mMessagesParent, getString(message), null);
678     }
679
680     private void removePackagesSection() {
681         getPreferenceScreen().removePreference(mPackagesParent);
682     }
683
684     private void killProcesses() {
685         if (mPackages == null) return;
686         ActivityManager am = (ActivityManager)getActivity().getSystemService(
687                 Context.ACTIVITY_SERVICE);
688         final int userId = UserHandle.getUserId(mUid);
689         for (int i = 0; i < mPackages.length; i++) {
690             am.forceStopPackageAsUser(mPackages[i], userId);
691         }
692         checkForceStop();
693     }
694
695     private final BroadcastReceiver mCheckKillProcessesReceiver = new BroadcastReceiver() {
696         @Override
697         public void onReceive(Context context, Intent intent) {
698             mForceStopButton.setEnabled(getResultCode() != Activity.RESULT_CANCELED);
699         }
700     };
701
702     private void checkForceStop() {
703         if (mPackages == null || mUid < Process.FIRST_APPLICATION_UID) {
704             mForceStopButton.setEnabled(false);
705             return;
706         }
707         for (int i = 0; i < mPackages.length; i++) {
708             if (mDpm.packageHasActiveAdmins(mPackages[i])) {
709                 mForceStopButton.setEnabled(false);
710                 return;
711             }
712         }
713         for (int i = 0; i < mPackages.length; i++) {
714             try {
715                 ApplicationInfo info = mPm.getApplicationInfo(mPackages[i], 0);
716                 if ((info.flags&ApplicationInfo.FLAG_STOPPED) == 0) {
717                     mForceStopButton.setEnabled(true);
718                     break;
719                 }
720             } catch (PackageManager.NameNotFoundException e) {
721             }
722         }
723         Intent intent = new Intent(Intent.ACTION_QUERY_PACKAGE_RESTART,
724                 Uri.fromParts("package", mPackages[0], null));
725         intent.putExtra(Intent.EXTRA_PACKAGES, mPackages);
726         intent.putExtra(Intent.EXTRA_UID, mUid);
727         intent.putExtra(Intent.EXTRA_USER_HANDLE, UserHandle.getUserId(mUid));
728         getActivity().sendOrderedBroadcast(intent, null, mCheckKillProcessesReceiver, null,
729                 Activity.RESULT_CANCELED, null, null);
730     }
731
732     private void reportBatteryUse() {
733         if (mPackages == null) return;
734
735         ApplicationErrorReport report = new ApplicationErrorReport();
736         report.type = ApplicationErrorReport.TYPE_BATTERY;
737         report.packageName = mPackages[0];
738         report.installerPackageName = mInstaller.getPackageName();
739         report.processName = mPackages[0];
740         report.time = System.currentTimeMillis();
741         report.systemApp = (mApp.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
742
743         final Bundle args = getArguments();
744         ApplicationErrorReport.BatteryInfo batteryInfo = new ApplicationErrorReport.BatteryInfo();
745         batteryInfo.usagePercent = args.getInt(EXTRA_PERCENT, 1);
746         batteryInfo.durationMicros = args.getLong(EXTRA_USAGE_DURATION, 0);
747         batteryInfo.usageDetails = args.getString(EXTRA_REPORT_DETAILS);
748         batteryInfo.checkinDetails = args.getString(EXTRA_REPORT_CHECKIN_DETAILS);
749         report.batteryInfo = batteryInfo;
750
751         Intent result = new Intent(Intent.ACTION_APP_ERROR);
752         result.setComponent(mInstaller);
753         result.putExtra(Intent.EXTRA_BUG_REPORT, report);
754         result.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
755         startActivity(result);
756     }
757
758     private void fillPackagesSection(int uid) {
759         if (uid < 1) {
760             removePackagesSection();
761             return;
762         }
763         if (mPackages == null || mPackages.length < 2) {
764             removePackagesSection();
765             return;
766         }
767
768         PackageManager pm = getPackageManager();
769         // Convert package names to user-facing labels where possible
770         for (int i = 0; i < mPackages.length; i++) {
771             try {
772                 ApplicationInfo ai = pm.getApplicationInfo(mPackages[i], 0);
773                 CharSequence label = ai.loadLabel(pm);
774                 if (label != null) {
775                     mPackages[i] = label.toString();
776                 }
777                 addHorizontalPreference(mPackagesParent, mPackages[i], null);
778             } catch (NameNotFoundException e) {
779             }
780         }
781     }
782 }