Move the getBatteryLevelData function from DataProcessor to
DataProcessManager and start the async task in DataProcessManager when there is no battery level data. Test: make RunSettingsRoboTests + manually Bug: 260964903 Change-Id: Ie36ab6d121a5596a3abc16e7f570dd0d9b32e11c
This commit is contained in:
@@ -209,7 +209,7 @@ public class BatteryChartPreferenceController extends AbstractPreferenceControll
|
|||||||
// Ensure the battery chart group is visible for users.
|
// Ensure the battery chart group is visible for users.
|
||||||
animateBatteryChartViewGroup();
|
animateBatteryChartViewGroup();
|
||||||
final BatteryLevelData batteryLevelData =
|
final BatteryLevelData batteryLevelData =
|
||||||
DataProcessor.getBatteryLevelData(mContext, mHandler, batteryHistoryMap,
|
DataProcessManager.getBatteryLevelData(mContext, mHandler, batteryHistoryMap,
|
||||||
batteryUsageMap -> {
|
batteryUsageMap -> {
|
||||||
mBatteryUsageMap = batteryUsageMap;
|
mBatteryUsageMap = batteryUsageMap;
|
||||||
refreshUi();
|
refreshUi();
|
||||||
|
@@ -20,11 +20,13 @@ import android.app.usage.UsageEvents;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.os.AsyncTask;
|
import android.os.AsyncTask;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
|
import android.os.Looper;
|
||||||
import android.os.UserHandle;
|
import android.os.UserHandle;
|
||||||
import android.os.UserManager;
|
import android.os.UserManager;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
import com.android.internal.annotations.VisibleForTesting;
|
import com.android.internal.annotations.VisibleForTesting;
|
||||||
import com.android.settings.Utils;
|
import com.android.settings.Utils;
|
||||||
@@ -39,7 +41,7 @@ import java.util.Map;
|
|||||||
/**
|
/**
|
||||||
* Manages the async tasks to process battery and app usage data.
|
* 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:
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li>loadCurrentBatteryHistoryMap: load the latest battery history data from battery stats
|
* <li>loadCurrentBatteryHistoryMap: load the latest battery history data from battery stats
|
||||||
* service.</li>
|
* service.</li>
|
||||||
@@ -47,9 +49,11 @@ import java.util.Map;
|
|||||||
* from usage stats service.</li>
|
* from usage stats service.</li>
|
||||||
* <li>loadDatabaseAppUsageList: load the necessary app usage data (after last full charge) from
|
* <li>loadDatabaseAppUsageList: load the necessary app usage data (after last full charge) from
|
||||||
* database</li>
|
* database</li>
|
||||||
|
* <li>loadAndApplyBatteryMapFromServiceOnly: load all the battery history data (should be after
|
||||||
|
* last full charge) from battery stats service and apply the callback function directly</li>
|
||||||
* </ul>
|
* </ul>
|
||||||
*
|
*
|
||||||
* 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.
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li>After loadCurrentAppUsageList and loadDatabaseAppUsageList complete, which means all app
|
* <li>After loadCurrentAppUsageList and loadDatabaseAppUsageList complete, which means all app
|
||||||
* usage data has been loaded, the intermediate usage result will be generated.</li>
|
* usage data has been loaded, the intermediate usage result will be generated.</li>
|
||||||
@@ -59,6 +63,9 @@ import java.util.Map;
|
|||||||
* <li>If current user is locked, which means we couldn't get the latest app usage data,
|
* <li>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.</li>
|
* screen-on time will not be shown in the UI and empty screen-on time data will be returned.</li>
|
||||||
* </ul>
|
* </ul>
|
||||||
|
*
|
||||||
|
* 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 {
|
public class DataProcessManager {
|
||||||
private static final String TAG = "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
|
// 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
|
// start time when loading app usage data, this value is used as the start time of querying app
|
||||||
// usage data.
|
// usage data.
|
||||||
private long mStartTimestampOfLevelData = 0;
|
private long mStartTimestampOfLevelData;
|
||||||
|
|
||||||
private boolean mIsCurrentBatteryHistoryLoaded = false;
|
private boolean mIsCurrentBatteryHistoryLoaded = false;
|
||||||
private boolean mIsCurrentAppUsageLoaded = false;
|
private boolean mIsCurrentAppUsageLoaded = false;
|
||||||
private boolean mIsDatabaseAppUsageLoaded = false;
|
private boolean mIsDatabaseAppUsageLoaded = false;
|
||||||
// Used to identify whether screen-on time data should be shown in the UI.
|
// Used to identify whether screen-on time data should be shown in the UI.
|
||||||
private boolean mShowScreenOnTime = true;
|
private boolean mShowScreenOnTime = true;
|
||||||
|
// Used to identify whether battery level data should be shown in the UI.
|
||||||
|
private boolean mShowBatteryLevel = true;
|
||||||
|
|
||||||
private List<AppUsageEvent> mAppUsageEventList = new ArrayList<>();
|
private List<AppUsageEvent> mAppUsageEventList = new ArrayList<>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor when this exists battery level data.
|
* Constructor when there exists battery level data.
|
||||||
*/
|
*/
|
||||||
DataProcessManager(
|
DataProcessManager(
|
||||||
Context context,
|
Context context,
|
||||||
Handler handler,
|
Handler handler,
|
||||||
final DataProcessor.UsageMapAsyncResponse callbackFunction,
|
@NonNull final DataProcessor.UsageMapAsyncResponse callbackFunction,
|
||||||
@NonNull final List<BatteryLevelData.PeriodBatteryLevelData> hourlyBatteryLevelsPerDay,
|
@NonNull final List<BatteryLevelData.PeriodBatteryLevelData> hourlyBatteryLevelsPerDay,
|
||||||
@NonNull final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap) {
|
@NonNull final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap) {
|
||||||
mContext = context.getApplicationContext();
|
mContext = context.getApplicationContext();
|
||||||
@@ -102,16 +111,40 @@ public class DataProcessManager {
|
|||||||
mStartTimestampOfLevelData = getStartTimestampOfBatteryLevelData();
|
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.
|
* Starts the async tasks to load battery history data and app usage data.
|
||||||
*/
|
*/
|
||||||
public void start() {
|
public void start() {
|
||||||
// Load the latest battery history data from the service.
|
// 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();
|
loadCurrentBatteryHistoryMap();
|
||||||
// Load app usage list from database.
|
// Loads app usage list from database.
|
||||||
loadDatabaseAppUsageList();
|
loadDatabaseAppUsageList();
|
||||||
// Load the latest app usage list from the service.
|
// Loads the latest app usage list from the service.
|
||||||
loadCurrentAppUsageList();
|
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
|
@VisibleForTesting
|
||||||
@@ -154,6 +187,11 @@ public class DataProcessManager {
|
|||||||
return mShowScreenOnTime;
|
return mShowScreenOnTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
boolean getShowBatteryLevel() {
|
||||||
|
return mShowBatteryLevel;
|
||||||
|
}
|
||||||
|
|
||||||
private void loadCurrentBatteryHistoryMap() {
|
private void loadCurrentBatteryHistoryMap() {
|
||||||
new AsyncTask<Void, Void, Map<String, BatteryHistEntry>>() {
|
new AsyncTask<Void, Void, Map<String, BatteryHistEntry>>() {
|
||||||
@Override
|
@Override
|
||||||
@@ -279,6 +317,35 @@ public class DataProcessManager {
|
|||||||
}.execute();
|
}.execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void loadAndApplyBatteryMapFromServiceOnly() {
|
||||||
|
new AsyncTask<Void, Void, Map<Integer, Map<Integer, BatteryDiffData>>>() {
|
||||||
|
@Override
|
||||||
|
protected Map<Integer, Map<Integer, BatteryDiffData>> doInBackground(Void... voids) {
|
||||||
|
final long startTime = System.currentTimeMillis();
|
||||||
|
final Map<Integer, Map<Integer, BatteryDiffData>> 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<Integer, Map<Integer, BatteryDiffData>> 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() {
|
private void tryToProcessAppUsageData() {
|
||||||
// Only when all app usage events has been loaded, start processing app usage data to an
|
// Only when all app usage events has been loaded, start processing app usage data to an
|
||||||
// intermediate result for further use.
|
// intermediate result for further use.
|
||||||
@@ -313,6 +380,10 @@ public class DataProcessManager {
|
|||||||
private void generateFinalDataAndApplyCallback() {
|
private void generateFinalDataAndApplyCallback() {
|
||||||
// TODO: generate the final data including battery usage map and device screen-on time and
|
// TODO: generate the final data including battery usage map and device screen-on time and
|
||||||
// then apply the callback function.
|
// 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.
|
// Whether we should load app usage data from service or database.
|
||||||
@@ -350,4 +421,47 @@ public class DataProcessManager {
|
|||||||
Utils.getManagedProfile(mUserManager);
|
Utils.getManagedProfile(mUserManager);
|
||||||
return userHandle != null ? userHandle.getIdentifier() : Integer.MIN_VALUE;
|
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<Long, Map<String, BatteryHistEntry>> 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<Long, Map<String, BatteryHistEntry>> 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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -32,7 +32,6 @@ import android.os.BatteryStatsManager;
|
|||||||
import android.os.BatteryUsageStats;
|
import android.os.BatteryUsageStats;
|
||||||
import android.os.BatteryUsageStatsQuery;
|
import android.os.BatteryUsageStatsQuery;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.Looper;
|
|
||||||
import android.os.Process;
|
import android.os.Process;
|
||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
import android.os.ServiceManager;
|
import android.os.ServiceManager;
|
||||||
@@ -113,48 +112,6 @@ public final class DataProcessor {
|
|||||||
private 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<Long, Map<String, BatteryHistEntry>> 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<Long, Map<String, BatteryHistEntry>> 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.
|
* @return Returns battery usage data of different entries.
|
||||||
* Returns null if the input is invalid or there is no enough data.
|
* 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
|
* 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.
|
* timestamp. If there's no data in some key, the value will be the empty hashmap.
|
||||||
*/
|
*/
|
||||||
@VisibleForTesting
|
|
||||||
static Map<Long, Map<String, BatteryHistEntry>> getHistoryMapWithExpectedTimestamps(
|
static Map<Long, Map<String, BatteryHistEntry>> getHistoryMapWithExpectedTimestamps(
|
||||||
Context context,
|
Context context,
|
||||||
final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap) {
|
final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap) {
|
||||||
@@ -385,7 +341,6 @@ public final class DataProcessor {
|
|||||||
return resultMap;
|
return resultMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
|
||||||
@Nullable
|
@Nullable
|
||||||
static BatteryLevelData getLevelDataThroughProcessedHistoryMap(
|
static BatteryLevelData getLevelDataThroughProcessedHistoryMap(
|
||||||
Context context,
|
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(
|
static Map<Integer, Map<Integer, BatteryDiffData>> getBatteryUsageMapFromStatsService(
|
||||||
Context context,
|
final Context context) {
|
||||||
@Nullable Handler handler,
|
final Map<Integer, Map<Integer, BatteryDiffData>> resultMap = new HashMap<>();
|
||||||
final UsageMapAsyncResponse asyncResponseDelegate) {
|
final Map<Integer, BatteryDiffData> allUsageMap = new HashMap<>();
|
||||||
new LoadUsageMapFromBatteryStatsServiceTask(
|
// Always construct the map whether the value is null or not.
|
||||||
context,
|
allUsageMap.put(SELECTED_INDEX_ALL,
|
||||||
handler,
|
generateBatteryDiffData(context, getBatteryHistListFromFromStatsService(context)));
|
||||||
asyncResponseDelegate).execute();
|
resultMap.put(SELECTED_INDEX_ALL, allUsageMap);
|
||||||
|
processBatteryDiffData(context, resultMap);
|
||||||
|
return resultMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void loadLabelAndIcon(
|
||||||
|
@Nullable final Map<Integer, Map<Integer, BatteryDiffData>> 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
|
@Nullable
|
||||||
@@ -672,24 +648,6 @@ public final class DataProcessor {
|
|||||||
return events;
|
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<Integer, Map<Integer, BatteryDiffData>> getBatteryUsageMapFromStatsService(
|
|
||||||
final Context context) {
|
|
||||||
final Map<Integer, Map<Integer, BatteryDiffData>> resultMap = new HashMap<>();
|
|
||||||
final Map<Integer, BatteryDiffData> 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
|
@Nullable
|
||||||
private static List<BatteryHistEntry> getBatteryHistListFromFromStatsService(
|
private static List<BatteryHistEntry> getBatteryHistListFromFromStatsService(
|
||||||
final Context context) {
|
final Context context) {
|
||||||
@@ -1469,22 +1427,6 @@ public final class DataProcessor {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void loadLabelAndIcon(
|
|
||||||
@Nullable final Map<Integer, Map<Integer, BatteryDiffData>> 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) {
|
private static long getTimestampWithDayDiff(final long timestamp, final int dayDiff) {
|
||||||
final Calendar calendar = Calendar.getInstance();
|
final Calendar calendar = Calendar.getInstance();
|
||||||
calendar.setTimeInMillis(timestamp);
|
calendar.setTimeInMillis(timestamp);
|
||||||
@@ -1527,7 +1469,7 @@ public final class DataProcessor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Compute diff map and loads all items (icon and label) in the background.
|
// Compute diff map and loads all items (icon and label) in the background.
|
||||||
private static class ComputeUsageMapAndLoadItemsTask
|
static class ComputeUsageMapAndLoadItemsTask
|
||||||
extends AsyncTask<Void, Void, Map<Integer, Map<Integer, BatteryDiffData>>> {
|
extends AsyncTask<Void, Void, Map<Integer, Map<Integer, BatteryDiffData>>> {
|
||||||
|
|
||||||
Context mApplicationContext;
|
Context mApplicationContext;
|
||||||
@@ -1536,7 +1478,7 @@ public final class DataProcessor {
|
|||||||
private List<BatteryLevelData.PeriodBatteryLevelData> mHourlyBatteryLevelsPerDay;
|
private List<BatteryLevelData.PeriodBatteryLevelData> mHourlyBatteryLevelsPerDay;
|
||||||
private Map<Long, Map<String, BatteryHistEntry>> mBatteryHistoryMap;
|
private Map<Long, Map<String, BatteryHistEntry>> mBatteryHistoryMap;
|
||||||
|
|
||||||
private ComputeUsageMapAndLoadItemsTask(
|
ComputeUsageMapAndLoadItemsTask(
|
||||||
Context context,
|
Context context,
|
||||||
Handler handler,
|
Handler handler,
|
||||||
final UsageMapAsyncResponse asyncResponseDelegate,
|
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<Integer, Map<Integer, BatteryDiffData>> 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<Integer, Map<Integer, BatteryDiffData>> batteryUsageMap =
|
|
||||||
getBatteryUsageMapFromStatsService(mApplicationContext);
|
|
||||||
loadLabelAndIcon(batteryUsageMap);
|
|
||||||
Log.d(TAG, String.format("execute LoadUsageMapFromBatteryStatsServiceTask in %d/ms",
|
|
||||||
(System.currentTimeMillis() - startTime)));
|
|
||||||
return batteryUsageMap;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@@ -371,8 +371,8 @@ public final class BatteryChartPreferenceControllerTest {
|
|||||||
@Test
|
@Test
|
||||||
public void getTotalHours_getExpectedResult() {
|
public void getTotalHours_getExpectedResult() {
|
||||||
Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap = createBatteryHistoryMap(60);
|
Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap = createBatteryHistoryMap(60);
|
||||||
BatteryLevelData batteryLevelData = DataProcessor.getBatteryLevelData(mContext, null,
|
BatteryLevelData batteryLevelData =
|
||||||
batteryHistoryMap, null);
|
DataProcessManager.getBatteryLevelData(mContext, null, batteryHistoryMap, null);
|
||||||
|
|
||||||
final int totalHour = BatteryChartPreferenceController.getTotalHours(batteryLevelData);
|
final int totalHour = BatteryChartPreferenceController.getTotalHours(batteryLevelData);
|
||||||
|
|
||||||
|
@@ -21,16 +21,21 @@ import static com.google.common.truth.Truth.assertThat;
|
|||||||
import static org.mockito.ArgumentMatchers.any;
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
import static org.mockito.ArgumentMatchers.anyInt;
|
import static org.mockito.ArgumentMatchers.anyInt;
|
||||||
import static org.mockito.ArgumentMatchers.anyLong;
|
import static org.mockito.ArgumentMatchers.anyLong;
|
||||||
|
import static org.mockito.ArgumentMatchers.eq;
|
||||||
import static org.mockito.Mockito.doReturn;
|
import static org.mockito.Mockito.doReturn;
|
||||||
import static org.mockito.Mockito.spy;
|
import static org.mockito.Mockito.spy;
|
||||||
|
|
||||||
import android.app.usage.IUsageStatsManager;
|
import android.app.usage.IUsageStatsManager;
|
||||||
import android.app.usage.UsageEvents;
|
import android.app.usage.UsageEvents;
|
||||||
|
import android.content.ContentValues;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
import android.database.MatrixCursor;
|
import android.database.MatrixCursor;
|
||||||
|
import android.os.BatteryManager;
|
||||||
import android.os.Parcel;
|
import android.os.Parcel;
|
||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
import android.os.UserManager;
|
import android.os.UserManager;
|
||||||
|
import android.text.format.DateUtils;
|
||||||
|
|
||||||
import com.android.settings.fuelgauge.batteryusage.db.AppUsageEventEntity;
|
import com.android.settings.fuelgauge.batteryusage.db.AppUsageEventEntity;
|
||||||
|
|
||||||
@@ -43,10 +48,14 @@ import org.robolectric.RobolectricTestRunner;
|
|||||||
import org.robolectric.RuntimeEnvironment;
|
import org.robolectric.RuntimeEnvironment;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
@RunWith(RobolectricTestRunner.class)
|
@RunWith(RobolectricTestRunner.class)
|
||||||
public final class DataProcessManagerTest {
|
public final class DataProcessManagerTest {
|
||||||
|
private static final String FAKE_ENTRY_KEY = "fake_entry_key";
|
||||||
|
|
||||||
private Context mContext;
|
private Context mContext;
|
||||||
private DataProcessManager mDataProcessManager;
|
private DataProcessManager mDataProcessManager;
|
||||||
|
|
||||||
@@ -54,6 +63,8 @@ public final class DataProcessManagerTest {
|
|||||||
private IUsageStatsManager mUsageStatsManager;
|
private IUsageStatsManager mUsageStatsManager;
|
||||||
@Mock
|
@Mock
|
||||||
private UserManager mUserManager;
|
private UserManager mUserManager;
|
||||||
|
@Mock
|
||||||
|
private Intent mIntent;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
@@ -65,12 +76,23 @@ public final class DataProcessManagerTest {
|
|||||||
doReturn(mUserManager)
|
doReturn(mUserManager)
|
||||||
.when(mContext)
|
.when(mContext)
|
||||||
.getSystemService(UserManager.class);
|
.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(
|
mDataProcessManager = new DataProcessManager(
|
||||||
mContext, /*handler=*/ null, /*callbackFunction=*/ null,
|
mContext, /*handler=*/ null, /*callbackFunction=*/ null,
|
||||||
/*hourlyBatteryLevelsPerDay=*/ new ArrayList<>(), /*batteryHistoryMap=*/ 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
|
@Test
|
||||||
public void start_loadEmptyDatabaseAppUsageData() {
|
public void start_loadEmptyDatabaseAppUsageData() {
|
||||||
final MatrixCursor cursor = new MatrixCursor(
|
final MatrixCursor cursor = new MatrixCursor(
|
||||||
@@ -204,6 +226,66 @@ public final class DataProcessManagerTest {
|
|||||||
assertThat(dataProcessManager.getStartTimestampOfBatteryLevelData()).isEqualTo(0);
|
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<Long, Map<String, BatteryHistEntry>> 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<Long, Map<String, BatteryHistEntry>> batteryHistoryMap =
|
||||||
|
createHistoryMap(timestamps, levels);
|
||||||
|
DataProcessor.sFakeCurrentTimeMillis = timestamps[timestamps.length - 1];
|
||||||
|
|
||||||
|
final BatteryLevelData resultData =
|
||||||
|
DataProcessManager.getBatteryLevelData(
|
||||||
|
mContext,
|
||||||
|
/*handler=*/ null,
|
||||||
|
batteryHistoryMap,
|
||||||
|
/*asyncResponseDelegate=*/ null);
|
||||||
|
|
||||||
|
final List<Long> expectedDailyTimestamps = List.of(
|
||||||
|
1640966400000L, // 2022-01-01 00:00:00
|
||||||
|
1640973600000L); // 2022-01-01 02:00:00
|
||||||
|
final List<Integer> expectedDailyLevels = List.of(100, 66);
|
||||||
|
final List<List<Long>> expectedHourlyTimestamps = List.of(expectedDailyTimestamps);
|
||||||
|
final List<List<Integer>> expectedHourlyLevels = List.of(expectedDailyLevels);
|
||||||
|
verifyExpectedBatteryLevelData(
|
||||||
|
resultData,
|
||||||
|
expectedDailyTimestamps,
|
||||||
|
expectedDailyLevels,
|
||||||
|
expectedHourlyTimestamps,
|
||||||
|
expectedHourlyLevels);
|
||||||
|
}
|
||||||
|
|
||||||
private UsageEvents getUsageEvents(final List<UsageEvents.Event> events) {
|
private UsageEvents getUsageEvents(final List<UsageEvents.Event> events) {
|
||||||
UsageEvents usageEvents = new UsageEvents(events, new String[] {"package"});
|
UsageEvents usageEvents = new UsageEvents(events, new String[] {"package"});
|
||||||
Parcel parcel = Parcel.obtain();
|
Parcel parcel = Parcel.obtain();
|
||||||
@@ -222,9 +304,77 @@ public final class DataProcessManagerTest {
|
|||||||
return event;
|
return event;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static Map<Long, Map<String, BatteryHistEntry>> createHistoryMap(
|
||||||
|
final long[] timestamps, final int[] levels) {
|
||||||
|
final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap = new HashMap<>();
|
||||||
|
for (int index = 0; index < timestamps.length; index++) {
|
||||||
|
final Map<String, BatteryHistEntry> 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(
|
private void assertAppUsageEvent(
|
||||||
final AppUsageEvent event, final AppUsageEventType eventType, final long timestamp) {
|
final AppUsageEvent event, final AppUsageEventType eventType, final long timestamp) {
|
||||||
assertThat(event.getType()).isEqualTo(eventType);
|
assertThat(event.getType()).isEqualTo(eventType);
|
||||||
assertThat(event.getTimestamp()).isEqualTo(timestamp);
|
assertThat(event.getTimestamp()).isEqualTo(timestamp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void verifyExpectedBatteryLevelData(
|
||||||
|
final BatteryLevelData resultData,
|
||||||
|
final List<Long> expectedDailyTimestamps,
|
||||||
|
final List<Integer> expectedDailyLevels,
|
||||||
|
final List<List<Long>> expectedHourlyTimestamps,
|
||||||
|
final List<List<Integer>> expectedHourlyLevels) {
|
||||||
|
final BatteryLevelData.PeriodBatteryLevelData dailyResultData =
|
||||||
|
resultData.getDailyBatteryLevels();
|
||||||
|
final List<BatteryLevelData.PeriodBatteryLevelData> hourlyResultData =
|
||||||
|
resultData.getHourlyBatteryLevelsPerDay();
|
||||||
|
verifyExpectedDailyBatteryLevelData(
|
||||||
|
dailyResultData, expectedDailyTimestamps, expectedDailyLevels);
|
||||||
|
verifyExpectedHourlyBatteryLevelData(
|
||||||
|
hourlyResultData, expectedHourlyTimestamps, expectedHourlyLevels);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void verifyExpectedDailyBatteryLevelData(
|
||||||
|
final BatteryLevelData.PeriodBatteryLevelData dailyResultData,
|
||||||
|
final List<Long> expectedDailyTimestamps,
|
||||||
|
final List<Integer> expectedDailyLevels) {
|
||||||
|
assertThat(dailyResultData.getTimestamps()).isEqualTo(expectedDailyTimestamps);
|
||||||
|
assertThat(dailyResultData.getLevels()).isEqualTo(expectedDailyLevels);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void verifyExpectedHourlyBatteryLevelData(
|
||||||
|
final List<BatteryLevelData.PeriodBatteryLevelData> hourlyResultData,
|
||||||
|
final List<List<Long>> expectedHourlyTimestamps,
|
||||||
|
final List<List<Integer>> 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));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -98,66 +98,6 @@ public final class DataProcessorTest {
|
|||||||
doReturn(mUserManager).when(mContext).getSystemService(UserManager.class);
|
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<Long, Map<String, BatteryHistEntry>> 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<Long, Map<String, BatteryHistEntry>> batteryHistoryMap =
|
|
||||||
createHistoryMap(timestamps, levels);
|
|
||||||
DataProcessor.sFakeCurrentTimeMillis = timestamps[timestamps.length - 1];
|
|
||||||
|
|
||||||
final BatteryLevelData resultData =
|
|
||||||
DataProcessor.getBatteryLevelData(
|
|
||||||
mContext,
|
|
||||||
/*handler=*/ null,
|
|
||||||
batteryHistoryMap,
|
|
||||||
/*asyncResponseDelegate=*/ null);
|
|
||||||
|
|
||||||
final List<Long> expectedDailyTimestamps = List.of(
|
|
||||||
1640966400000L, // 2022-01-01 00:00:00
|
|
||||||
1640973600000L); // 2022-01-01 02:00:00
|
|
||||||
final List<Integer> expectedDailyLevels = List.of(100, 66);
|
|
||||||
final List<List<Long>> expectedHourlyTimestamps = List.of(expectedDailyTimestamps);
|
|
||||||
final List<List<Integer>> expectedHourlyLevels = List.of(expectedDailyLevels);
|
|
||||||
verifyExpectedBatteryLevelData(
|
|
||||||
resultData,
|
|
||||||
expectedDailyTimestamps,
|
|
||||||
expectedDailyLevels,
|
|
||||||
expectedHourlyTimestamps,
|
|
||||||
expectedHourlyLevels);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getAppUsageEvents_returnExpectedResult() throws RemoteException {
|
public void getAppUsageEvents_returnExpectedResult() throws RemoteException {
|
||||||
UserInfo userInfo = new UserInfo(/*id=*/ 0, "user_0", /*flags=*/ 0);
|
UserInfo userInfo = new UserInfo(/*id=*/ 0, "user_0", /*flags=*/ 0);
|
||||||
|
Reference in New Issue
Block a user