1 /* 2 * Copyright (C) 2017 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.admin.DevicePolicyManager; 21 import android.content.Context; 22 import android.content.Intent; 23 import android.content.pm.PackageManager; 24 import android.os.BatteryStats; 25 import android.os.Bundle; 26 import android.os.UserHandle; 27 import android.os.UserManager; 28 import android.support.annotation.VisibleForTesting; 29 import android.support.v14.preference.PreferenceFragment; 30 import android.support.v7.preference.Preference; 31 import android.view.View; 32 33 import com.android.internal.logging.nano.MetricsProto.MetricsEvent; 34 import com.android.internal.os.BatterySipper; 35 import com.android.internal.os.BatteryStatsHelper; 36 import com.android.internal.util.ArrayUtils; 37 import com.android.settings.R; 38 import com.android.settings.SettingsActivity; 39 import com.android.settings.Utils; 40 import com.android.settings.applications.AppHeaderController; 41 import com.android.settings.applications.LayoutPreference; 42 import com.android.settings.core.PreferenceController; 43 import com.android.settings.dashboard.DashboardFragment; 44 import com.android.settings.enterprise.DevicePolicyManagerWrapper; 45 import com.android.settings.enterprise.DevicePolicyManagerWrapperImpl; 46 import com.android.settings.overlay.FeatureFactory; 47 import com.android.settingslib.applications.AppUtils; 48 import com.android.settingslib.applications.ApplicationsState; 49 50 import java.util.ArrayList; 51 import java.util.List; 52 53 /** 54 * Power usage detail fragment for each app, this fragment contains 55 * 56 * 1. Detail battery usage information for app(i.e. usage time, usage amount) 57 * 2. Battery related controls for app(i.e uninstall, force stop) 58 * 59 */ 60 public class AdvancedPowerUsageDetail extends DashboardFragment implements 61 ButtonActionDialogFragment.AppButtonsDialogListener { 62 63 public static final String TAG = "AdvancedPowerUsageDetail"; 64 public static final String EXTRA_UID = "extra_uid"; 65 public static final String EXTRA_PACKAGE_NAME = "extra_package_name"; 66 public static final String EXTRA_FOREGROUND_TIME = "extra_foreground_time"; 67 public static final String EXTRA_BACKGROUND_TIME = "extra_background_time"; 68 public static final String EXTRA_LABEL = "extra_label"; 69 public static final String EXTRA_ICON_ID = "extra_icon_id"; 70 public static final String EXTRA_POWER_USAGE_PERCENT = "extra_power_usage_percent"; 71 public static final String EXTRA_POWER_USAGE_AMOUNT = "extra_power_usage_amount"; 72 73 private static final String KEY_PREF_FOREGROUND = "app_usage_foreground"; 74 private static final String KEY_PREF_BACKGROUND = "app_usage_background"; 75 private static final String KEY_PREF_POWER_USAGE = "app_power_usage"; 76 private static final String KEY_PREF_HEADER = "header_view"; 77 78 private static final int REQUEST_UNINSTALL = 0; 79 private static final int REQUEST_REMOVE_DEVICE_ADMIN = 1; 80 81 @VisibleForTesting 82 LayoutPreference mHeaderPreference; 83 @VisibleForTesting 84 ApplicationsState mState; 85 @VisibleForTesting 86 ApplicationsState.AppEntry mAppEntry; 87 @VisibleForTesting 88 BatteryUtils mBatteryUtils; 89 90 private Preference mForegroundPreference; 91 private Preference mBackgroundPreference; 92 private Preference mPowerUsagePreference; 93 private AppButtonsPreferenceController mAppButtonsPreferenceController; 94 95 private DevicePolicyManagerWrapper mDpm; 96 private UserManager mUserManager; 97 private PackageManager mPackageManager; 98 99 public static void startBatteryDetailPage(SettingsActivity caller, PreferenceFragment fragment, 100 BatteryStatsHelper helper, int which, BatteryEntry entry, String usagePercent) { 101 // Initialize mStats if necessary. 102 helper.getStats(); 103 104 final Bundle args = new Bundle(); 105 final BatterySipper sipper = entry.sipper; 106 final BatteryStats.Uid uid = sipper.uidObj; 107 final BatteryUtils batteryUtils = BatteryUtils.getInstance(caller); 108 final boolean isTypeApp = sipper.drainType == BatterySipper.DrainType.APP; 109 110 final long foregroundTimeMs = isTypeApp ? batteryUtils.getProcessTimeMs( 111 BatteryUtils.StatusType.FOREGROUND, uid, which) : sipper.usageTimeMs; 112 final long backgroundTimeMs = isTypeApp ? batteryUtils.getProcessTimeMs( 113 BatteryUtils.StatusType.BACKGROUND, uid, which) : 0; 114 115 if (ArrayUtils.isEmpty(sipper.mPackages)) { 116 // populate data for system app 117 args.putString(EXTRA_LABEL, entry.getLabel()); 118 args.putInt(EXTRA_ICON_ID, entry.iconId); 119 args.putString(EXTRA_PACKAGE_NAME, null); 120 } else { 121 // populate data for normal app 122 args.putString(EXTRA_PACKAGE_NAME, entry.defaultPackageName); 123 } 124 125 args.putInt(EXTRA_UID, sipper.getUid()); 126 args.putLong(EXTRA_BACKGROUND_TIME, backgroundTimeMs); 127 args.putLong(EXTRA_FOREGROUND_TIME, foregroundTimeMs); 128 args.putString(EXTRA_POWER_USAGE_PERCENT, usagePercent); 129 args.putInt(EXTRA_POWER_USAGE_AMOUNT, (int) sipper.totalPowerMah); 130 131 caller.startPreferencePanelAsUser(fragment, AdvancedPowerUsageDetail.class.getName(), args, 132 R.string.battery_details_title, null, 133 new UserHandle(UserHandle.getUserId(sipper.getUid()))); 134 } 135 136 public static void startBatteryDetailPage(SettingsActivity caller, PreferenceFragment fragment, 137 String packageName) { 138 final Bundle args = new Bundle(2); 139 args.putString(EXTRA_PACKAGE_NAME, packageName); 140 args.putString(EXTRA_POWER_USAGE_PERCENT, Utils.formatPercentage(0)); 141 142 caller.startPreferencePanelAsUser(fragment, AdvancedPowerUsageDetail.class.getName(), args, 143 R.string.battery_details_title, null, new UserHandle(UserHandle.myUserId())); 144 } 145 146 @Override 147 public void onAttach(Activity activity) { 148 super.onAttach(activity); 149 150 mState = ApplicationsState.getInstance(getActivity().getApplication()); 151 mDpm = new DevicePolicyManagerWrapperImpl( 152 (DevicePolicyManager) activity.getSystemService(Context.DEVICE_POLICY_SERVICE)); 153 mUserManager = (UserManager) activity.getSystemService(Context.USER_SERVICE); 154 mPackageManager = activity.getPackageManager(); 155 mBatteryUtils = BatteryUtils.getInstance(getContext()); 156 } 157 158 @Override 159 public void onCreate(Bundle icicle) { 160 super.onCreate(icicle); 161 162 mForegroundPreference = findPreference(KEY_PREF_FOREGROUND); 163 mBackgroundPreference = findPreference(KEY_PREF_BACKGROUND); 164 mPowerUsagePreference = findPreference(KEY_PREF_POWER_USAGE); 165 mHeaderPreference = (LayoutPreference) findPreference(KEY_PREF_HEADER); 166 167 final String packageName = getArguments().getString(EXTRA_PACKAGE_NAME); 168 if (packageName != null) { 169 mAppEntry = mState.getEntry(packageName, UserHandle.myUserId()); 170 } 171 } 172 173 @Override 174 public void onResume() { 175 super.onResume(); 176 177 initHeader(); 178 179 final Bundle bundle = getArguments(); 180 final Context context = getContext(); 181 182 final long foregroundTimeMs = bundle.getLong(EXTRA_FOREGROUND_TIME); 183 final long backgroundTimeMs = bundle.getLong(EXTRA_BACKGROUND_TIME); 184 final String usagePercent = bundle.getString(EXTRA_POWER_USAGE_PERCENT); 185 final int powerMah = bundle.getInt(EXTRA_POWER_USAGE_AMOUNT); 186 mForegroundPreference.setSummary(Utils.formatElapsedTime(context, foregroundTimeMs, false)); 187 mBackgroundPreference.setSummary(Utils.formatElapsedTime(context, backgroundTimeMs, false)); 188 mPowerUsagePreference.setSummary( 189 getString(R.string.battery_detail_power_percentage, usagePercent, powerMah)); 190 } 191 192 @VisibleForTesting 193 void initHeader() { 194 final View appSnippet = mHeaderPreference.findViewById(R.id.app_snippet); 195 final Activity context = getActivity(); 196 final Bundle bundle = getArguments(); 197 AppHeaderController controller = FeatureFactory.getFactory(context) 198 .getApplicationFeatureProvider(context) 199 .newAppHeaderController(this, appSnippet) 200 .setButtonActions(AppHeaderController.ActionType.ACTION_NONE, 201 AppHeaderController.ActionType.ACTION_NONE); 202 203 if (mAppEntry == null) { 204 controller.setLabel(bundle.getString(EXTRA_LABEL)); 205 206 final int iconId = bundle.getInt(EXTRA_ICON_ID, 0); 207 if (iconId == 0) { 208 controller.setIcon(context.getPackageManager().getDefaultActivityIcon()); 209 } else { 210 controller.setIcon(context.getDrawable(bundle.getInt(EXTRA_ICON_ID))); 211 } 212 } else { 213 mState.ensureIcon(mAppEntry); 214 controller.setLabel(mAppEntry); 215 controller.setIcon(mAppEntry); 216 boolean isInstantApp = AppUtils.isInstant(mAppEntry.info); 217 CharSequence summary = isInstantApp 218 ? null : getString(Utils.getInstallationStatus(mAppEntry.info)); 219 controller.setIsInstantApp(AppUtils.isInstant(mAppEntry.info)); 220 controller.setSummary(summary); 221 } 222 223 controller.done(context, true /* rebindActions */); 224 } 225 226 @Override 227 public int getMetricsCategory() { 228 return MetricsEvent.FUELGAUGE_POWER_USAGE_DETAIL; 229 } 230 231 @Override 232 protected String getLogTag() { 233 return TAG; 234 } 235 236 @Override 237 protected int getPreferenceScreenResId() { 238 return R.xml.power_usage_detail_ia; 239 } 240 241 @Override 242 protected List<PreferenceController> getPreferenceControllers(Context context) { 243 final List<PreferenceController> controllers = new ArrayList<>(); 244 final Bundle bundle = getArguments(); 245 final int uid = bundle.getInt(EXTRA_UID, 0); 246 final String packageName = bundle.getString(EXTRA_PACKAGE_NAME); 247 248 controllers.add(new BackgroundActivityPreferenceController(context, uid)); 249 controllers.add(new BatteryOptimizationPreferenceController( 250 (SettingsActivity) getActivity(), this, packageName)); 251 mAppButtonsPreferenceController = new AppButtonsPreferenceController( 252 (SettingsActivity) getActivity(), this, getLifecycle(), packageName, mState, mDpm, 253 mUserManager, mPackageManager, REQUEST_UNINSTALL, REQUEST_REMOVE_DEVICE_ADMIN); 254 controllers.add(mAppButtonsPreferenceController); 255 256 return controllers; 257 } 258 259 @Override 260 public void onActivityResult(int requestCode, int resultCode, Intent data) { 261 super.onActivityResult(requestCode, resultCode, data); 262 if (mAppButtonsPreferenceController != null) { 263 mAppButtonsPreferenceController.handleActivityResult(requestCode, resultCode, data); 264 } 265 } 266 267 @Override 268 public void handleDialogClick(int id) { 269 if (mAppButtonsPreferenceController != null) { 270 mAppButtonsPreferenceController.handleDialogClick(id); 271 } 272 } 273 } 274