diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryCallbackData.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryCallbackData.java new file mode 100644 index 00000000000..17e5f5c7073 --- /dev/null +++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryCallbackData.java @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.fuelgauge.batteryusage; + +import androidx.annotation.Nullable; + +import java.util.Locale; +import java.util.Map; + +/** Wraps the battery usage data and device screen-on time data used for battery usage page. */ +public class BatteryCallbackData { + + // The usage app data used for rendering app list. + private final Map> mBatteryUsageMap; + // The device screen-on time data. + private final Map> mDeviceScreenOnTime; + + public BatteryCallbackData( + @Nullable Map> batteryUsageMap, + @Nullable Map> deviceScreenOnTime) { + mBatteryUsageMap = batteryUsageMap; + mDeviceScreenOnTime = deviceScreenOnTime; + } + + public Map> getBatteryUsageMap() { + return mBatteryUsageMap; + } + + public Map> getDeviceScreenOnTime() { + return mDeviceScreenOnTime; + } + + @Override + public String toString() { + return String.format(Locale.ENGLISH, + "batteryUsageMap: %s; deviceScreenOnTime: %s", + mBatteryUsageMap, + mDeviceScreenOnTime); + } +} diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceController.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceController.java index b048dbc083b..6e214599e4e 100644 --- a/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceController.java +++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceController.java @@ -210,8 +210,8 @@ public class BatteryChartPreferenceController extends AbstractPreferenceControll animateBatteryChartViewGroup(); final BatteryLevelData batteryLevelData = DataProcessManager.getBatteryLevelData(mContext, mHandler, batteryHistoryMap, - batteryUsageMap -> { - mBatteryUsageMap = batteryUsageMap; + batteryCallbackData -> { + mBatteryUsageMap = batteryCallbackData.getBatteryUsageMap(); refreshUi(); }); Log.d(TAG, "getBatteryLevelData: " + batteryLevelData); diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffEntry.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffEntry.java index 893ca4c64e6..2c23bb377bd 100644 --- a/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffEntry.java +++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffEntry.java @@ -53,6 +53,7 @@ public class BatteryDiffEntry { public long mForegroundUsageTimeInMs; public long mBackgroundUsageTimeInMs; + public long mScreenOnTimeInMs; public double mConsumePower; public double mForegroundUsageConsumePower; public double mForegroundServiceUsageConsumePower; @@ -83,6 +84,7 @@ public class BatteryDiffEntry { Context context, long foregroundUsageTimeInMs, long backgroundUsageTimeInMs, + long screenOnTimeInMs, double consumePower, double foregroundUsageConsumePower, double foregroundServiceUsageConsumePower, @@ -97,6 +99,7 @@ public class BatteryDiffEntry { mCachedUsageConsumePower = cachedUsageConsumePower; mForegroundUsageTimeInMs = foregroundUsageTimeInMs; mBackgroundUsageTimeInMs = backgroundUsageTimeInMs; + mScreenOnTimeInMs = screenOnTimeInMs; mBatteryHistEntry = batteryHistEntry; mUserManager = context.getSystemService(UserManager.class); } @@ -119,6 +122,7 @@ public class BatteryDiffEntry { this.mContext, this.mForegroundUsageTimeInMs, this.mBackgroundUsageTimeInMs, + this.mScreenOnTimeInMs, this.mConsumePower, this.mForegroundUsageConsumePower, this.mForegroundServiceUsageConsumePower, @@ -367,10 +371,12 @@ public class BatteryDiffEntry { mForegroundUsageConsumePower, mForegroundServiceUsageConsumePower)) .append(String.format("\n\tconsume power= background:%f cached:%f", mBackgroundUsageConsumePower, mCachedUsageConsumePower)) - .append(String.format("\n\ttime= foreground:%s background:%s", + .append(String.format("\n\ttime= foreground:%s background:%s screen-on:%s", StringUtil.formatElapsedTime(mContext, (double) mForegroundUsageTimeInMs, /*withSeconds=*/ true, /*collapseTimeUnit=*/ false), StringUtil.formatElapsedTime(mContext, (double) mBackgroundUsageTimeInMs, + /*withSeconds=*/ true, /*collapseTimeUnit=*/ false), + StringUtil.formatElapsedTime(mContext, (double) mScreenOnTimeInMs, /*withSeconds=*/ true, /*collapseTimeUnit=*/ false))) .append(String.format("\n\tpackage:%s|%s uid:%d userId:%d", mBatteryHistEntry.mPackageName, getPackageName(), diff --git a/src/com/android/settings/fuelgauge/batteryusage/DataProcessManager.java b/src/com/android/settings/fuelgauge/batteryusage/DataProcessManager.java index a1634bfb05f..762ea2458cf 100644 --- a/src/com/android/settings/fuelgauge/batteryusage/DataProcessManager.java +++ b/src/com/android/settings/fuelgauge/batteryusage/DataProcessManager.java @@ -330,9 +330,9 @@ public class DataProcessManager { } private void loadAndApplyBatteryMapFromServiceOnly() { - new AsyncTask>>() { + new AsyncTask() { @Override - protected Map> doInBackground(Void... voids) { + protected BatteryCallbackData doInBackground(Void... voids) { final long startTime = System.currentTimeMillis(); final Map> batteryUsageMap = DataProcessor.getBatteryUsageMapFromStatsService(mContext); @@ -340,18 +340,18 @@ public class DataProcessManager { Log.d(TAG, String.format( "execute loadAndApplyBatteryMapFromServiceOnly size=%d in %d/ms", batteryUsageMap.size(), (System.currentTimeMillis() - startTime))); - return batteryUsageMap; + return new BatteryCallbackData(batteryUsageMap, /*deviceScreenOnTime=*/ null); } @Override protected void onPostExecute( - final Map> batteryUsageMap) { + final BatteryCallbackData batteryCallbackData) { // Set the unused variables to null. mContext = null; // Post results back to main thread to refresh UI. if (mHandler != null && mCallbackFunction != null) { mHandler.post(() -> { - mCallbackFunction.onBatteryUsageMapLoaded(batteryUsageMap); + mCallbackFunction.onBatteryCallbackDataLoaded(batteryCallbackData); }); } } @@ -391,12 +391,36 @@ public class DataProcessManager { } private void generateFinalDataAndApplyCallback() { - // TODO: generate the final data including battery usage map and device screen-on time and - // then apply the callback function. - // Set the unused variables to null. - mContext = null; - mHourlyBatteryLevelsPerDay = null; - mBatteryHistoryMap = null; + new AsyncTask() { + @Override + protected BatteryCallbackData doInBackground(Void... voids) { + final long startTime = System.currentTimeMillis(); + final Map> batteryUsageMap = + DataProcessor.getBatteryUsageMap( + mContext, mHourlyBatteryLevelsPerDay, mBatteryHistoryMap, + mAppUsagePeriodMap); + final Map> deviceScreenOnTime = + DataProcessor.getDeviceScreenOnTime(mAppUsagePeriodMap); + DataProcessor.loadLabelAndIcon(batteryUsageMap); + Log.d(TAG, String.format("execute generateFinalDataAndApplyCallback in %d/ms", + (System.currentTimeMillis() - startTime))); + return new BatteryCallbackData(batteryUsageMap, deviceScreenOnTime); + } + + @Override + protected void onPostExecute(final BatteryCallbackData batteryCallbackData) { + // Set the unused variables to null. + mContext = null; + mHourlyBatteryLevelsPerDay = null; + mBatteryHistoryMap = null; + // Post results back to main thread to refresh UI. + if (mHandler != null && mCallbackFunction != null) { + mHandler.post(() -> { + mCallbackFunction.onBatteryCallbackDataLoaded(batteryCallbackData); + }); + } + } + }.execute(); } // Whether we should load app usage data from service or database. @@ -465,15 +489,13 @@ public class DataProcessManager { return null; } - // TODO: replace the task below with new DataProcessManager(...).start() after - // DataProcessManager is completed; // Start the async task to compute diff usage data and load labels and icons. - new DataProcessor.ComputeUsageMapAndLoadItemsTask( + new DataProcessManager( context, handler, asyncResponseDelegate, batteryLevelData.getHourlyBatteryLevelsPerDay(), - processedBatteryHistoryMap).execute(); + processedBatteryHistoryMap).start(); return batteryLevelData; } diff --git a/src/com/android/settings/fuelgauge/batteryusage/DataProcessor.java b/src/com/android/settings/fuelgauge/batteryusage/DataProcessor.java index 6f99f5baef2..ff52774bacb 100644 --- a/src/com/android/settings/fuelgauge/batteryusage/DataProcessor.java +++ b/src/com/android/settings/fuelgauge/batteryusage/DataProcessor.java @@ -27,12 +27,10 @@ import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.content.pm.UserInfo; -import android.os.AsyncTask; import android.os.BatteryConsumer; import android.os.BatteryStatsManager; import android.os.BatteryUsageStats; import android.os.BatteryUsageStatsQuery; -import android.os.Handler; import android.os.Process; import android.os.RemoteException; import android.os.ServiceManager; @@ -68,6 +66,7 @@ import java.util.List; import java.util.Map; import java.util.Set; import java.util.stream.Collectors; +import java.util.stream.Stream; /** * A utility class to process data loaded from database and make the data easy to use for battery @@ -111,8 +110,7 @@ public final class DataProcessor { /** A callback listener when battery usage loading async task is executed. */ public interface UsageMapAsyncResponse { /** The callback function when batteryUsageMap is loaded. */ - void onBatteryUsageMapLoaded( - Map> batteryUsageMap); + void onBatteryCallbackDataLoaded(BatteryCallbackData batteryCallbackData); } private DataProcessor() { @@ -141,7 +139,8 @@ public final class DataProcessor { : getBatteryUsageMap( context, batteryLevelData.getHourlyBatteryLevelsPerDay(), - processedBatteryHistoryMap); + processedBatteryHistoryMap, + /*appUsagePeriodMap=*/ null); } /** @@ -364,6 +363,35 @@ public final class DataProcessor { return appUsageEventList; } + /** + * @return Returns the device screen-on time data. + * + *

There could be 2 cases of the returned value:

+ *
    + *
  • null: empty or invalid data.
  • + *
  • non-null: must be a 2d map and composed by 3 parts:
  • + *

    1 - [SELECTED_INDEX_ALL][SELECTED_INDEX_ALL]

    + *

    2 - [0][SELECTED_INDEX_ALL] ~ [maxDailyIndex][SELECTED_INDEX_ALL]

    + *

    3 - [0][0] ~ [maxDailyIndex][maxHourlyIndex]

    + *
+ * + *

The structure is consistent with the battery usage map returned by + * {@code getBatteryUsageMap}.

+ */ + @Nullable + public static Map> getDeviceScreenOnTime( + final Map>>>> + appUsagePeriodMap) { + if (appUsagePeriodMap == null) { + return null; + } + final Map> deviceScreenOnTime = new HashMap<>(); + insertHourlyDeviceScreenOnTime(appUsagePeriodMap, deviceScreenOnTime); + insertDailyDeviceScreenOnTime(appUsagePeriodMap, deviceScreenOnTime); + insertAllDeviceScreenOnTime(deviceScreenOnTime); + return deviceScreenOnTime; + } + /** * Generates the list of {@link BatteryEntry} from the supplied {@link BatteryUsageStats}. */ @@ -597,19 +625,21 @@ public final class DataProcessor { *

3 - [0][0] ~ [maxDailyIndex][maxHourlyIndex]

* */ - @VisibleForTesting @Nullable static Map> getBatteryUsageMap( final Context context, final List hourlyBatteryLevelsPerDay, - final Map> batteryHistoryMap) { + final Map> batteryHistoryMap, + final Map>>>> + appUsagePeriodMap) { if (batteryHistoryMap.isEmpty()) { return null; } final Map> resultMap = new HashMap<>(); // Insert diff data from [0][0] to [maxDailyIndex][maxHourlyIndex]. insertHourlyUsageDiffData( - context, hourlyBatteryLevelsPerDay, batteryHistoryMap, resultMap); + context, hourlyBatteryLevelsPerDay, batteryHistoryMap, appUsagePeriodMap, + resultMap); // Insert diff data from [0][SELECTED_INDEX_ALL] to [maxDailyIndex][SELECTED_INDEX_ALL]. insertDailyUsageDiffData(hourlyBatteryLevelsPerDay, resultMap); // Insert diff data [SELECTED_INDEX_ALL][SELECTED_INDEX_ALL]. @@ -649,6 +679,7 @@ public final class DataProcessor { context, entry.mForegroundUsageTimeInMs, entry.mBackgroundUsageTimeInMs, + /*screenOnTimeInMs=*/ 0, entry.mConsumePower, entry.mForegroundUsageConsumePower, entry.mForegroundServiceUsageConsumePower, @@ -805,6 +836,18 @@ public final class DataProcessor { return usagePeriodList; } + @VisibleForTesting + static long getScreenOnTime( + final Map>> appUsageMap, + final long userId, + final String packageName) { + if (appUsageMap == null || appUsageMap.get(userId) == null) { + return 0; + } + + return getScreenOnTime(appUsageMap.get(userId).get(packageName)); + } + /** * @return Returns the overall battery usage data from battery stats service directly. * @@ -889,6 +932,84 @@ public final class DataProcessor { return currentIndex; } + private static void insertHourlyDeviceScreenOnTime( + final Map>>>> + appUsagePeriodMap, + final Map> resultMap) { + for (final int dailyIndex : appUsagePeriodMap.keySet()) { + final Map>>> dailyAppUsageMap = + appUsagePeriodMap.get(dailyIndex); + final Map dailyScreenOnTime = new HashMap<>(); + resultMap.put(dailyIndex, dailyScreenOnTime); + if (dailyAppUsageMap == null) { + continue; + } + + for (final int hourlyIndex : dailyAppUsageMap.keySet()) { + final Map>> appUsageMap = + dailyAppUsageMap.get(hourlyIndex); + if (appUsageMap == null || appUsageMap.isEmpty()) { + dailyScreenOnTime.put(hourlyIndex, 0L); + } else { + final List flatUsageList = new ArrayList<>(); + for (final long userId: appUsageMap.keySet()) { + if (appUsageMap.get(userId) == null) { + continue; + } + for (final String packageName: appUsageMap.get(userId).keySet()) { + final List appUsagePeriodList = + appUsageMap.get(userId).get(packageName); + if (appUsagePeriodList != null && !appUsagePeriodList.isEmpty()) { + flatUsageList.addAll(appUsagePeriodList); + } + } + } + // Compute the screen on time and make sure it won't exceed the threshold. + final long screenOnTime = Math.min( + (long) TOTAL_HOURLY_TIME_THRESHOLD, getScreenOnTime(flatUsageList)); + dailyScreenOnTime.put(hourlyIndex, screenOnTime); + } + } + } + } + + private static void insertDailyDeviceScreenOnTime( + final Map>>>> + appUsagePeriodMap, + final Map> resultMap) { + for (final int dailyIndex : appUsagePeriodMap.keySet()) { + Map dailyResultMap = resultMap.get(dailyIndex); + if (dailyResultMap == null) { + dailyResultMap = new HashMap<>(); + resultMap.put(dailyIndex, dailyResultMap); + } + dailyResultMap.put( + SELECTED_INDEX_ALL, + getAccumulatedScreenOnTime(dailyResultMap)); + } + } + + private static void insertAllDeviceScreenOnTime( + final Map> resultMap) { + final Map dailyAllMap = new HashMap<>(); + resultMap.keySet().forEach( + key -> dailyAllMap.put(key, resultMap.get(key).get(SELECTED_INDEX_ALL))); + final Map allUsageMap = new HashMap<>(); + allUsageMap.put(SELECTED_INDEX_ALL, getAccumulatedScreenOnTime(dailyAllMap)); + resultMap.put(SELECTED_INDEX_ALL, allUsageMap); + } + + private static long getAccumulatedScreenOnTime(final Map screenOnTimeMap) { + if (screenOnTimeMap == null || screenOnTimeMap.isEmpty()) { + return 0; + } + long sum = 0; + for (final int index : screenOnTimeMap.keySet()) { + sum += screenOnTimeMap.get(index) == null ? 0 : screenOnTimeMap.get(index); + } + return sum; + } + @Nullable private static UsageEvents getAppUsageEventsForUser( Context context, final UserManager userManager, final int userID, @@ -1226,6 +1347,8 @@ public final class DataProcessor { Context context, final List hourlyBatteryLevelsPerDay, final Map> batteryHistoryMap, + final Map>>>> + appUsagePeriodMap, final Map> resultMap) { final int currentUserId = context.getUserId(); final UserHandle userHandle = @@ -1251,6 +1374,10 @@ public final class DataProcessor { workProfileUserId, hourlyIndex, timestamps, + appUsagePeriodMap == null + || appUsagePeriodMap.get(dailyIndex) == null + ? null + : appUsagePeriodMap.get(dailyIndex).get(hourlyIndex), batteryHistoryMap); dailyDiffMap.put(hourlyIndex, hourlyBatteryDiffData); } @@ -1289,6 +1416,7 @@ public final class DataProcessor { final int workProfileUserId, final int currentIndex, final List timestamps, + final Map>> appUsageMap, final Map> batteryHistoryMap) { final List appEntries = new ArrayList<>(); final List systemEntries = new ArrayList<>(); @@ -1405,10 +1533,18 @@ public final class DataProcessor { cachedUsageConsumePower = cachedUsageConsumePower * ratio; } + // Compute the screen on time and make sure it won't exceed the threshold. + final long screenOnTime = Math.min( + (long) TOTAL_HOURLY_TIME_THRESHOLD, + getScreenOnTime( + appUsageMap, + selectedBatteryEntry.mUserId, + selectedBatteryEntry.mPackageName)); final BatteryDiffEntry currentBatteryDiffEntry = new BatteryDiffEntry( context, foregroundUsageTimeInMs, backgroundUsageTimeInMs, + screenOnTime, consumePower, foregroundUsageConsumePower, foregroundServiceUsageConsumePower, @@ -1430,6 +1566,49 @@ public final class DataProcessor { return new BatteryDiffData(appEntries, systemEntries); } + private static long getScreenOnTime(@Nullable final List appUsagePeriodList) { + if (appUsagePeriodList == null || appUsagePeriodList.isEmpty()) { + return 0; + } + // Create a list of endpoints (the beginning or the end) of usage periods and order the list + // chronologically. + final List endPoints = + appUsagePeriodList.stream() + .flatMap( + foregroundUsage -> + Stream.of( + AppUsageEndPoint.newBuilder() + .setTimestamp( + foregroundUsage.getStartTime()) + .setType(AppUsageEndPointType.START) + .build(), + AppUsageEndPoint.newBuilder() + .setTimestamp(foregroundUsage.getEndTime()) + .setType(AppUsageEndPointType.END) + .build())) + .sorted((x, y) -> (int) (x.getTimestamp() - y.getTimestamp())) + .collect(Collectors.toList()); + + // Traverse the list of endpoints in order to determine the non-overlapping usage duration. + int numberOfActiveAppUsagePeriods = 0; + long startOfCurrentContiguousAppUsagePeriod = 0; + long totalScreenOnTime = 0; + for (final AppUsageEndPoint endPoint : endPoints) { + if (endPoint.getType() == AppUsageEndPointType.START) { + if (numberOfActiveAppUsagePeriods++ == 0) { + startOfCurrentContiguousAppUsagePeriod = endPoint.getTimestamp(); + } + } else { + if (--numberOfActiveAppUsagePeriods == 0) { + totalScreenOnTime += + (endPoint.getTimestamp() - startOfCurrentContiguousAppUsagePeriod); + } + } + } + + return totalScreenOnTime; + } + private static boolean isConsumedFromOtherUsers( final int currentUserId, final int workProfileUserId, @@ -1484,6 +1663,8 @@ public final class DataProcessor { entry.mForegroundUsageTimeInMs; oldBatteryDiffEntry.mBackgroundUsageTimeInMs += entry.mBackgroundUsageTimeInMs; + oldBatteryDiffEntry.mScreenOnTimeInMs += + entry.mScreenOnTimeInMs; oldBatteryDiffEntry.mConsumePower += entry.mConsumePower; oldBatteryDiffEntry.mForegroundUsageConsumePower += entry.mForegroundUsageConsumePower; oldBatteryDiffEntry.mForegroundServiceUsageConsumePower @@ -1752,73 +1933,4 @@ public final class DataProcessor { utcToLocalTime(context, timestamp), content, entry)); } } - - // Compute diff map and loads all items (icon and label) in the background. - static class ComputeUsageMapAndLoadItemsTask - extends AsyncTask>> { - - Context mApplicationContext; - final Handler mHandler; - final UsageMapAsyncResponse mAsyncResponseDelegate; - private List mHourlyBatteryLevelsPerDay; - private Map> mBatteryHistoryMap; - - ComputeUsageMapAndLoadItemsTask( - Context context, - Handler handler, - final UsageMapAsyncResponse asyncResponseDelegate, - final List hourlyBatteryLevelsPerDay, - final Map> batteryHistoryMap) { - mApplicationContext = context.getApplicationContext(); - mHandler = handler; - mAsyncResponseDelegate = asyncResponseDelegate; - mHourlyBatteryLevelsPerDay = hourlyBatteryLevelsPerDay; - mBatteryHistoryMap = batteryHistoryMap; - } - - @Override - protected Map> doInBackground(Void... voids) { - if (mApplicationContext == null - || mHandler == null - || mAsyncResponseDelegate == null - || mBatteryHistoryMap == null - || mHourlyBatteryLevelsPerDay == null) { - Log.e(TAG, "invalid input for ComputeUsageMapAndLoadItemsTask()"); - return null; - } - final long startTime = System.currentTimeMillis(); - // Loads the current battery usage data from the battery stats service and replaces the - // placeholder in mBatteryHistoryMap. - Map currentBatteryHistoryMap = - getCurrentBatteryHistoryMapFromStatsService(mApplicationContext); - for (Map.Entry> mapEntry - : mBatteryHistoryMap.entrySet()) { - if (mapEntry.getValue().containsKey(CURRENT_TIME_BATTERY_HISTORY_PLACEHOLDER)) { - mapEntry.setValue(currentBatteryHistoryMap); - } - } - - final Map> batteryUsageMap = - getBatteryUsageMap( - mApplicationContext, mHourlyBatteryLevelsPerDay, mBatteryHistoryMap); - loadLabelAndIcon(batteryUsageMap); - Log.d(TAG, String.format("execute ComputeUsageMapAndLoadItemsTask in %d/ms", - (System.currentTimeMillis() - startTime))); - return batteryUsageMap; - } - - @Override - protected void onPostExecute( - final Map> batteryUsageMap) { - mApplicationContext = null; - mHourlyBatteryLevelsPerDay = null; - mBatteryHistoryMap = null; - // Post results back to main thread to refresh UI. - if (mHandler != null && mAsyncResponseDelegate != null) { - mHandler.post(() -> { - mAsyncResponseDelegate.onBatteryUsageMapLoaded(batteryUsageMap); - }); - } - } - } } diff --git a/src/com/android/settings/fuelgauge/protos/app_usage_event.proto b/src/com/android/settings/fuelgauge/protos/app_usage_event.proto index c47fd1dbc65..65fef4ae7a9 100644 --- a/src/com/android/settings/fuelgauge/protos/app_usage_event.proto +++ b/src/com/android/settings/fuelgauge/protos/app_usage_event.proto @@ -40,3 +40,16 @@ message AppUsagePeriod { // End of the usage period. optional int64 end_time = 2; } + +enum AppUsageEndPointType { + START = 1; + END = 2; +} + +// The endpoint (the beginning or the end) of an AppUsagePeriod. +message AppUsageEndPoint { + // Type of the end point. + optional AppUsageEndPointType type = 1; + // Timestamp of the end point. + optional int64 timestamp = 2; +} diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceControllerTest.java index 839cae255db..a31fffa6717 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceControllerTest.java @@ -37,6 +37,7 @@ import android.content.res.Resources; import android.os.BatteryManager; import android.os.Bundle; import android.os.LocaleList; +import android.os.UserManager; import android.text.format.DateUtils; import android.view.View; import android.view.ViewPropertyAnimator; @@ -65,9 +66,9 @@ public final class BatteryChartPreferenceControllerTest { @Mock private Intent mIntent; @Mock - private SettingsActivity mSettingsActivity; + private UserManager mUserManager; @Mock - private BatteryHistEntry mBatteryHistEntry; + private SettingsActivity mSettingsActivity; @Mock private BatteryChartView mDailyChartView; @Mock @@ -79,7 +80,6 @@ public final class BatteryChartPreferenceControllerTest { private Context mContext; private FakeFeatureFactory mFeatureFactory; - private BatteryDiffEntry mBatteryDiffEntry; private BatteryChartPreferenceController mBatteryChartPreferenceController; @Before @@ -90,6 +90,11 @@ public final class BatteryChartPreferenceControllerTest { TimeZone.setDefault(TimeZone.getTimeZone("UTC")); mFeatureFactory = FakeFeatureFactory.setupForTest(); mContext = spy(RuntimeEnvironment.application); + doReturn(mContext).when(mContext).getApplicationContext(); + doReturn(mUserManager) + .when(mContext) + .getSystemService(UserManager.class); + doReturn(true).when(mUserManager).isUserUnlocked(anyInt()); final Resources resources = spy(mContext.getResources()); resources.getConfiguration().setLocales(new LocaleList(new Locale("en_US"))); doReturn(resources).when(mContext).getResources(); @@ -105,17 +110,6 @@ public final class BatteryChartPreferenceControllerTest { mBatteryChartPreferenceController.mPrefContext = mContext; mBatteryChartPreferenceController.mDailyChartView = mDailyChartView; mBatteryChartPreferenceController.mHourlyChartView = mHourlyChartView; - mBatteryDiffEntry = new BatteryDiffEntry( - mContext, - /*foregroundUsageTimeInMs=*/ 1, - /*backgroundUsageTimeInMs=*/ 2, - /*consumePower=*/ 3, - /*foregroundUsageConsumePower=*/ 0, - /*foregroundServiceUsageConsumePower=*/ 1, - /*backgroundUsageConsumePower=*/ 2, - /*cachedUsageConsumePower=*/ 0, - mBatteryHistEntry); - mBatteryDiffEntry = spy(mBatteryDiffEntry); // Adds fake testing data. BatteryDiffEntry.sResourceCache.put( "fakeBatteryDiffEntryKey", @@ -403,6 +397,7 @@ public final class BatteryChartPreferenceControllerTest { .build(); values.put(BatteryHistEntry.KEY_BATTERY_INFORMATION, ConvertUtils.convertBatteryInformationToString(batteryInformation)); + values.put(BatteryHistEntry.KEY_PACKAGE_NAME, "package" + index); final BatteryHistEntry entry = new BatteryHistEntry(values); final Map entryMap = new HashMap<>(); entryMap.put("fake_entry_key" + index, entry); diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffEntryTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffEntryTest.java index cb2f5c80123..900913b5526 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffEntryTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffEntryTest.java @@ -97,6 +97,7 @@ public final class BatteryDiffEntryTest { mContext, /*foregroundUsageTimeInMs=*/ 10001L, /*backgroundUsageTimeInMs=*/ 20002L, + /*screenOnTimeInMs=*/ 30003L, /*consumePower=*/ 22.0, /*foregroundUsageConsumePower=*/ 10.0, /*foregroundServiceUsageConsumePower=*/ 10.0, @@ -115,6 +116,7 @@ public final class BatteryDiffEntryTest { mContext, /*foregroundUsageTimeInMs=*/ 10001L, /*backgroundUsageTimeInMs=*/ 20002L, + /*screenOnTimeInMs=*/ 30003L, /*consumePower=*/ 22.0, /*foregroundUsageConsumePower=*/ 10.0, /*foregroundServiceUsageConsumePower=*/ 10.0, @@ -479,6 +481,7 @@ public final class BatteryDiffEntryTest { mContext, /*foregroundUsageTimeInMs=*/ 0, /*backgroundUsageTimeInMs=*/ 0, + /*screenOnTimeInMs=*/ 0, /*consumePower=*/ 0, /*foregroundUsageConsumePower=*/ 0, /*foregroundServiceUsageConsumePower=*/ 0, @@ -493,6 +496,7 @@ public final class BatteryDiffEntryTest { mContext, /*foregroundUsageTimeInMs=*/ 0, /*backgroundUsageTimeInMs=*/ 0, + /*screenOnTimeInMs=*/ 0, consumePower, /*foregroundUsageConsumePower=*/ 0, /*foregroundServiceUsageConsumePower=*/ 0, diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBreakdownControllerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBreakdownControllerTest.java index 1d06e608e26..e5afcc241f9 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBreakdownControllerTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBreakdownControllerTest.java @@ -96,6 +96,7 @@ public final class BatteryUsageBreakdownControllerTest { mContext, /*foregroundUsageTimeInMs=*/ 1, /*backgroundUsageTimeInMs=*/ 2, + /*screenOnTimeInMs=*/ 0, /*consumePower=*/ 3, /*foregroundUsageConsumePower=*/ 0, /*foregroundServiceUsageConsumePower=*/ 1, @@ -297,10 +298,10 @@ public final class BatteryUsageBreakdownControllerTest { private BatteryDiffEntry createBatteryDiffEntry( long foregroundUsageTimeInMs, long backgroundUsageTimeInMs) { return new BatteryDiffEntry( - mContext, foregroundUsageTimeInMs, backgroundUsageTimeInMs, /*consumePower=*/ 0, - /*foregroundUsageConsumePower=*/ 0, /*foregroundServiceUsageConsumePower=*/ 0, - /*backgroundUsageConsumePower=*/ 0, /*cachedUsageConsumePower=*/ 0, - mBatteryHistEntry); + mContext, foregroundUsageTimeInMs, backgroundUsageTimeInMs, /*screenOnTimeInMs=*/ 0, + /*consumePower=*/ 0, /*foregroundUsageConsumePower=*/ 0, + /*foregroundServiceUsageConsumePower=*/ 0, /*backgroundUsageConsumePower=*/ 0, + /*cachedUsageConsumePower=*/ 0, mBatteryHistEntry); } private BatteryUsageBreakdownController createController() { diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DataProcessManagerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DataProcessManagerTest.java index 7ee0fb9f4eb..409c803edc8 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DataProcessManagerTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DataProcessManagerTest.java @@ -83,7 +83,8 @@ public final class DataProcessManagerTest { mDataProcessManager = new DataProcessManager( mContext, /*handler=*/ null, /*callbackFunction=*/ null, - /*hourlyBatteryLevelsPerDay=*/ new ArrayList<>(), /*batteryHistoryMap=*/ null); + /*hourlyBatteryLevelsPerDay=*/ new ArrayList<>(), + /*batteryHistoryMap=*/ new HashMap<>()); } @Test @@ -174,7 +175,7 @@ public final class DataProcessManagerTest { final DataProcessManager dataProcessManager = new DataProcessManager( mContext, /*handler=*/ null, /*callbackFunction=*/ null, - hourlyBatteryLevelsPerDay, /*batteryHistoryMap=*/ null); + hourlyBatteryLevelsPerDay, /*batteryHistoryMap=*/ new HashMap<>()); dataProcessManager.start(); assertThat(dataProcessManager.getIsCurrentAppUsageLoaded()).isTrue(); diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DataProcessorTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DataProcessorTest.java index 063934fea6e..fb91ea2060d 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DataProcessorTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DataProcessorTest.java @@ -310,6 +310,62 @@ public final class DataProcessorTest { appUsageEventList.get(2), AppUsageEventType.DEVICE_SHUTDOWN, /*timestamp=*/ 4); } + @Test + public void getDeviceScreenOnTime_returnExpectedResult() { + final Map>>>> + appUsagePeriodMap = new HashMap<>(); + appUsagePeriodMap.put(0, new HashMap<>()); + appUsagePeriodMap.put(1, new HashMap<>()); + appUsagePeriodMap.put(2, null); + final long userId1 = 1; + final long userId2 = 2; + // Adds the index [0][0]. + Map>> appUsageMap = new HashMap<>(); + Map> userPeriodMap = new HashMap<>(); + appUsageMap.put(userId1, userPeriodMap); + userPeriodMap.put( + "package1", List.of(buildAppUsagePeriod(0, 5), buildAppUsagePeriod(5, 7))); + userPeriodMap.put("package2", List.of(buildAppUsagePeriod(10, 25))); + userPeriodMap = new HashMap<>(); + appUsageMap.put(userId2, userPeriodMap); + userPeriodMap.put("package3", List.of(buildAppUsagePeriod(15, 45))); + appUsagePeriodMap.get(0).put(0, appUsageMap); + // Adds the index [0][1]. + appUsageMap = new HashMap<>(); + userPeriodMap = new HashMap<>(); + appUsageMap.put(userId1, userPeriodMap); + userPeriodMap.put( + "package1", List.of(buildAppUsagePeriod(50, 60), buildAppUsagePeriod(70, 80))); + appUsagePeriodMap.get(0).put(1, appUsageMap); + // Adds the index [1][0]. + appUsageMap = new HashMap<>(); + userPeriodMap = new HashMap<>(); + appUsageMap.put(userId1, userPeriodMap); + userPeriodMap.put("package2", List.of(buildAppUsagePeriod(0, 8000000L))); + userPeriodMap.put("package3", + List.of(buildAppUsagePeriod(10, 15), buildAppUsagePeriod(25, 29))); + appUsagePeriodMap.get(1).put(0, appUsageMap); + + final Map> deviceScreenOnTime = + DataProcessor.getDeviceScreenOnTime(appUsagePeriodMap); + + assertThat(deviceScreenOnTime.get(0).get(0)).isEqualTo(42); + assertThat(deviceScreenOnTime.get(0).get(1)).isEqualTo(20); + assertThat(deviceScreenOnTime.get(1).get(0)).isEqualTo(7200000); + assertThat(deviceScreenOnTime.get(0).get(DataProcessor.SELECTED_INDEX_ALL)).isEqualTo(62); + assertThat(deviceScreenOnTime.get(1).get(DataProcessor.SELECTED_INDEX_ALL)) + .isEqualTo(7200000); + assertThat(deviceScreenOnTime + .get(DataProcessor.SELECTED_INDEX_ALL) + .get(DataProcessor.SELECTED_INDEX_ALL)) + .isEqualTo(7200062); + } + + @Test + public void getDeviceScreenOnTime_nullUsageMap_returnNull() { + assertThat(DataProcessor.getDeviceScreenOnTime(null)).isNull(); + } + @Test public void getHistoryMapWithExpectedTimestamps_emptyHistoryMap_returnEmptyMap() { assertThat(DataProcessor @@ -493,12 +549,12 @@ public final class DataProcessorTest { final Calendar startCalendar = Calendar.getInstance(); startCalendar.set(2022, 6, 5, 5, 0, 50); // 2022-07-05 05:00:50 final Calendar endCalendar = Calendar.getInstance(); - endCalendar.set(2022, 6, 6, 21, 00, 50); // 2022-07-06 21:00:50 + endCalendar.set(2022, 6, 6, 21, 0, 50); // 2022-07-06 21:00:50 final Calendar expectedStartCalendar = Calendar.getInstance(); - expectedStartCalendar.set(2022, 6, 5, 6, 00, 00); // 2022-07-05 06:00:00 + expectedStartCalendar.set(2022, 6, 5, 6, 0, 0); // 2022-07-05 06:00:00 final Calendar expectedEndCalendar = Calendar.getInstance(); - expectedEndCalendar.set(2022, 6, 6, 22, 00, 00); // 2022-07-06 20:00:00 + expectedEndCalendar.set(2022, 6, 6, 22, 0, 0); // 2022-07-06 20:00:00 verifyExpectedTimestampSlots( startCalendar, endCalendar, expectedStartCalendar, expectedEndCalendar); } @@ -692,7 +748,8 @@ public final class DataProcessorTest { new BatteryLevelData.PeriodBatteryLevelData(new ArrayList<>(), new ArrayList<>())); assertThat(DataProcessor.getBatteryUsageMap( - mContext, hourlyBatteryLevelsPerDay, new HashMap<>())).isNull(); + mContext, hourlyBatteryLevelsPerDay, new HashMap<>(), /*appUsagePeriodMap=*/ null)) + .isNull(); } @Test @@ -751,7 +808,7 @@ public final class DataProcessorTest { /*backgroundUsageTimeInMs=*/ 35L); entryMap.put(entry.getKey(), entry); entry = createBatteryHistEntry( - "package2", "label2", /*consumePower=*/ 10.0, + "package3", "label3", /*consumePower=*/ 10.0, /*foregroundUsageConsumePower=*/ 4, /*foregroundServiceUsageConsumePower=*/ 2, /*backgroundUsageConsumePower=*/ 2, /*cachedUsageConsumePower=*/ 2, /*uid=*/ 3L, currentUserId, @@ -759,7 +816,7 @@ public final class DataProcessorTest { /*backgroundUsageTimeInMs=*/ 50L); entryMap.put(entry.getKey(), entry); entry = createBatteryHistEntry( - "package3", "label3", /*consumePower=*/ 15.0, + "package4", "label3", /*consumePower=*/ 15.0, /*foregroundUsageConsumePower=*/ 6, /*foregroundServiceUsageConsumePower=*/ 3, /*backgroundUsageConsumePower=*/ 3, /*cachedUsageConsumePower=*/ 3, /*uid=*/ 4L, currentUserId, @@ -779,7 +836,7 @@ public final class DataProcessorTest { /*backgroundUsageTimeInMs=*/ 40L); entryMap.put(entry.getKey(), entry); entry = createBatteryHistEntry( - "package2", "label2", /*consumePower=*/ 20.0, + "package3", "label3", /*consumePower=*/ 20.0, /*foregroundUsageConsumePower=*/ 5, /*foregroundServiceUsageConsumePower=*/ 5, /*backgroundUsageConsumePower=*/ 5, /*cachedUsageConsumePower=*/ 5, /*uid=*/ 3L, currentUserId, @@ -787,7 +844,7 @@ public final class DataProcessorTest { /*backgroundUsageTimeInMs=*/ 60L); entryMap.put(entry.getKey(), entry); entry = createBatteryHistEntry( - "package3", "label3", /*consumePower=*/ 40.0, + "package4", "label4", /*consumePower=*/ 40.0, /*foregroundUsageConsumePower=*/ 8, /*foregroundServiceUsageConsumePower=*/ 8, /*backgroundUsageConsumePower=*/ 8, /*cachedUsageConsumePower=*/ 8, /*uid=*/ 4L, currentUserId, @@ -809,9 +866,31 @@ public final class DataProcessorTest { hourlyBatteryLevelsPerDay.add( new BatteryLevelData.PeriodBatteryLevelData(timestamps, levels)); + // Adds app usage data to test screen on time. + final Map>>>> + appUsagePeriodMap = new HashMap<>(); + appUsagePeriodMap.put(0, new HashMap<>()); + appUsagePeriodMap.put(1, new HashMap<>()); + // Adds the index [0][0]. + Map>> appUsageMap = new HashMap<>(); + Map> userPeriodMap = new HashMap<>(); + appUsageMap.put(Long.valueOf(currentUserId), userPeriodMap); + userPeriodMap.put("package2", List.of(buildAppUsagePeriod(0, 5))); + userPeriodMap.put("package3", List.of(buildAppUsagePeriod(10, 25))); + appUsagePeriodMap.get(0).put(0, appUsageMap); + // Adds the index [1][0]. + appUsageMap = new HashMap<>(); + userPeriodMap = new HashMap<>(); + appUsageMap.put(Long.valueOf(currentUserId), userPeriodMap); + userPeriodMap.put("package2", + List.of(buildAppUsagePeriod(2, 7), buildAppUsagePeriod(5, 9))); + userPeriodMap.put("package3", + List.of(buildAppUsagePeriod(10, 15), buildAppUsagePeriod(25, 29))); + appUsagePeriodMap.get(1).put(0, appUsageMap); + final Map> resultMap = DataProcessor.getBatteryUsageMap( - mContext, hourlyBatteryLevelsPerDay, batteryHistoryMap); + mContext, hourlyBatteryLevelsPerDay, batteryHistoryMap, appUsagePeriodMap); BatteryDiffData resultDiffData = resultMap @@ -822,45 +901,52 @@ public final class DataProcessorTest { ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*consumePercentage=*/ 50.0, /*foregroundUsageConsumePower=*/ 14, /*foregroundServiceUsageConsumePower=*/ 9, /*backgroundUsageConsumePower=*/ 9, /*cachedUsageConsumePower=*/ 8, - /*foregroundUsageTimeInMs=*/ 30, /*backgroundUsageTimeInMs=*/ 40); + /*foregroundUsageTimeInMs=*/ 30, /*backgroundUsageTimeInMs=*/ 40, + /*screenOnTimeInMs=*/ 12); assertBatteryDiffEntry( resultDiffData.getAppDiffEntryList().get(1), currentUserId, /*uid=*/ 4L, ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*consumePercentage=*/ 50.0, /*foregroundUsageConsumePower=*/ 8, /*foregroundServiceUsageConsumePower=*/ 8, /*backgroundUsageConsumePower=*/ 8, /*cachedUsageConsumePower=*/ 8, - /*foregroundUsageTimeInMs=*/ 5, /*backgroundUsageTimeInMs=*/ 5); + /*foregroundUsageTimeInMs=*/ 5, /*backgroundUsageTimeInMs=*/ 5, + /*screenOnTimeInMs=*/ 0); assertBatteryDiffEntry( resultDiffData.getSystemDiffEntryList().get(0), currentUserId, /*uid=*/ 3L, ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY, /*consumePercentage=*/ 100.0, /*foregroundUsageConsumePower=*/ 5, /*foregroundServiceUsageConsumePower=*/ 5, /*backgroundUsageConsumePower=*/ 5, /*cachedUsageConsumePower=*/ 5, - /*foregroundUsageTimeInMs=*/ 50, /*backgroundUsageTimeInMs=*/ 60); + /*foregroundUsageTimeInMs=*/ 50, /*backgroundUsageTimeInMs=*/ 60, + /*screenOnTimeInMs=*/ 9); resultDiffData = resultMap.get(0).get(DataProcessor.SELECTED_INDEX_ALL); assertBatteryDiffEntry( resultDiffData.getAppDiffEntryList().get(0), currentUserId, /*uid=*/ 2L, ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*consumePercentage=*/ 100.0, /*foregroundUsageConsumePower=*/ 5, /*foregroundServiceUsageConsumePower=*/ 5, /*backgroundUsageConsumePower=*/ 5, /*cachedUsageConsumePower=*/ 5, - /*foregroundUsageTimeInMs=*/ 15, /*backgroundUsageTimeInMs=*/ 25); + /*foregroundUsageTimeInMs=*/ 15, /*backgroundUsageTimeInMs=*/ 25, + /*screenOnTimeInMs=*/ 5); resultDiffData = resultMap.get(1).get(DataProcessor.SELECTED_INDEX_ALL); assertBatteryDiffEntry( resultDiffData.getAppDiffEntryList().get(0), currentUserId, /*uid=*/ 4L, ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*consumePercentage=*/ 66.66666666666666, /*foregroundUsageConsumePower=*/ 8, /*foregroundServiceUsageConsumePower=*/ 8, /*backgroundUsageConsumePower=*/ 8, /*cachedUsageConsumePower=*/ 8, - /*foregroundUsageTimeInMs=*/ 5, /*backgroundUsageTimeInMs=*/ 5); + /*foregroundUsageTimeInMs=*/ 5, /*backgroundUsageTimeInMs=*/ 5, + /*screenOnTimeInMs=*/ 0); assertBatteryDiffEntry( resultDiffData.getAppDiffEntryList().get(1), currentUserId, /*uid=*/ 2L, ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*consumePercentage=*/ 33.33333333333333, /*foregroundUsageConsumePower=*/ 9, /*foregroundServiceUsageConsumePower=*/ 4, /*backgroundUsageConsumePower=*/ 4, /*cachedUsageConsumePower=*/ 3, - /*foregroundUsageTimeInMs=*/ 15, /*backgroundUsageTimeInMs=*/ 15); + /*foregroundUsageTimeInMs=*/ 15, /*backgroundUsageTimeInMs=*/ 15, + /*screenOnTimeInMs=*/ 7); assertBatteryDiffEntry( resultDiffData.getSystemDiffEntryList().get(0), currentUserId, /*uid=*/ 3L, ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY, /*consumePercentage=*/ 100.0, /*foregroundUsageConsumePower=*/ 5, /*foregroundServiceUsageConsumePower=*/ 5, /*backgroundUsageConsumePower=*/ 5, /*cachedUsageConsumePower=*/ 5, - /*foregroundUsageTimeInMs=*/ 50, /*backgroundUsageTimeInMs=*/ 60); + /*foregroundUsageTimeInMs=*/ 50, /*backgroundUsageTimeInMs=*/ 60, + /*screenOnTimeInMs=*/ 9); } @Test @@ -962,7 +1048,8 @@ public final class DataProcessorTest { final Map> resultMap = DataProcessor.getBatteryUsageMap( - mContext, hourlyBatteryLevelsPerDay, batteryHistoryMap); + mContext, hourlyBatteryLevelsPerDay, batteryHistoryMap, + /*appUsagePeriodMap=*/ null); final BatteryDiffData resultDiffData = resultMap @@ -973,7 +1060,8 @@ public final class DataProcessorTest { ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*consumePercentage=*/ 100.0, /*foregroundUsageConsumePower=*/ 5, /*foregroundServiceUsageConsumePower=*/ 5, /*backgroundUsageConsumePower=*/ 5, /*cachedUsageConsumePower=*/ 5, - /*foregroundUsageTimeInMs=*/ 10, /*backgroundUsageTimeInMs=*/ 10); + /*foregroundUsageTimeInMs=*/ 10, /*backgroundUsageTimeInMs=*/ 10, + /*screenOnTimeInMs=*/ 0); assertThat(resultDiffData.getSystemDiffEntryList()).isEmpty(); assertThat(resultMap.get(0).get(0)).isNotNull(); assertThat(resultMap.get(0).get(DataProcessor.SELECTED_INDEX_ALL)).isNotNull(); @@ -1028,9 +1116,20 @@ public final class DataProcessorTest { hourlyBatteryLevelsPerDay.add( new BatteryLevelData.PeriodBatteryLevelData(timestamps, levels)); + // Adds app usage data to test screen on time. + final Map>>>> + appUsagePeriodMap = new HashMap<>(); + appUsagePeriodMap.put(0, new HashMap<>()); + // Adds the index [0][0]. + final Map>> appUsageMap = new HashMap<>(); + final Map> userPeriodMap = new HashMap<>(); + appUsageMap.put(Long.valueOf(currentUserId), userPeriodMap); + userPeriodMap.put("package1", List.of(buildAppUsagePeriod(0, 8000000))); + appUsagePeriodMap.get(0).put(0, appUsageMap); + final Map> resultMap = DataProcessor.getBatteryUsageMap( - mContext, hourlyBatteryLevelsPerDay, batteryHistoryMap); + mContext, hourlyBatteryLevelsPerDay, batteryHistoryMap, appUsagePeriodMap); final BatteryDiffData resultDiffData = resultMap @@ -1053,6 +1152,7 @@ public final class DataProcessorTest { .isEqualTo(entry.mBackgroundUsageConsumePower * ratio); assertThat(resultEntry.mCachedUsageConsumePower) .isEqualTo(entry.mCachedUsageConsumePower * ratio); + assertThat(resultEntry.mScreenOnTimeInMs).isEqualTo(7200000L); assertThat(resultMap.get(0).get(0)).isNotNull(); assertThat(resultMap.get(0).get(DataProcessor.SELECTED_INDEX_ALL)).isNotNull(); } @@ -1134,7 +1234,8 @@ public final class DataProcessorTest { final Map> resultMap = DataProcessor.getBatteryUsageMap( - mContext, hourlyBatteryLevelsPerDay, batteryHistoryMap); + mContext, hourlyBatteryLevelsPerDay, batteryHistoryMap, + /*appUsagePeriodMap=*/ null); final BatteryDiffData resultDiffData = resultMap @@ -1145,7 +1246,8 @@ public final class DataProcessorTest { ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*consumePercentage=*/ 100.0, /*foregroundUsageConsumePower=*/ 0, /*foregroundServiceUsageConsumePower=*/ 0, /*backgroundUsageConsumePower=*/ 5, /*cachedUsageConsumePower=*/ 5, - /*foregroundUsageTimeInMs=*/ 10, /*backgroundUsageTimeInMs=*/ 20); + /*foregroundUsageTimeInMs=*/ 10, /*backgroundUsageTimeInMs=*/ 20, + /*screenOnTimeInMs=*/ 0); } @Test @@ -1225,7 +1327,8 @@ public final class DataProcessorTest { final Map> resultMap = DataProcessor.getBatteryUsageMap( - mContext, hourlyBatteryLevelsPerDay, batteryHistoryMap); + mContext, hourlyBatteryLevelsPerDay, batteryHistoryMap, + /*appUsagePeriodMap=*/ null); final BatteryDiffData resultDiffData = resultMap @@ -1300,19 +1403,22 @@ public final class DataProcessorTest { ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*consumePercentage=*/ 100.0, /*foregroundUsageConsumePower=*/ 0.5, /*foregroundServiceUsageConsumePower=*/ 0, /*backgroundUsageConsumePower=*/ 0, /*cachedUsageConsumePower=*/ 0, - /*foregroundUsageTimeInMs=*/ 20, /*backgroundUsageTimeInMs=*/ 20); + /*foregroundUsageTimeInMs=*/ 20, /*backgroundUsageTimeInMs=*/ 20, + /*screenOnTimeInMs=*/ 0); assertBatteryDiffEntry( batteryDiffData.getAppDiffEntryList().get(1), 0, /*uid=*/ 1L, ConvertUtils.CONSUMER_TYPE_UID_BATTERY, /*consumePercentage=*/ 0.0, /*foregroundUsageConsumePower=*/ 0, /*foregroundServiceUsageConsumePower=*/ 0, /*backgroundUsageConsumePower=*/ 0, /*cachedUsageConsumePower=*/ 0, - /*foregroundUsageTimeInMs=*/ 30, /*backgroundUsageTimeInMs=*/ 40); + /*foregroundUsageTimeInMs=*/ 30, /*backgroundUsageTimeInMs=*/ 40, + /*screenOnTimeInMs=*/ 0); assertBatteryDiffEntry( batteryDiffData.getSystemDiffEntryList().get(0), 0, /*uid=*/ 4L, ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY, /*consumePercentage=*/ 100.0, /*foregroundUsageConsumePower=*/ 0.9, /*foregroundServiceUsageConsumePower=*/ 0.2, /*backgroundUsageConsumePower=*/ 0.3, /*cachedUsageConsumePower=*/ 0.1, - /*foregroundUsageTimeInMs=*/ 10, /*backgroundUsageTimeInMs=*/ 10); + /*foregroundUsageTimeInMs=*/ 10, /*backgroundUsageTimeInMs=*/ 10, + /*screenOnTimeInMs=*/ 0); } @Test @@ -1459,6 +1565,44 @@ public final class DataProcessorTest { assertAppUsagePeriod(appUsagePeriodList.get(0), 0, 100000); } + @Test + public void getScreenOnTime_returnExpectedResult() { + final long userId = 1; + final String packageName = "com.android.settings"; + final Map>> appUsageMap = new HashMap<>(); + final List appUsagePeriodList = new ArrayList<>(); + appUsageMap.put(userId, new HashMap<>()); + appUsageMap.get(userId).put(packageName, appUsagePeriodList); + // Fake overlapped case. + appUsagePeriodList.add(buildAppUsagePeriod(0, 5)); + appUsagePeriodList.add(buildAppUsagePeriod(2, 3)); + appUsagePeriodList.add(buildAppUsagePeriod(2, 4)); + appUsagePeriodList.add(buildAppUsagePeriod(5, 7)); + // Fake same case. + appUsagePeriodList.add(buildAppUsagePeriod(10, 12)); + appUsagePeriodList.add(buildAppUsagePeriod(10, 12)); + appUsagePeriodList.add(buildAppUsagePeriod(10, 12)); + // Fake normal case. + appUsagePeriodList.add(buildAppUsagePeriod(15, 20)); + appUsagePeriodList.add(buildAppUsagePeriod(35, 40)); + appUsagePeriodList.add(buildAppUsagePeriod(25, 30)); + + assertThat(DataProcessor.getScreenOnTime(appUsageMap, userId, packageName)).isEqualTo(24); + } + + @Test + public void getScreenOnTime_nullInput_returnZero() { + final long userId = 1; + final String packageName = "com.android.settings"; + final Map>> appUsageMap = new HashMap<>(); + appUsageMap.put(userId, new HashMap<>()); + + assertThat(DataProcessor.getScreenOnTime(null, userId, packageName)).isEqualTo(0); + assertThat(DataProcessor.getScreenOnTime(new HashMap<>(), userId, packageName)) + .isEqualTo(0); + assertThat(DataProcessor.getScreenOnTime(appUsageMap, userId, packageName)).isEqualTo(0); + } + private static Map> createHistoryMap( final long[] timestamps, final int[] levels) { final Map> batteryHistoryMap = new HashMap<>(); @@ -1558,6 +1702,13 @@ public final class DataProcessorTest { .build(); } + private AppUsagePeriod buildAppUsagePeriod(final long start, final long end) { + return AppUsagePeriod.newBuilder() + .setStartTime(start) + .setEndTime(end) + .build(); + } + private void assertAppUsageEvent( final AppUsageEvent event, final AppUsageEventType eventType, final long timestamp) { assertThat(event.getType()).isEqualTo(eventType); @@ -1635,7 +1786,8 @@ public final class DataProcessorTest { final double foregroundUsageConsumePower, final double foregroundServiceUsageConsumePower, final double backgroundUsageConsumePower, final double cachedUsageConsumePower, - final long foregroundUsageTimeInMs, final long backgroundUsageTimeInMs) { + final long foregroundUsageTimeInMs, final long backgroundUsageTimeInMs, + final long screenOnTimeInMs) { assertThat(entry.mBatteryHistEntry.mUserId).isEqualTo(userId); assertThat(entry.mBatteryHistEntry.mUid).isEqualTo(uid); assertThat(entry.mBatteryHistEntry.mConsumerType).isEqualTo(consumerType); @@ -1647,5 +1799,6 @@ public final class DataProcessorTest { assertThat(entry.mCachedUsageConsumePower).isEqualTo(cachedUsageConsumePower); assertThat(entry.mForegroundUsageTimeInMs).isEqualTo(foregroundUsageTimeInMs); assertThat(entry.mBackgroundUsageTimeInMs).isEqualTo(backgroundUsageTimeInMs); + assertThat(entry.mScreenOnTimeInMs).isEqualTo(screenOnTimeInMs); } }