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.annotation.UserIdInt; 20 import android.app.Activity; 21 import android.app.ActivityManager; 22 import android.app.backup.BackupManager; 23 import android.app.settings.SettingsEnums; 24 import android.content.Context; 25 import android.content.Intent; 26 import android.content.pm.PackageManager; 27 import android.os.Bundle; 28 import android.os.UserHandle; 29 import android.text.TextUtils; 30 import android.text.format.DateUtils; 31 import android.util.Log; 32 import android.view.View; 33 34 import androidx.annotation.VisibleForTesting; 35 import androidx.preference.Preference; 36 37 import com.android.settings.R; 38 import com.android.settings.SettingsActivity; 39 import com.android.settings.Utils; 40 import com.android.settings.applications.appinfo.AppButtonsPreferenceController; 41 import com.android.settings.applications.appinfo.ButtonActionDialogFragment; 42 import com.android.settings.core.InstrumentedPreferenceFragment; 43 import com.android.settings.core.SubSettingLauncher; 44 import com.android.settings.dashboard.DashboardFragment; 45 import com.android.settings.fuelgauge.batterytip.BatteryTipPreferenceController; 46 import com.android.settings.fuelgauge.batterytip.tips.BatteryTip; 47 import com.android.settings.overlay.FeatureFactory; 48 import com.android.settings.widget.EntityHeaderController; 49 import com.android.settingslib.HelpUtils; 50 import com.android.settingslib.applications.AppUtils; 51 import com.android.settingslib.applications.ApplicationsState; 52 import com.android.settingslib.core.AbstractPreferenceController; 53 import com.android.settingslib.utils.StringUtil; 54 import com.android.settingslib.widget.FooterPreference; 55 import com.android.settingslib.widget.LayoutPreference; 56 import com.android.settingslib.widget.RadioButtonPreference; 57 58 import java.util.ArrayList; 59 import java.util.List; 60 61 /** 62 * Power usage detail fragment for each app, this fragment contains 63 * 64 * 1. Detail battery usage information for app(i.e. usage time, usage amount) 65 * 2. Battery related controls for app(i.e uninstall, force stop) 66 */ 67 public class AdvancedPowerUsageDetail extends DashboardFragment implements 68 ButtonActionDialogFragment.AppButtonsDialogListener, 69 BatteryTipPreferenceController.BatteryTipListener, RadioButtonPreference.OnClickListener { 70 71 public static final String TAG = "AdvancedPowerDetail"; 72 public static final String EXTRA_UID = "extra_uid"; 73 public static final String EXTRA_PACKAGE_NAME = "extra_package_name"; 74 public static final String EXTRA_FOREGROUND_TIME = "extra_foreground_time"; 75 public static final String EXTRA_BACKGROUND_TIME = "extra_background_time"; 76 public static final String EXTRA_SLOT_TIME = "extra_slot_time"; 77 public static final String EXTRA_LABEL = "extra_label"; 78 public static final String EXTRA_ICON_ID = "extra_icon_id"; 79 public static final String EXTRA_POWER_USAGE_PERCENT = "extra_power_usage_percent"; 80 public static final String EXTRA_POWER_USAGE_AMOUNT = "extra_power_usage_amount"; 81 82 private static final String KEY_PREF_FOREGROUND = "app_usage_foreground"; 83 private static final String KEY_PREF_BACKGROUND = "app_usage_background"; 84 private static final String KEY_PREF_HEADER = "header_view"; 85 private static final String KEY_PREF_UNRESTRICTED = "unrestricted_pref"; 86 private static final String KEY_PREF_OPTIMIZED = "optimized_pref"; 87 private static final String KEY_PREF_RESTRICTED = "restricted_pref"; 88 private static final String KEY_FOOTER_PREFERENCE = "app_usage_footer_preference"; 89 private static final String PACKAGE_NAME_NONE = "none"; 90 91 private static final int REQUEST_UNINSTALL = 0; 92 private static final int REQUEST_REMOVE_DEVICE_ADMIN = 1; 93 94 @VisibleForTesting 95 LayoutPreference mHeaderPreference; 96 @VisibleForTesting 97 ApplicationsState mState; 98 @VisibleForTesting 99 ApplicationsState.AppEntry mAppEntry; 100 @VisibleForTesting 101 BatteryUtils mBatteryUtils; 102 @VisibleForTesting 103 BatteryOptimizeUtils mBatteryOptimizeUtils; 104 @VisibleForTesting 105 Preference mForegroundPreference; 106 @VisibleForTesting 107 Preference mBackgroundPreference; 108 @VisibleForTesting 109 FooterPreference mFooterPreference; 110 @VisibleForTesting 111 RadioButtonPreference mRestrictedPreference; 112 @VisibleForTesting 113 RadioButtonPreference mOptimizePreference; 114 @VisibleForTesting 115 RadioButtonPreference mUnrestrictedPreference; 116 @VisibleForTesting 117 boolean mEnableTriState = true; 118 @VisibleForTesting 119 @BatteryOptimizeUtils.OptimizationMode 120 int mOptimizationMode = BatteryOptimizeUtils.MODE_UNKNOWN; 121 @VisibleForTesting 122 BackupManager mBackupManager; 123 124 private AppButtonsPreferenceController mAppButtonsPreferenceController; 125 private BackgroundActivityPreferenceController mBackgroundActivityPreferenceController; 126 127 // A wrapper class to carry LaunchBatteryDetailPage required arguments. 128 private static final class LaunchBatteryDetailPageArgs { 129 private String mUsagePercent; 130 private String mPackageName; 131 private String mAppLabel; 132 private String mSlotInformation; 133 private int mUid; 134 private int mIconId; 135 private int mConsumedPower; 136 private long mForegroundTimeMs; 137 private long mBackgroundTimeMs; 138 private boolean mIsUserEntry; 139 } 140 141 /** Launches battery details page for an individual battery consumer. */ startBatteryDetailPage( Activity caller, InstrumentedPreferenceFragment fragment, BatteryDiffEntry diffEntry, String usagePercent, boolean isValidToShowSummary, String slotInformation)142 public static void startBatteryDetailPage( 143 Activity caller, InstrumentedPreferenceFragment fragment, 144 BatteryDiffEntry diffEntry, String usagePercent, 145 boolean isValidToShowSummary, String slotInformation) { 146 final BatteryHistEntry histEntry = diffEntry.mBatteryHistEntry; 147 final LaunchBatteryDetailPageArgs launchArgs = new LaunchBatteryDetailPageArgs(); 148 // configure the launch argument. 149 launchArgs.mUsagePercent = usagePercent; 150 launchArgs.mPackageName = diffEntry.getPackageName(); 151 launchArgs.mAppLabel = diffEntry.getAppLabel(); 152 launchArgs.mSlotInformation = slotInformation; 153 launchArgs.mUid = (int) histEntry.mUid; 154 launchArgs.mIconId = diffEntry.getAppIconId(); 155 launchArgs.mConsumedPower = (int) diffEntry.mConsumePower; 156 launchArgs.mForegroundTimeMs = 157 isValidToShowSummary ? diffEntry.mForegroundUsageTimeInMs : 0; 158 launchArgs.mBackgroundTimeMs = 159 isValidToShowSummary ? diffEntry.mBackgroundUsageTimeInMs : 0; 160 launchArgs.mIsUserEntry = histEntry.isUserEntry(); 161 startBatteryDetailPage(caller, fragment, launchArgs); 162 } 163 164 /** Launches battery details page for an individual battery consumer. */ startBatteryDetailPage(Activity caller, InstrumentedPreferenceFragment fragment, BatteryEntry entry, String usagePercent, boolean isValidToShowSummary)165 public static void startBatteryDetailPage(Activity caller, 166 InstrumentedPreferenceFragment fragment, BatteryEntry entry, String usagePercent, 167 boolean isValidToShowSummary) { 168 final LaunchBatteryDetailPageArgs launchArgs = new LaunchBatteryDetailPageArgs(); 169 // configure the launch argument. 170 launchArgs.mUsagePercent = usagePercent; 171 launchArgs.mPackageName = entry.getDefaultPackageName(); 172 launchArgs.mAppLabel = entry.getLabel(); 173 launchArgs.mUid = entry.getUid(); 174 launchArgs.mIconId = entry.iconId; 175 launchArgs.mConsumedPower = (int) entry.getConsumedPower(); 176 launchArgs.mForegroundTimeMs = isValidToShowSummary ? entry.getTimeInForegroundMs() : 0; 177 launchArgs.mBackgroundTimeMs = isValidToShowSummary ? entry.getTimeInBackgroundMs() : 0; 178 launchArgs.mIsUserEntry = entry.isUserEntry(); 179 startBatteryDetailPage(caller, fragment, launchArgs); 180 } 181 startBatteryDetailPage(Activity caller, InstrumentedPreferenceFragment fragment, LaunchBatteryDetailPageArgs launchArgs)182 private static void startBatteryDetailPage(Activity caller, 183 InstrumentedPreferenceFragment fragment, LaunchBatteryDetailPageArgs launchArgs) { 184 final Bundle args = new Bundle(); 185 if (launchArgs.mPackageName == null) { 186 // populate data for system app 187 args.putString(EXTRA_LABEL, launchArgs.mAppLabel); 188 args.putInt(EXTRA_ICON_ID, launchArgs.mIconId); 189 args.putString(EXTRA_PACKAGE_NAME, null); 190 } else { 191 // populate data for normal app 192 args.putString(EXTRA_PACKAGE_NAME, launchArgs.mPackageName); 193 } 194 195 args.putInt(EXTRA_UID, launchArgs.mUid); 196 args.putLong(EXTRA_BACKGROUND_TIME, launchArgs.mBackgroundTimeMs); 197 args.putLong(EXTRA_FOREGROUND_TIME, launchArgs.mForegroundTimeMs); 198 args.putString(EXTRA_SLOT_TIME, launchArgs.mSlotInformation); 199 args.putString(EXTRA_POWER_USAGE_PERCENT, launchArgs.mUsagePercent); 200 args.putInt(EXTRA_POWER_USAGE_AMOUNT, launchArgs.mConsumedPower); 201 final int userId = launchArgs.mIsUserEntry ? ActivityManager.getCurrentUser() 202 : UserHandle.getUserId(launchArgs.mUid); 203 204 new SubSettingLauncher(caller) 205 .setDestination(AdvancedPowerUsageDetail.class.getName()) 206 .setTitleRes(R.string.battery_details_title) 207 .setArguments(args) 208 .setSourceMetricsCategory(fragment.getMetricsCategory()) 209 .setUserHandle(new UserHandle(userId)) 210 .launch(); 211 } 212 getUserIdToLaunchAdvancePowerUsageDetail( BatteryEntry batteryEntry)213 private static @UserIdInt int getUserIdToLaunchAdvancePowerUsageDetail( 214 BatteryEntry batteryEntry) { 215 if (batteryEntry.isUserEntry()) { 216 return ActivityManager.getCurrentUser(); 217 } 218 return UserHandle.getUserId(batteryEntry.getUid()); 219 } 220 startBatteryDetailPage(Activity caller, InstrumentedPreferenceFragment fragment, String packageName)221 public static void startBatteryDetailPage(Activity caller, 222 InstrumentedPreferenceFragment fragment, String packageName) { 223 final Bundle args = new Bundle(3); 224 final PackageManager packageManager = caller.getPackageManager(); 225 args.putString(EXTRA_PACKAGE_NAME, packageName); 226 args.putString(EXTRA_POWER_USAGE_PERCENT, Utils.formatPercentage(0)); 227 try { 228 args.putInt(EXTRA_UID, packageManager.getPackageUid(packageName, 0 /* no flag */)); 229 } catch (PackageManager.NameNotFoundException e) { 230 Log.w(TAG, "Cannot find package: " + packageName, e); 231 } 232 233 new SubSettingLauncher(caller) 234 .setDestination(AdvancedPowerUsageDetail.class.getName()) 235 .setTitleRes(R.string.battery_details_title) 236 .setArguments(args) 237 .setSourceMetricsCategory(fragment.getMetricsCategory()) 238 .launch(); 239 } 240 241 @Override onAttach(Activity activity)242 public void onAttach(Activity activity) { 243 super.onAttach(activity); 244 245 mState = ApplicationsState.getInstance(getActivity().getApplication()); 246 mBatteryUtils = BatteryUtils.getInstance(getContext()); 247 } 248 249 @Override onCreate(Bundle icicle)250 public void onCreate(Bundle icicle) { 251 super.onCreate(icicle); 252 253 final String packageName = getArguments().getString(EXTRA_PACKAGE_NAME); 254 if (mEnableTriState) { 255 onCreateForTriState(packageName); 256 } else { 257 mForegroundPreference = findPreference(KEY_PREF_FOREGROUND); 258 mBackgroundPreference = findPreference(KEY_PREF_BACKGROUND); 259 } 260 mHeaderPreference = findPreference(KEY_PREF_HEADER); 261 262 if (packageName != null) { 263 mAppEntry = mState.getEntry(packageName, UserHandle.myUserId()); 264 } 265 } 266 267 @Override onResume()268 public void onResume() { 269 super.onResume(); 270 271 initHeader(); 272 if (mEnableTriState) { 273 mOptimizationMode = mBatteryOptimizeUtils.getAppOptimizationMode(); 274 initPreferenceForTriState(getContext()); 275 final String packageName = mBatteryOptimizeUtils.getPackageName(); 276 FeatureFactory.getFactory(getContext()).getMetricsFeatureProvider() 277 .action( 278 getContext(), 279 SettingsEnums.OPEN_APP_BATTERY_USAGE, 280 packageName); 281 } else { 282 initPreference(getContext()); 283 } 284 } 285 286 @Override onPause()287 public void onPause() { 288 super.onPause(); 289 if (mEnableTriState) { 290 final int selectedPreference = getSelectedPreference(); 291 292 notifyBackupManager(); 293 logMetricCategory(selectedPreference); 294 mBatteryOptimizeUtils.setAppUsageState(selectedPreference); 295 Log.d(TAG, "Leave with mode: " + selectedPreference); 296 } 297 } 298 299 @VisibleForTesting notifyBackupManager()300 void notifyBackupManager() { 301 if (mOptimizationMode != mBatteryOptimizeUtils.getAppOptimizationMode()) { 302 final BackupManager backupManager = mBackupManager != null 303 ? mBackupManager : new BackupManager(getContext()); 304 backupManager.dataChanged(); 305 } 306 } 307 308 @VisibleForTesting initHeader()309 void initHeader() { 310 final View appSnippet = mHeaderPreference.findViewById(R.id.entity_header); 311 final Activity context = getActivity(); 312 final Bundle bundle = getArguments(); 313 EntityHeaderController controller = EntityHeaderController 314 .newInstance(context, this, appSnippet) 315 .setRecyclerView(getListView(), getSettingsLifecycle()) 316 .setButtonActions(EntityHeaderController.ActionType.ACTION_NONE, 317 EntityHeaderController.ActionType.ACTION_NONE); 318 319 if (mAppEntry == null) { 320 controller.setLabel(bundle.getString(EXTRA_LABEL)); 321 322 final int iconId = bundle.getInt(EXTRA_ICON_ID, 0); 323 if (iconId == 0) { 324 controller.setIcon(context.getPackageManager().getDefaultActivityIcon()); 325 } else { 326 controller.setIcon(context.getDrawable(bundle.getInt(EXTRA_ICON_ID))); 327 } 328 } else { 329 mState.ensureIcon(mAppEntry); 330 controller.setLabel(mAppEntry); 331 controller.setIcon(mAppEntry); 332 controller.setIsInstantApp(AppUtils.isInstant(mAppEntry.info)); 333 } 334 335 if (mEnableTriState) { 336 controller.setSummary(getAppActiveTime(bundle)); 337 } 338 339 controller.done(context, true /* rebindActions */); 340 } 341 342 @VisibleForTesting initPreference(Context context)343 void initPreference(Context context) { 344 final Bundle bundle = getArguments(); 345 final long foregroundTimeMs = bundle.getLong(EXTRA_FOREGROUND_TIME); 346 final long backgroundTimeMs = bundle.getLong(EXTRA_BACKGROUND_TIME); 347 mForegroundPreference.setSummary( 348 TextUtils.expandTemplate(getText(R.string.battery_used_for), 349 StringUtil.formatElapsedTime( 350 context, 351 foregroundTimeMs, 352 /* withSeconds */ false, 353 /* collapseTimeUnit */ false))); 354 mBackgroundPreference.setSummary( 355 TextUtils.expandTemplate(getText(R.string.battery_active_for), 356 StringUtil.formatElapsedTime( 357 context, 358 backgroundTimeMs, 359 /* withSeconds */ false, 360 /* collapseTimeUnit */ false))); 361 } 362 363 @VisibleForTesting initPreferenceForTriState(Context context)364 void initPreferenceForTriState(Context context) { 365 final String stateString; 366 final String footerString; 367 368 if (!mBatteryOptimizeUtils.isValidPackageName()) { 369 // Present optimized only string when the package name is invalid or 370 // it's in allow list not idle app. 371 stateString = context.getString(R.string.manager_battery_usage_optimized_only); 372 footerString = context.getString( 373 R.string.manager_battery_usage_footer_limited, stateString); 374 } else if (mBatteryOptimizeUtils.isSystemOrDefaultApp()) { 375 // Present unrestricted only string when the package is system or default active app. 376 stateString = context.getString(R.string.manager_battery_usage_unrestricted_only); 377 footerString = context.getString( 378 R.string.manager_battery_usage_footer_limited, stateString); 379 } else { 380 // Present default string to normal app. 381 footerString = context.getString(R.string.manager_battery_usage_footer); 382 } 383 mFooterPreference.setTitle(footerString); 384 final Intent helpIntent = HelpUtils.getHelpIntent(context, context.getString( 385 R.string.help_url_app_usage_settings), /*backupContext=*/ ""); 386 if (helpIntent != null) { 387 mFooterPreference.setLearnMoreAction(v -> 388 startActivityForResult(helpIntent, /*requestCode=*/ 0)); 389 mFooterPreference.setLearnMoreContentDescription( 390 context.getString(R.string.manager_battery_usage_link_a11y)); 391 } 392 } 393 394 @Override getMetricsCategory()395 public int getMetricsCategory() { 396 return SettingsEnums.FUELGAUGE_POWER_USAGE_DETAIL; 397 } 398 399 @Override getLogTag()400 protected String getLogTag() { 401 return TAG; 402 } 403 404 @Override getPreferenceScreenResId()405 protected int getPreferenceScreenResId() { 406 return mEnableTriState ? R.xml.power_usage_detail : R.xml.power_usage_detail_legacy; 407 } 408 409 @Override createPreferenceControllers(Context context)410 protected List<AbstractPreferenceController> createPreferenceControllers(Context context) { 411 final List<AbstractPreferenceController> controllers = new ArrayList<>(); 412 final Bundle bundle = getArguments(); 413 final int uid = bundle.getInt(EXTRA_UID, 0); 414 final String packageName = bundle.getString(EXTRA_PACKAGE_NAME); 415 416 mAppButtonsPreferenceController = new AppButtonsPreferenceController( 417 (SettingsActivity) getActivity(), this, getSettingsLifecycle(), packageName, 418 mState, REQUEST_UNINSTALL, REQUEST_REMOVE_DEVICE_ADMIN); 419 controllers.add(mAppButtonsPreferenceController); 420 if (mEnableTriState) { 421 controllers.add(new UnrestrictedPreferenceController(context, uid, packageName)); 422 controllers.add(new OptimizedPreferenceController(context, uid, packageName)); 423 controllers.add(new RestrictedPreferenceController(context, uid, packageName)); 424 } else { 425 mBackgroundActivityPreferenceController = new BackgroundActivityPreferenceController( 426 context, this, uid, packageName); 427 controllers.add(mBackgroundActivityPreferenceController); 428 controllers.add(new BatteryOptimizationPreferenceController( 429 (SettingsActivity) getActivity(), this, packageName)); 430 } 431 432 return controllers; 433 } 434 435 @Override onActivityResult(int requestCode, int resultCode, Intent data)436 public void onActivityResult(int requestCode, int resultCode, Intent data) { 437 super.onActivityResult(requestCode, resultCode, data); 438 if (mAppButtonsPreferenceController != null) { 439 mAppButtonsPreferenceController.handleActivityResult(requestCode, resultCode, data); 440 } 441 } 442 443 @Override handleDialogClick(int id)444 public void handleDialogClick(int id) { 445 if (mAppButtonsPreferenceController != null) { 446 mAppButtonsPreferenceController.handleDialogClick(id); 447 } 448 } 449 450 @Override onBatteryTipHandled(BatteryTip batteryTip)451 public void onBatteryTipHandled(BatteryTip batteryTip) { 452 mBackgroundActivityPreferenceController.updateSummary( 453 findPreference(mBackgroundActivityPreferenceController.getPreferenceKey())); 454 } 455 456 @Override onRadioButtonClicked(RadioButtonPreference selected)457 public void onRadioButtonClicked(RadioButtonPreference selected) { 458 final String selectedKey = selected.getKey(); 459 updatePreferenceState(mUnrestrictedPreference, selectedKey); 460 updatePreferenceState(mOptimizePreference, selectedKey); 461 updatePreferenceState(mRestrictedPreference, selectedKey); 462 } 463 updatePreferenceState(RadioButtonPreference preference, String selectedKey)464 private void updatePreferenceState(RadioButtonPreference preference, String selectedKey) { 465 preference.setChecked(selectedKey.equals(preference.getKey())); 466 } 467 logMetricCategory(int selectedKey)468 private void logMetricCategory(int selectedKey) { 469 if (selectedKey == mOptimizationMode) { 470 return; 471 } 472 473 int metricCategory = 0; 474 switch (selectedKey) { 475 case BatteryOptimizeUtils.MODE_UNRESTRICTED: 476 metricCategory = SettingsEnums.ACTION_APP_BATTERY_USAGE_UNRESTRICTED; 477 break; 478 case BatteryOptimizeUtils.MODE_OPTIMIZED: 479 metricCategory = SettingsEnums.ACTION_APP_BATTERY_USAGE_OPTIMIZED; 480 break; 481 case BatteryOptimizeUtils.MODE_RESTRICTED: 482 metricCategory = SettingsEnums.ACTION_APP_BATTERY_USAGE_RESTRICTED; 483 break; 484 } 485 486 if (metricCategory != 0) { 487 final String packageName = mBatteryOptimizeUtils.getPackageName(); 488 FeatureFactory.getFactory(getContext()).getMetricsFeatureProvider() 489 .action( 490 /* attribution */ SettingsEnums.OPEN_APP_BATTERY_USAGE, 491 /* action */ metricCategory, 492 /* pageId */ SettingsEnums.OPEN_APP_BATTERY_USAGE, 493 TextUtils.isEmpty(packageName) ? PACKAGE_NAME_NONE : packageName, 494 getArguments().getInt(EXTRA_POWER_USAGE_AMOUNT)); 495 } 496 } 497 onCreateForTriState(String packageName)498 private void onCreateForTriState(String packageName) { 499 mUnrestrictedPreference = findPreference(KEY_PREF_UNRESTRICTED); 500 mOptimizePreference = findPreference(KEY_PREF_OPTIMIZED); 501 mRestrictedPreference = findPreference(KEY_PREF_RESTRICTED); 502 mFooterPreference = findPreference(KEY_FOOTER_PREFERENCE); 503 mUnrestrictedPreference.setOnClickListener(this); 504 mOptimizePreference.setOnClickListener(this); 505 mRestrictedPreference.setOnClickListener(this); 506 507 mBatteryOptimizeUtils = new BatteryOptimizeUtils( 508 getContext(), getArguments().getInt(EXTRA_UID), packageName); 509 } 510 getSelectedPreference()511 private int getSelectedPreference() { 512 if (mRestrictedPreference.isChecked()) { 513 return BatteryOptimizeUtils.MODE_RESTRICTED; 514 } else if (mUnrestrictedPreference.isChecked()) { 515 return BatteryOptimizeUtils.MODE_UNRESTRICTED; 516 } else if (mOptimizePreference.isChecked()) { 517 return BatteryOptimizeUtils.MODE_OPTIMIZED; 518 } else { 519 return BatteryOptimizeUtils.MODE_UNKNOWN; 520 } 521 } 522 getAppActiveTime(Bundle bundle)523 private CharSequence getAppActiveTime(Bundle bundle) { 524 final long foregroundTimeMs = bundle.getLong(EXTRA_FOREGROUND_TIME); 525 final long backgroundTimeMs = bundle.getLong(EXTRA_BACKGROUND_TIME); 526 final int consumedPower = bundle.getInt(EXTRA_POWER_USAGE_AMOUNT); 527 final String slotTime = bundle.getString(EXTRA_SLOT_TIME, null); 528 final long totalTimeMs = foregroundTimeMs + backgroundTimeMs; 529 final CharSequence usageTimeSummary; 530 final PowerUsageFeatureProvider powerFeatureProvider = 531 FeatureFactory.getFactory(getContext()).getPowerUsageFeatureProvider(getContext()); 532 533 if (totalTimeMs == 0) { 534 final int batteryWithoutUsageTime = consumedPower > 0 535 ? R.string.battery_usage_without_time : R.string.battery_not_usage_24hr; 536 usageTimeSummary = getText(powerFeatureProvider.isChartGraphEnabled(getContext()) 537 ? batteryWithoutUsageTime : R.string.battery_not_usage); 538 } else if (slotTime == null) { 539 // Shows summary text with past 24 hr or full charge if slot time is null. 540 usageTimeSummary = powerFeatureProvider.isChartGraphEnabled(getContext()) 541 ? getAppPast24HrActiveSummary(foregroundTimeMs, backgroundTimeMs, totalTimeMs) 542 : getAppFullChargeActiveSummary( 543 foregroundTimeMs, backgroundTimeMs, totalTimeMs); 544 } else { 545 // Shows summary text with slot time. 546 usageTimeSummary = getAppActiveSummaryWithSlotTime( 547 foregroundTimeMs, backgroundTimeMs, totalTimeMs, slotTime); 548 } 549 return usageTimeSummary; 550 } 551 getAppFullChargeActiveSummary( long foregroundTimeMs, long backgroundTimeMs, long totalTimeMs)552 private CharSequence getAppFullChargeActiveSummary( 553 long foregroundTimeMs, long backgroundTimeMs, long totalTimeMs) { 554 // Shows background summary only if we don't have foreground usage time. 555 if (foregroundTimeMs == 0 && backgroundTimeMs != 0) { 556 return backgroundTimeMs < DateUtils.MINUTE_IN_MILLIS ? 557 getText(R.string.battery_bg_usage_less_minute) : 558 TextUtils.expandTemplate(getText(R.string.battery_bg_usage), 559 StringUtil.formatElapsedTime( 560 getContext(), 561 backgroundTimeMs, 562 /* withSeconds */ false, 563 /* collapseTimeUnit */ false)); 564 // Shows total usage summary only if total usage time is small. 565 } else if (totalTimeMs < DateUtils.MINUTE_IN_MILLIS) { 566 return getText(R.string.battery_total_usage_less_minute); 567 // Shows different total usage summary when background usage time is small. 568 } else if (backgroundTimeMs < DateUtils.MINUTE_IN_MILLIS) { 569 return TextUtils.expandTemplate( 570 getText(backgroundTimeMs == 0 ? 571 R.string.battery_total_usage : 572 R.string.battery_total_usage_and_bg_less_minute_usage), 573 StringUtil.formatElapsedTime( 574 getContext(), 575 totalTimeMs, 576 /* withSeconds */ false, 577 /* collapseTimeUnit */ false)); 578 // Shows default summary. 579 } else { 580 return TextUtils.expandTemplate( 581 getText(R.string.battery_total_and_bg_usage), 582 StringUtil.formatElapsedTime( 583 getContext(), 584 totalTimeMs, 585 /* withSeconds */ false, 586 /* collapseTimeUnit */ false), 587 StringUtil.formatElapsedTime( 588 getContext(), 589 backgroundTimeMs, 590 /* withSeconds */ false, 591 /* collapseTimeUnit */ false)); 592 } 593 } 594 getAppPast24HrActiveSummary( long foregroundTimeMs, long backgroundTimeMs, long totalTimeMs)595 private CharSequence getAppPast24HrActiveSummary( 596 long foregroundTimeMs, long backgroundTimeMs, long totalTimeMs) { 597 // Shows background summary only if we don't have foreground usage time. 598 if (foregroundTimeMs == 0 && backgroundTimeMs != 0) { 599 return backgroundTimeMs < DateUtils.MINUTE_IN_MILLIS 600 ? getText(R.string.battery_bg_usage_less_minute_24hr) 601 : TextUtils.expandTemplate(getText(R.string.battery_bg_usage_24hr), 602 StringUtil.formatElapsedTime( 603 getContext(), 604 backgroundTimeMs, 605 /* withSeconds */ false, 606 /* collapseTimeUnit */ false)); 607 // Shows total usage summary only if total usage time is small. 608 } else if (totalTimeMs < DateUtils.MINUTE_IN_MILLIS) { 609 return getText(R.string.battery_total_usage_less_minute_24hr); 610 // Shows different total usage summary when background usage time is small. 611 } else if (backgroundTimeMs < DateUtils.MINUTE_IN_MILLIS) { 612 return TextUtils.expandTemplate( 613 getText(backgroundTimeMs == 0 614 ? R.string.battery_total_usage_24hr 615 : R.string.battery_total_usage_and_bg_less_minute_usage_24hr), 616 StringUtil.formatElapsedTime( 617 getContext(), 618 totalTimeMs, 619 /* withSeconds */ false, 620 /* collapseTimeUnit */ false)); 621 // Shows default summary. 622 } else { 623 return TextUtils.expandTemplate( 624 getText(R.string.battery_total_and_bg_usage_24hr), 625 StringUtil.formatElapsedTime( 626 getContext(), 627 totalTimeMs, 628 /* withSeconds */ false, 629 /* collapseTimeUnit */ false), 630 StringUtil.formatElapsedTime( 631 getContext(), 632 backgroundTimeMs, 633 /* withSeconds */ false, 634 /* collapseTimeUnit */ false)); 635 } 636 } 637 getAppActiveSummaryWithSlotTime( long foregroundTimeMs, long backgroundTimeMs, long totalTimeMs, String slotTime)638 private CharSequence getAppActiveSummaryWithSlotTime( 639 long foregroundTimeMs, long backgroundTimeMs, long totalTimeMs, String slotTime) { 640 // Shows background summary only if we don't have foreground usage time. 641 if (foregroundTimeMs == 0 && backgroundTimeMs != 0) { 642 return backgroundTimeMs < DateUtils.MINUTE_IN_MILLIS ? 643 TextUtils.expandTemplate( 644 getText(R.string.battery_bg_usage_less_minute_with_period), 645 slotTime) : 646 TextUtils.expandTemplate(getText(R.string.battery_bg_usage_with_period), 647 StringUtil.formatElapsedTime( 648 getContext(), 649 backgroundTimeMs, 650 /* withSeconds */ false, 651 /* collapseTimeUnit */ false), slotTime); 652 // Shows total usage summary only if total usage time is small. 653 } else if (totalTimeMs < DateUtils.MINUTE_IN_MILLIS) { 654 return TextUtils.expandTemplate( 655 getText(R.string.battery_total_usage_less_minute_with_period), slotTime); 656 // Shows different total usage summary when background usage time is small. 657 } else if (backgroundTimeMs < DateUtils.MINUTE_IN_MILLIS) { 658 return TextUtils.expandTemplate( 659 getText(backgroundTimeMs == 0 ? 660 R.string.battery_total_usage_with_period : 661 R.string.battery_total_usage_and_bg_less_minute_usage_with_period), 662 StringUtil.formatElapsedTime( 663 getContext(), 664 totalTimeMs, 665 /* withSeconds */ false, 666 /* collapseTimeUnit */ false), slotTime); 667 // Shows default summary. 668 } else { 669 return TextUtils.expandTemplate( 670 getText(R.string.battery_total_and_bg_usage_with_period), 671 StringUtil.formatElapsedTime( 672 getContext(), 673 totalTimeMs, 674 /* withSeconds */ false, 675 /* collapseTimeUnit */ false), 676 StringUtil.formatElapsedTime( 677 getContext(), 678 backgroundTimeMs, 679 /* withSeconds */ false, 680 /* collapseTimeUnit */ false), slotTime); 681 } 682 } 683 } 684