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