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