diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceController.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceController.java
index c2eab5749cd..b048dbc083b 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceController.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceController.java
@@ -209,7 +209,7 @@ public class BatteryChartPreferenceController extends AbstractPreferenceControll
// Ensure the battery chart group is visible for users.
animateBatteryChartViewGroup();
final BatteryLevelData batteryLevelData =
- DataProcessor.getBatteryLevelData(mContext, mHandler, batteryHistoryMap,
+ DataProcessManager.getBatteryLevelData(mContext, mHandler, batteryHistoryMap,
batteryUsageMap -> {
mBatteryUsageMap = batteryUsageMap;
refreshUi();
diff --git a/src/com/android/settings/fuelgauge/batteryusage/DataProcessManager.java b/src/com/android/settings/fuelgauge/batteryusage/DataProcessManager.java
index 784f64fab1e..dd6b9d9d4af 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/DataProcessManager.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/DataProcessManager.java
@@ -20,11 +20,13 @@ import android.app.usage.UsageEvents;
import android.content.Context;
import android.os.AsyncTask;
import android.os.Handler;
+import android.os.Looper;
import android.os.UserHandle;
import android.os.UserManager;
import android.util.Log;
import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import com.android.internal.annotations.VisibleForTesting;
import com.android.settings.Utils;
@@ -39,7 +41,7 @@ import java.util.Map;
/**
* Manages the async tasks to process battery and app usage data.
*
- * For now, there exist 3 async tasks in this manager:
+ * For now, there exist 4 async tasks in this manager:
*
* - loadCurrentBatteryHistoryMap: load the latest battery history data from battery stats
* service.
@@ -47,9 +49,11 @@ import java.util.Map;
* from usage stats service.
* - loadDatabaseAppUsageList: load the necessary app usage data (after last full charge) from
* database
+ * - loadAndApplyBatteryMapFromServiceOnly: load all the battery history data (should be after
+ * last full charge) from battery stats service and apply the callback function directly
*
*
- * The 3 async tasks will be started at the same time.
+ * If there is battery level data, the first 3 async tasks will be started at the same time.
*
* - After loadCurrentAppUsageList and loadDatabaseAppUsageList complete, which means all app
* usage data has been loaded, the intermediate usage result will be generated.
@@ -59,6 +63,9 @@ import java.util.Map;
* - If current user is locked, which means we couldn't get the latest app usage data,
* screen-on time will not be shown in the UI and empty screen-on time data will be returned.
*
+ *
+ * If there is no battery level data, the 4th async task will be started only and the usage map
+ * callback function will be applied directly to show the app list on the UI.
*/
public class DataProcessManager {
private static final String TAG = "DataProcessManager";
@@ -74,23 +81,25 @@ public class DataProcessManager {
// The start timestamp of battery level data. As we don't know when is the full charge cycle
// start time when loading app usage data, this value is used as the start time of querying app
// usage data.
- private long mStartTimestampOfLevelData = 0;
+ private long mStartTimestampOfLevelData;
private boolean mIsCurrentBatteryHistoryLoaded = false;
private boolean mIsCurrentAppUsageLoaded = false;
private boolean mIsDatabaseAppUsageLoaded = false;
// Used to identify whether screen-on time data should be shown in the UI.
private boolean mShowScreenOnTime = true;
+ // Used to identify whether battery level data should be shown in the UI.
+ private boolean mShowBatteryLevel = true;
private List mAppUsageEventList = new ArrayList<>();
/**
- * Constructor when this exists battery level data.
+ * Constructor when there exists battery level data.
*/
DataProcessManager(
Context context,
Handler handler,
- final DataProcessor.UsageMapAsyncResponse callbackFunction,
+ @NonNull final DataProcessor.UsageMapAsyncResponse callbackFunction,
@NonNull final List hourlyBatteryLevelsPerDay,
@NonNull final Map> batteryHistoryMap) {
mContext = context.getApplicationContext();
@@ -102,16 +111,40 @@ public class DataProcessManager {
mStartTimestampOfLevelData = getStartTimestampOfBatteryLevelData();
}
+ /**
+ * Constructor when there is no battery level data.
+ */
+ DataProcessManager(
+ Context context,
+ Handler handler,
+ @NonNull final DataProcessor.UsageMapAsyncResponse callbackFunction) {
+ mContext = context.getApplicationContext();
+ mHandler = handler;
+ mUserManager = mContext.getSystemService(UserManager.class);
+ mCallbackFunction = callbackFunction;
+ // When there is no battery level data, don't show screen-on time and battery level chart on
+ // the UI.
+ mShowScreenOnTime = false;
+ mShowBatteryLevel = false;
+ }
+
/**
* Starts the async tasks to load battery history data and app usage data.
*/
public void start() {
- // Load the latest battery history data from the service.
- loadCurrentBatteryHistoryMap();
- // Load app usage list from database.
- loadDatabaseAppUsageList();
- // Load the latest app usage list from the service.
- loadCurrentAppUsageList();
+ // If we have battery level data, load the battery history map and app usage simultaneously.
+ if (mShowBatteryLevel) {
+ // Loads the latest battery history data from the service.
+ loadCurrentBatteryHistoryMap();
+ // Loads app usage list from database.
+ loadDatabaseAppUsageList();
+ // Loads the latest app usage list from the service.
+ loadCurrentAppUsageList();
+ } else {
+ // If there is no battery level data, only load the battery history data from service
+ // and show it as the app list directly.
+ loadAndApplyBatteryMapFromServiceOnly();
+ }
}
@VisibleForTesting
@@ -154,6 +187,11 @@ public class DataProcessManager {
return mShowScreenOnTime;
}
+ @VisibleForTesting
+ boolean getShowBatteryLevel() {
+ return mShowBatteryLevel;
+ }
+
private void loadCurrentBatteryHistoryMap() {
new AsyncTask>() {
@Override
@@ -279,6 +317,35 @@ public class DataProcessManager {
}.execute();
}
+ private void loadAndApplyBatteryMapFromServiceOnly() {
+ new AsyncTask>>() {
+ @Override
+ protected Map> doInBackground(Void... voids) {
+ final long startTime = System.currentTimeMillis();
+ final Map> batteryUsageMap =
+ DataProcessor.getBatteryUsageMapFromStatsService(mContext);
+ DataProcessor.loadLabelAndIcon(batteryUsageMap);
+ Log.d(TAG, String.format(
+ "execute loadAndApplyBatteryMapFromServiceOnly size=%d in %d/ms",
+ batteryUsageMap.size(), (System.currentTimeMillis() - startTime)));
+ return batteryUsageMap;
+ }
+
+ @Override
+ protected void onPostExecute(
+ final Map> batteryUsageMap) {
+ // 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);
+ });
+ }
+ }
+ }.execute();
+ }
+
private void tryToProcessAppUsageData() {
// Only when all app usage events has been loaded, start processing app usage data to an
// intermediate result for further use.
@@ -313,6 +380,10 @@ 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;
}
// Whether we should load app usage data from service or database.
@@ -350,4 +421,47 @@ public class DataProcessManager {
Utils.getManagedProfile(mUserManager);
return userHandle != null ? userHandle.getIdentifier() : Integer.MIN_VALUE;
}
+
+ /**
+ * @return Returns battery level data and start async task to compute battery diff usage data
+ * and load app labels + icons.
+ * Returns null if the input is invalid or not having at least 2 hours data.
+ */
+ @Nullable
+ public static BatteryLevelData getBatteryLevelData(
+ Context context,
+ @Nullable Handler handler,
+ @Nullable final Map> batteryHistoryMap,
+ final DataProcessor.UsageMapAsyncResponse asyncResponseDelegate) {
+ if (batteryHistoryMap == null || batteryHistoryMap.isEmpty()) {
+ Log.d(TAG, "batteryHistoryMap is null in getBatteryLevelData()");
+ new DataProcessManager(context, handler, asyncResponseDelegate).start();
+ return null;
+ }
+ handler = handler != null ? handler : new Handler(Looper.getMainLooper());
+ // Process raw history map data into hourly timestamps.
+ final Map> processedBatteryHistoryMap =
+ DataProcessor.getHistoryMapWithExpectedTimestamps(context, batteryHistoryMap);
+ // Wrap and processed history map into easy-to-use format for UI rendering.
+ final BatteryLevelData batteryLevelData =
+ DataProcessor.getLevelDataThroughProcessedHistoryMap(
+ context, processedBatteryHistoryMap);
+ if (batteryLevelData == null) {
+ new DataProcessManager(context, handler, asyncResponseDelegate).start();
+ Log.d(TAG, "getBatteryLevelData() returns null");
+ 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(
+ context,
+ handler,
+ asyncResponseDelegate,
+ batteryLevelData.getHourlyBatteryLevelsPerDay(),
+ processedBatteryHistoryMap).execute();
+
+ return batteryLevelData;
+ }
}
diff --git a/src/com/android/settings/fuelgauge/batteryusage/DataProcessor.java b/src/com/android/settings/fuelgauge/batteryusage/DataProcessor.java
index bfedeab9264..3b3a13582da 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/DataProcessor.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/DataProcessor.java
@@ -32,7 +32,6 @@ import android.os.BatteryStatsManager;
import android.os.BatteryUsageStats;
import android.os.BatteryUsageStatsQuery;
import android.os.Handler;
-import android.os.Looper;
import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
@@ -113,48 +112,6 @@ public final class DataProcessor {
private DataProcessor() {
}
- /**
- * @return Returns battery level data and start async task to compute battery diff usage data
- * and load app labels + icons.
- * Returns null if the input is invalid or not having at least 2 hours data.
- */
- @Nullable
- public static BatteryLevelData getBatteryLevelData(
- Context context,
- @Nullable Handler handler,
- @Nullable final Map> batteryHistoryMap,
- final UsageMapAsyncResponse asyncResponseDelegate) {
- if (batteryHistoryMap == null || batteryHistoryMap.isEmpty()) {
- Log.d(TAG, "batteryHistoryMap is null in getBatteryLevelData()");
- loadBatteryUsageDataFromBatteryStatsService(
- context, handler, asyncResponseDelegate);
- return null;
- }
- handler = handler != null ? handler : new Handler(Looper.getMainLooper());
- // Process raw history map data into hourly timestamps.
- final Map> processedBatteryHistoryMap =
- getHistoryMapWithExpectedTimestamps(context, batteryHistoryMap);
- // Wrap and processed history map into easy-to-use format for UI rendering.
- final BatteryLevelData batteryLevelData =
- getLevelDataThroughProcessedHistoryMap(context, processedBatteryHistoryMap);
- if (batteryLevelData == null) {
- loadBatteryUsageDataFromBatteryStatsService(
- context, handler, asyncResponseDelegate);
- Log.d(TAG, "getBatteryLevelData() returns null");
- return null;
- }
-
- // Start the async task to compute diff usage data and load labels and icons.
- new ComputeUsageMapAndLoadItemsTask(
- context,
- handler,
- asyncResponseDelegate,
- batteryLevelData.getHourlyBatteryLevelsPerDay(),
- processedBatteryHistoryMap).execute();
-
- return batteryLevelData;
- }
-
/**
* @return Returns battery usage data of different entries.
* Returns null if the input is invalid or there is no enough data.
@@ -361,7 +318,6 @@ public final class DataProcessor {
* The keys of processed history map should contain every hour between the start and end
* timestamp. If there's no data in some key, the value will be the empty hashmap.
*/
- @VisibleForTesting
static Map> getHistoryMapWithExpectedTimestamps(
Context context,
final Map> batteryHistoryMap) {
@@ -385,7 +341,6 @@ public final class DataProcessor {
return resultMap;
}
- @VisibleForTesting
@Nullable
static BatteryLevelData getLevelDataThroughProcessedHistoryMap(
Context context,
@@ -624,16 +579,37 @@ public final class DataProcessor {
}
/**
- * Starts the async task to load battery diff usage data and load app labels + icons.
+ * @return Returns the overall battery usage data from battery stats service directly.
+ *
+ * The returned value should be always a 2d map and composed by only 1 part:
+ * - [SELECTED_INDEX_ALL][SELECTED_INDEX_ALL]
*/
- private static void loadBatteryUsageDataFromBatteryStatsService(
- Context context,
- @Nullable Handler handler,
- final UsageMapAsyncResponse asyncResponseDelegate) {
- new LoadUsageMapFromBatteryStatsServiceTask(
- context,
- handler,
- asyncResponseDelegate).execute();
+ static Map> getBatteryUsageMapFromStatsService(
+ final Context context) {
+ final Map> resultMap = new HashMap<>();
+ final Map allUsageMap = new HashMap<>();
+ // Always construct the map whether the value is null or not.
+ allUsageMap.put(SELECTED_INDEX_ALL,
+ generateBatteryDiffData(context, getBatteryHistListFromFromStatsService(context)));
+ resultMap.put(SELECTED_INDEX_ALL, allUsageMap);
+ processBatteryDiffData(context, resultMap);
+ return resultMap;
+ }
+
+ static void loadLabelAndIcon(
+ @Nullable final Map> batteryUsageMap) {
+ if (batteryUsageMap == null) {
+ return;
+ }
+ // Pre-loads each BatteryDiffEntry relative icon and label for all slots.
+ final BatteryDiffData batteryUsageMapForAll =
+ batteryUsageMap.get(SELECTED_INDEX_ALL).get(SELECTED_INDEX_ALL);
+ if (batteryUsageMapForAll != null) {
+ batteryUsageMapForAll.getAppDiffEntryList().forEach(
+ entry -> entry.loadLabelAndIcon());
+ batteryUsageMapForAll.getSystemDiffEntryList().forEach(
+ entry -> entry.loadLabelAndIcon());
+ }
}
@Nullable
@@ -672,24 +648,6 @@ public final class DataProcessor {
return events;
}
- /**
- * @return Returns the overall battery usage data from battery stats service directly.
- *
- * The returned value should be always a 2d map and composed by only 1 part:
- * - [SELECTED_INDEX_ALL][SELECTED_INDEX_ALL]
- */
- private static Map> getBatteryUsageMapFromStatsService(
- final Context context) {
- final Map> resultMap = new HashMap<>();
- final Map allUsageMap = new HashMap<>();
- // Always construct the map whether the value is null or not.
- allUsageMap.put(SELECTED_INDEX_ALL,
- generateBatteryDiffData(context, getBatteryHistListFromFromStatsService(context)));
- resultMap.put(SELECTED_INDEX_ALL, allUsageMap);
- processBatteryDiffData(context, resultMap);
- return resultMap;
- }
-
@Nullable
private static List getBatteryHistListFromFromStatsService(
final Context context) {
@@ -1469,22 +1427,6 @@ public final class DataProcessor {
return true;
}
- private static void loadLabelAndIcon(
- @Nullable final Map> batteryUsageMap) {
- if (batteryUsageMap == null) {
- return;
- }
- // Pre-loads each BatteryDiffEntry relative icon and label for all slots.
- final BatteryDiffData batteryUsageMapForAll =
- batteryUsageMap.get(SELECTED_INDEX_ALL).get(SELECTED_INDEX_ALL);
- if (batteryUsageMapForAll != null) {
- batteryUsageMapForAll.getAppDiffEntryList().forEach(
- entry -> entry.loadLabelAndIcon());
- batteryUsageMapForAll.getSystemDiffEntryList().forEach(
- entry -> entry.loadLabelAndIcon());
- }
- }
-
private static long getTimestampWithDayDiff(final long timestamp, final int dayDiff) {
final Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(timestamp);
@@ -1527,7 +1469,7 @@ public final class DataProcessor {
}
// Compute diff map and loads all items (icon and label) in the background.
- private static class ComputeUsageMapAndLoadItemsTask
+ static class ComputeUsageMapAndLoadItemsTask
extends AsyncTask>> {
Context mApplicationContext;
@@ -1536,7 +1478,7 @@ public final class DataProcessor {
private List mHourlyBatteryLevelsPerDay;
private Map> mBatteryHistoryMap;
- private ComputeUsageMapAndLoadItemsTask(
+ ComputeUsageMapAndLoadItemsTask(
Context context,
Handler handler,
final UsageMapAsyncResponse asyncResponseDelegate,
@@ -1594,35 +1536,4 @@ public final class DataProcessor {
}
}
}
-
- // Loads battery usage data from battery stats service directly and loads all items (icon and
- // label) in the background.
- private static final class LoadUsageMapFromBatteryStatsServiceTask
- extends ComputeUsageMapAndLoadItemsTask {
-
- private LoadUsageMapFromBatteryStatsServiceTask(
- Context context,
- Handler handler,
- final UsageMapAsyncResponse asyncResponseDelegate) {
- super(context, handler, asyncResponseDelegate, /*hourlyBatteryLevelsPerDay=*/ null,
- /*batteryHistoryMap=*/ null);
- }
-
- @Override
- protected Map> doInBackground(Void... voids) {
- if (mApplicationContext == null
- || mHandler == null
- || mAsyncResponseDelegate == null) {
- Log.e(TAG, "invalid input for ComputeUsageMapAndLoadItemsTask()");
- return null;
- }
- final long startTime = System.currentTimeMillis();
- final Map> batteryUsageMap =
- getBatteryUsageMapFromStatsService(mApplicationContext);
- loadLabelAndIcon(batteryUsageMap);
- Log.d(TAG, String.format("execute LoadUsageMapFromBatteryStatsServiceTask in %d/ms",
- (System.currentTimeMillis() - startTime)));
- return batteryUsageMap;
- }
- }
}
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 57963aaa111..839cae255db 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryChartPreferenceControllerTest.java
@@ -371,8 +371,8 @@ public final class BatteryChartPreferenceControllerTest {
@Test
public void getTotalHours_getExpectedResult() {
Map> batteryHistoryMap = createBatteryHistoryMap(60);
- BatteryLevelData batteryLevelData = DataProcessor.getBatteryLevelData(mContext, null,
- batteryHistoryMap, null);
+ BatteryLevelData batteryLevelData =
+ DataProcessManager.getBatteryLevelData(mContext, null, batteryHistoryMap, null);
final int totalHour = BatteryChartPreferenceController.getTotalHours(batteryLevelData);
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 1bfff0749bb..ee374692cae 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DataProcessManagerTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DataProcessManagerTest.java
@@ -21,16 +21,21 @@ import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
import android.app.usage.IUsageStatsManager;
import android.app.usage.UsageEvents;
+import android.content.ContentValues;
import android.content.Context;
+import android.content.Intent;
import android.database.MatrixCursor;
+import android.os.BatteryManager;
import android.os.Parcel;
import android.os.RemoteException;
import android.os.UserManager;
+import android.text.format.DateUtils;
import com.android.settings.fuelgauge.batteryusage.db.AppUsageEventEntity;
@@ -43,10 +48,14 @@ import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
@RunWith(RobolectricTestRunner.class)
public final class DataProcessManagerTest {
+ private static final String FAKE_ENTRY_KEY = "fake_entry_key";
+
private Context mContext;
private DataProcessManager mDataProcessManager;
@@ -54,6 +63,8 @@ public final class DataProcessManagerTest {
private IUsageStatsManager mUsageStatsManager;
@Mock
private UserManager mUserManager;
+ @Mock
+ private Intent mIntent;
@Before
public void setUp() {
@@ -65,12 +76,23 @@ public final class DataProcessManagerTest {
doReturn(mUserManager)
.when(mContext)
.getSystemService(UserManager.class);
+ doReturn(mIntent).when(mContext).registerReceiver(any(), any());
+ doReturn(100).when(mIntent).getIntExtra(eq(BatteryManager.EXTRA_SCALE), anyInt());
+ doReturn(66).when(mIntent).getIntExtra(eq(BatteryManager.EXTRA_LEVEL), anyInt());
mDataProcessManager = new DataProcessManager(
mContext, /*handler=*/ null, /*callbackFunction=*/ null,
/*hourlyBatteryLevelsPerDay=*/ new ArrayList<>(), /*batteryHistoryMap=*/ null);
}
+ @Test
+ public void constructor_noLevelData() {
+ final DataProcessManager dataProcessManager =
+ new DataProcessManager(mContext, /*handler=*/ null, /*callbackFunction=*/ null);
+ assertThat(dataProcessManager.getShowScreenOnTime()).isFalse();
+ assertThat(dataProcessManager.getShowBatteryLevel()).isFalse();
+ }
+
@Test
public void start_loadEmptyDatabaseAppUsageData() {
final MatrixCursor cursor = new MatrixCursor(
@@ -204,6 +226,66 @@ public final class DataProcessManagerTest {
assertThat(dataProcessManager.getStartTimestampOfBatteryLevelData()).isEqualTo(0);
}
+ @Test
+ public void getBatteryLevelData_emptyHistoryMap_returnNull() {
+ assertThat(DataProcessManager.getBatteryLevelData(
+ mContext,
+ /*handler=*/ null,
+ /*batteryHistoryMap=*/ null,
+ /*asyncResponseDelegate=*/ null))
+ .isNull();
+ assertThat(DataProcessManager.getBatteryLevelData(
+ mContext, /*handler=*/ null, new HashMap<>(), /*asyncResponseDelegate=*/ null))
+ .isNull();
+ }
+
+ @Test
+ public void getBatteryLevelData_notEnoughData_returnNull() {
+ // The timestamps and the current time are within half hour before an even hour.
+ final long[] timestamps = {
+ DateUtils.HOUR_IN_MILLIS * 2 - 300L,
+ DateUtils.HOUR_IN_MILLIS * 2 - 200L,
+ DateUtils.HOUR_IN_MILLIS * 2 - 100L};
+ final int[] levels = {100, 99, 98};
+ final Map> batteryHistoryMap =
+ createHistoryMap(timestamps, levels);
+ DataProcessor.sFakeCurrentTimeMillis = timestamps[timestamps.length - 1];
+
+ assertThat(DataProcessManager.getBatteryLevelData(
+ mContext, /*handler=*/ null, batteryHistoryMap, /*asyncResponseDelegate=*/ null))
+ .isNull();
+ }
+
+ @Test
+ public void getBatteryLevelData_returnExpectedResult() {
+ // Timezone GMT+8: 2022-01-01 00:00:00, 2022-01-01 01:00:00
+ final long[] timestamps = {1640966400000L, 1640970000000L};
+ final int[] levels = {100, 99};
+ final Map> batteryHistoryMap =
+ createHistoryMap(timestamps, levels);
+ DataProcessor.sFakeCurrentTimeMillis = timestamps[timestamps.length - 1];
+
+ final BatteryLevelData resultData =
+ DataProcessManager.getBatteryLevelData(
+ mContext,
+ /*handler=*/ null,
+ batteryHistoryMap,
+ /*asyncResponseDelegate=*/ null);
+
+ final List expectedDailyTimestamps = List.of(
+ 1640966400000L, // 2022-01-01 00:00:00
+ 1640973600000L); // 2022-01-01 02:00:00
+ final List expectedDailyLevels = List.of(100, 66);
+ final List> expectedHourlyTimestamps = List.of(expectedDailyTimestamps);
+ final List> expectedHourlyLevels = List.of(expectedDailyLevels);
+ verifyExpectedBatteryLevelData(
+ resultData,
+ expectedDailyTimestamps,
+ expectedDailyLevels,
+ expectedHourlyTimestamps,
+ expectedHourlyLevels);
+ }
+
private UsageEvents getUsageEvents(final List events) {
UsageEvents usageEvents = new UsageEvents(events, new String[] {"package"});
Parcel parcel = Parcel.obtain();
@@ -222,9 +304,77 @@ public final class DataProcessManagerTest {
return event;
}
+ private static Map> createHistoryMap(
+ final long[] timestamps, final int[] levels) {
+ final Map> batteryHistoryMap = new HashMap<>();
+ for (int index = 0; index < timestamps.length; index++) {
+ final Map entryMap = new HashMap<>();
+ final ContentValues values = getContentValuesWithBatteryLevel(levels[index]);
+ final BatteryHistEntry entry = new BatteryHistEntry(values);
+ entryMap.put(FAKE_ENTRY_KEY, entry);
+ batteryHistoryMap.put(timestamps[index], entryMap);
+ }
+ return batteryHistoryMap;
+ }
+
+ private static ContentValues getContentValuesWithBatteryLevel(final int level) {
+ final ContentValues values = new ContentValues();
+ final DeviceBatteryState deviceBatteryState =
+ DeviceBatteryState
+ .newBuilder()
+ .setBatteryLevel(level)
+ .build();
+ final BatteryInformation batteryInformation =
+ BatteryInformation
+ .newBuilder()
+ .setDeviceBatteryState(deviceBatteryState)
+ .build();
+ values.put(BatteryHistEntry.KEY_BATTERY_INFORMATION,
+ ConvertUtils.convertBatteryInformationToString(batteryInformation));
+ return values;
+ }
+
private void assertAppUsageEvent(
final AppUsageEvent event, final AppUsageEventType eventType, final long timestamp) {
assertThat(event.getType()).isEqualTo(eventType);
assertThat(event.getTimestamp()).isEqualTo(timestamp);
}
+
+ private static void verifyExpectedBatteryLevelData(
+ final BatteryLevelData resultData,
+ final List expectedDailyTimestamps,
+ final List expectedDailyLevels,
+ final List> expectedHourlyTimestamps,
+ final List> expectedHourlyLevels) {
+ final BatteryLevelData.PeriodBatteryLevelData dailyResultData =
+ resultData.getDailyBatteryLevels();
+ final List hourlyResultData =
+ resultData.getHourlyBatteryLevelsPerDay();
+ verifyExpectedDailyBatteryLevelData(
+ dailyResultData, expectedDailyTimestamps, expectedDailyLevels);
+ verifyExpectedHourlyBatteryLevelData(
+ hourlyResultData, expectedHourlyTimestamps, expectedHourlyLevels);
+ }
+
+ private static void verifyExpectedDailyBatteryLevelData(
+ final BatteryLevelData.PeriodBatteryLevelData dailyResultData,
+ final List expectedDailyTimestamps,
+ final List expectedDailyLevels) {
+ assertThat(dailyResultData.getTimestamps()).isEqualTo(expectedDailyTimestamps);
+ assertThat(dailyResultData.getLevels()).isEqualTo(expectedDailyLevels);
+ }
+
+ private static void verifyExpectedHourlyBatteryLevelData(
+ final List hourlyResultData,
+ final List> expectedHourlyTimestamps,
+ final List> expectedHourlyLevels) {
+ final int expectedHourlySize = expectedHourlyTimestamps.size();
+ assertThat(hourlyResultData).hasSize(expectedHourlySize);
+ for (int dailyIndex = 0; dailyIndex < expectedHourlySize; dailyIndex++) {
+ assertThat(hourlyResultData.get(dailyIndex).getTimestamps())
+ .isEqualTo(expectedHourlyTimestamps.get(dailyIndex));
+ assertThat(hourlyResultData.get(dailyIndex).getLevels())
+ .isEqualTo(expectedHourlyLevels.get(dailyIndex));
+ }
+ }
}
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 0f957541e44..aab3cb3a2f3 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DataProcessorTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DataProcessorTest.java
@@ -98,66 +98,6 @@ public final class DataProcessorTest {
doReturn(mUserManager).when(mContext).getSystemService(UserManager.class);
}
- @Test
- public void getBatteryLevelData_emptyHistoryMap_returnNull() {
- assertThat(DataProcessor.getBatteryLevelData(
- mContext,
- /*handler=*/ null,
- /*batteryHistoryMap=*/ null,
- /*asyncResponseDelegate=*/ null))
- .isNull();
- assertThat(DataProcessor.getBatteryLevelData(
- mContext, /*handler=*/ null, new HashMap<>(), /*asyncResponseDelegate=*/ null))
- .isNull();
- }
-
- @Test
- public void getBatteryLevelData_notEnoughData_returnNull() {
- // The timestamps and the current time are within half hour before an even hour.
- final long[] timestamps = {
- DateUtils.HOUR_IN_MILLIS * 2 - 300L,
- DateUtils.HOUR_IN_MILLIS * 2 - 200L,
- DateUtils.HOUR_IN_MILLIS * 2 - 100L};
- final int[] levels = {100, 99, 98};
- final Map> batteryHistoryMap =
- createHistoryMap(timestamps, levels);
- DataProcessor.sFakeCurrentTimeMillis = timestamps[timestamps.length - 1];
-
- assertThat(DataProcessor.getBatteryLevelData(
- mContext, /*handler=*/ null, batteryHistoryMap, /*asyncResponseDelegate=*/ null))
- .isNull();
- }
-
- @Test
- public void getBatteryLevelData_returnExpectedResult() {
- // Timezone GMT+8: 2022-01-01 00:00:00, 2022-01-01 01:00:00
- final long[] timestamps = {1640966400000L, 1640970000000L};
- final int[] levels = {100, 99};
- final Map> batteryHistoryMap =
- createHistoryMap(timestamps, levels);
- DataProcessor.sFakeCurrentTimeMillis = timestamps[timestamps.length - 1];
-
- final BatteryLevelData resultData =
- DataProcessor.getBatteryLevelData(
- mContext,
- /*handler=*/ null,
- batteryHistoryMap,
- /*asyncResponseDelegate=*/ null);
-
- final List expectedDailyTimestamps = List.of(
- 1640966400000L, // 2022-01-01 00:00:00
- 1640973600000L); // 2022-01-01 02:00:00
- final List expectedDailyLevels = List.of(100, 66);
- final List> expectedHourlyTimestamps = List.of(expectedDailyTimestamps);
- final List> expectedHourlyLevels = List.of(expectedDailyLevels);
- verifyExpectedBatteryLevelData(
- resultData,
- expectedDailyTimestamps,
- expectedDailyLevels,
- expectedHourlyTimestamps,
- expectedHourlyLevels);
- }
-
@Test
public void getAppUsageEvents_returnExpectedResult() throws RemoteException {
UserInfo userInfo = new UserInfo(/*id=*/ 0, "user_0", /*flags=*/ 0);