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