OSDN Git Service

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