OSDN Git Service

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