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