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