Home | History | Annotate | Download | only in fuelgauge
      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 
     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
    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
    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
    348     public void onResume() {
    349         super.onResume();
    350         mStartTime = android.os.Process.getElapsedCpuTime();
    351         checkForceStop();
    352     }
    353 
    354     @Override
    355     public void onPause() {
    356         super.onPause();
    357     }
    358 
    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 
    452     public void onClick(View v) {
    453         doAction((Integer) v.getTag());
    454     }
    455 
    456     // utility method used to start sub activity
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    761     private String getDescriptionForDrainType() {
    762         return getResources().getString(sDrainTypeDesciptions[mDrainType.ordinal()]);
    763     }
    764 }
    765