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.preference.Preference;
     38 import android.preference.Preference.OnPreferenceClickListener;
     39 import android.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.MetricsLogger;
     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.AppInfoWithHeader;
     57 import com.android.settings.applications.InstalledAppDetails;
     58 import com.android.settings.applications.LayoutPreference;
     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 PowerUsageBase 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         R.string.battery_desc_camera,
     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                     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 MetricsLogger.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 
    466         if (!TextUtils.isEmpty(pkg)) {
    467             try {
    468                 final PackageManager pm = getActivity().getPackageManager();
    469                 ApplicationInfo ai = pm.getPackageInfo(pkg, 0).applicationInfo;
    470                 if (ai != null) {
    471                     appIcon = ai.loadIcon(pm);
    472                 }
    473             } catch (NameNotFoundException nnfe) {
    474                 // Use default icon
    475             }
    476         } else if (iconId != 0) {
    477             appIcon = getActivity().getDrawable(iconId);
    478         }
    479         if (appIcon == null) {
    480             appIcon = getActivity().getPackageManager().getDefaultActivityIcon();
    481         }
    482 
    483         if (pkg == null && mPackages != null) {
    484             pkg = mPackages[0];
    485         }
    486         AppHeader.createAppHeader(this, appIcon, title,
    487                 pkg != null ? AppInfoWithHeader.getInfoIntent(this, pkg) : null,
    488                 mDrainType != DrainType.APP ? android.R.color.white : 0);
    489     }
    490 
    491     public void onClick(View v) {
    492         doAction((Integer) v.getTag());
    493     }
    494 
    495     // utility method used to start sub activity
    496     private void startApplicationDetailsActivity() {
    497         // start new fragment to display extended information
    498         Bundle args = new Bundle();
    499         args.putString(InstalledAppDetails.ARG_PACKAGE_NAME, mPackages[0]);
    500 
    501         SettingsActivity sa = (SettingsActivity) getActivity();
    502         sa.startPreferencePanel(InstalledAppDetails.class.getName(), args,
    503                 R.string.application_info_label, null, null, 0);
    504     }
    505 
    506     private void doAction(int action) {
    507         SettingsActivity sa = (SettingsActivity)getActivity();
    508         switch (action) {
    509             case ACTION_DISPLAY_SETTINGS:
    510                 sa.startPreferencePanel(DisplaySettings.class.getName(), null,
    511                         R.string.display_settings_title, null, null, 0);
    512                 break;
    513             case ACTION_WIFI_SETTINGS:
    514                 sa.startPreferencePanel(WifiSettings.class.getName(), null,
    515                         R.string.wifi_settings, null, null, 0);
    516                 break;
    517             case ACTION_BLUETOOTH_SETTINGS:
    518                 sa.startPreferencePanel(BluetoothSettings.class.getName(), null,
    519                         R.string.bluetooth_settings, null, null, 0);
    520                 break;
    521             case ACTION_WIRELESS_SETTINGS:
    522                 sa.startPreferencePanel(WirelessSettings.class.getName(), null,
    523                         R.string.radio_controls_title, null, null, 0);
    524                 break;
    525             case ACTION_APP_DETAILS:
    526                 startApplicationDetailsActivity();
    527                 break;
    528             case ACTION_LOCATION_SETTINGS:
    529                 sa.startPreferencePanel(LocationSettings.class.getName(), null,
    530                         R.string.location_settings_title, null, null, 0);
    531                 break;
    532             case ACTION_FORCE_STOP:
    533                 killProcesses();
    534                 break;
    535             case ACTION_REPORT:
    536                 reportBatteryUse();
    537                 break;
    538         }
    539     }
    540 
    541     private void fillDetailsSection() {
    542         if (mTypes != null && mValues != null) {
    543             for (int i = 0; i < mTypes.length; i++) {
    544                 // Only add an item if the time is greater than zero
    545                 if (mValues[i] <= 0) continue;
    546                 final String label = getString(mTypes[i]);
    547                 String value = null;
    548                 switch (mTypes[i]) {
    549                     case R.string.usage_type_data_recv:
    550                     case R.string.usage_type_data_send:
    551                     case R.string.usage_type_data_wifi_recv:
    552                     case R.string.usage_type_data_wifi_send:
    553                         final long packets = (long) (mValues[i]);
    554                         value = Long.toString(packets);
    555                         break;
    556                     case R.string.usage_type_no_coverage:
    557                         final int percentage = (int) Math.floor(mValues[i]);
    558                         value = Utils.formatPercentage(percentage);
    559                         break;
    560                     case R.string.usage_type_total_battery_capacity:
    561                     case R.string.usage_type_computed_power:
    562                     case R.string.usage_type_actual_power:
    563                         value = getActivity().getString(R.string.mah, (long)(mValues[i]));
    564                         break;
    565                     case R.string.usage_type_gps:
    566                         mUsesGps = true;
    567                         // Fall through
    568                     default:
    569                         value = Utils.formatElapsedTime(getActivity(), mValues[i], true);
    570                 }
    571                 addHorizontalPreference(mDetailsParent, label, value);
    572             }
    573         }
    574     }
    575 
    576     private void addHorizontalPreference(PreferenceCategory parent, CharSequence title,
    577             CharSequence summary) {
    578         Preference pref = new Preference(getActivity());
    579         pref.setLayoutResource(R.layout.horizontal_preference);
    580         pref.setTitle(title);
    581         pref.setSummary(summary);
    582         pref.setSelectable(false);
    583         parent.addPreference(pref);
    584     }
    585 
    586     private void fillControlsSection(int uid) {
    587         PackageManager pm = getActivity().getPackageManager();
    588         String[] packages = pm.getPackagesForUid(uid);
    589         PackageInfo pi = null;
    590         try {
    591             pi = packages != null ? pm.getPackageInfo(packages[0], 0) : null;
    592         } catch (NameNotFoundException nnfe) { /* Nothing */ }
    593         ApplicationInfo ai = pi != null? pi.applicationInfo : null;
    594 
    595         boolean removeHeader = true;
    596         switch (mDrainType) {
    597             case APP:
    598                 // If it is a Java application and only one package is associated with the Uid
    599                 if (packages != null && packages.length == 1) {
    600                     addControl(R.string.battery_action_app_details,
    601                             R.string.battery_sugg_apps_info, ACTION_APP_DETAILS);
    602                     removeHeader = false;
    603                     // If the application has a settings screen, jump to  that
    604                     // TODO:
    605                 }
    606                 // If power usage detail page is launched from location page, suppress "Location"
    607                 // button to prevent circular loops.
    608                 if (mUsesGps && mShowLocationButton) {
    609                     addControl(R.string.location_settings_title,
    610                             R.string.battery_sugg_apps_gps, ACTION_LOCATION_SETTINGS);
    611                     removeHeader = false;
    612                 }
    613                 break;
    614             case SCREEN:
    615                 addControl(R.string.display_settings,
    616                         R.string.battery_sugg_display,
    617                         ACTION_DISPLAY_SETTINGS);
    618                 removeHeader = false;
    619                 break;
    620             case WIFI:
    621                 addControl(R.string.wifi_settings,
    622                         R.string.battery_sugg_wifi,
    623                         ACTION_WIFI_SETTINGS);
    624                 removeHeader = false;
    625                 break;
    626             case BLUETOOTH:
    627                 addControl(R.string.bluetooth_settings,
    628                         R.string.battery_sugg_bluetooth_basic,
    629                         ACTION_BLUETOOTH_SETTINGS);
    630                 removeHeader = false;
    631                 break;
    632             case CELL:
    633                 if (mNoCoverage > 10) {
    634                     addControl(R.string.radio_controls_title,
    635                             R.string.battery_sugg_radio,
    636                             ACTION_WIRELESS_SETTINGS);
    637                     removeHeader = false;
    638                 }
    639                 break;
    640         }
    641         if (removeHeader) {
    642             mControlsParent.setTitle(null);
    643         }
    644     }
    645 
    646     private void addControl(int pageSummary, int actionTitle, final int action) {
    647         Preference pref = new Preference(getActivity());
    648         pref.setTitle(actionTitle);
    649         pref.setLayoutResource(R.layout.horizontal_preference);
    650         pref.setOnPreferenceClickListener(new OnPreferenceClickListener() {
    651             @Override
    652             public boolean onPreferenceClick(Preference preference) {
    653                 doAction(action);
    654                 return true;
    655             }
    656         });
    657         mControlsParent.addPreference(pref);
    658     }
    659 
    660     private void fillMessagesSection(int uid) {
    661         boolean removeHeader = true;
    662         switch (mDrainType) {
    663             case UNACCOUNTED:
    664                 addMessage(R.string.battery_msg_unaccounted);
    665                 removeHeader = false;
    666                 break;
    667         }
    668         if (removeHeader) {
    669             mMessagesParent.setTitle(null);
    670         }
    671     }
    672 
    673     private void addMessage(int message) {
    674         addHorizontalPreference(mMessagesParent, getString(message), null);
    675     }
    676 
    677     private void removePackagesSection() {
    678         getPreferenceScreen().removePreference(mPackagesParent);
    679     }
    680 
    681     private void killProcesses() {
    682         if (mPackages == null) return;
    683         ActivityManager am = (ActivityManager)getActivity().getSystemService(
    684                 Context.ACTIVITY_SERVICE);
    685         final int userId = UserHandle.getUserId(mUid);
    686         for (int i = 0; i < mPackages.length; i++) {
    687             am.forceStopPackageAsUser(mPackages[i], userId);
    688         }
    689         checkForceStop();
    690     }
    691 
    692     private final BroadcastReceiver mCheckKillProcessesReceiver = new BroadcastReceiver() {
    693         @Override
    694         public void onReceive(Context context, Intent intent) {
    695             mForceStopButton.setEnabled(getResultCode() != Activity.RESULT_CANCELED);
    696         }
    697     };
    698 
    699     private void checkForceStop() {
    700         if (mPackages == null || mUid < Process.FIRST_APPLICATION_UID) {
    701             mForceStopButton.setEnabled(false);
    702             return;
    703         }
    704         for (int i = 0; i < mPackages.length; i++) {
    705             if (mDpm.packageHasActiveAdmins(mPackages[i])) {
    706                 mForceStopButton.setEnabled(false);
    707                 return;
    708             }
    709         }
    710         for (int i = 0; i < mPackages.length; i++) {
    711             try {
    712                 ApplicationInfo info = mPm.getApplicationInfo(mPackages[i], 0);
    713                 if ((info.flags&ApplicationInfo.FLAG_STOPPED) == 0) {
    714                     mForceStopButton.setEnabled(true);
    715                     break;
    716                 }
    717             } catch (PackageManager.NameNotFoundException e) {
    718             }
    719         }
    720         Intent intent = new Intent(Intent.ACTION_QUERY_PACKAGE_RESTART,
    721                 Uri.fromParts("package", mPackages[0], null));
    722         intent.putExtra(Intent.EXTRA_PACKAGES, mPackages);
    723         intent.putExtra(Intent.EXTRA_UID, mUid);
    724         intent.putExtra(Intent.EXTRA_USER_HANDLE, UserHandle.getUserId(mUid));
    725         getActivity().sendOrderedBroadcast(intent, null, mCheckKillProcessesReceiver, null,
    726                 Activity.RESULT_CANCELED, null, null);
    727     }
    728 
    729     private void reportBatteryUse() {
    730         if (mPackages == null) return;
    731 
    732         ApplicationErrorReport report = new ApplicationErrorReport();
    733         report.type = ApplicationErrorReport.TYPE_BATTERY;
    734         report.packageName = mPackages[0];
    735         report.installerPackageName = mInstaller.getPackageName();
    736         report.processName = mPackages[0];
    737         report.time = System.currentTimeMillis();
    738         report.systemApp = (mApp.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
    739 
    740         final Bundle args = getArguments();
    741         ApplicationErrorReport.BatteryInfo batteryInfo = new ApplicationErrorReport.BatteryInfo();
    742         batteryInfo.usagePercent = args.getInt(EXTRA_PERCENT, 1);
    743         batteryInfo.durationMicros = args.getLong(EXTRA_USAGE_DURATION, 0);
    744         batteryInfo.usageDetails = args.getString(EXTRA_REPORT_DETAILS);
    745         batteryInfo.checkinDetails = args.getString(EXTRA_REPORT_CHECKIN_DETAILS);
    746         report.batteryInfo = batteryInfo;
    747 
    748         Intent result = new Intent(Intent.ACTION_APP_ERROR);
    749         result.setComponent(mInstaller);
    750         result.putExtra(Intent.EXTRA_BUG_REPORT, report);
    751         result.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    752         startActivity(result);
    753     }
    754 
    755     private void fillPackagesSection(int uid) {
    756         if (uid < 1) {
    757             removePackagesSection();
    758             return;
    759         }
    760         if (mPackages == null || mPackages.length < 2) {
    761             removePackagesSection();
    762             return;
    763         }
    764 
    765         PackageManager pm = getPackageManager();
    766         // Convert package names to user-facing labels where possible
    767         for (int i = 0; i < mPackages.length; i++) {
    768             try {
    769                 ApplicationInfo ai = pm.getApplicationInfo(mPackages[i], 0);
    770                 CharSequence label = ai.loadLabel(pm);
    771                 if (label != null) {
    772                     mPackages[i] = label.toString();
    773                 }
    774                 addHorizontalPreference(mPackagesParent, mPackages[i], null);
    775             } catch (NameNotFoundException e) {
    776             }
    777         }
    778     }
    779 }
    780