Merge "Battery usage page latency improvement (1-8)" into udc-qpr-dev am: 1dad0bf856
Original change: https://googleplex-android-review.googlesource.com/c/platform/packages/apps/Settings/+/24211971 Change-Id: I5b3b38a62fba34203e0195cdcc510c68f8e12652 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
@@ -83,6 +83,7 @@ android_library {
|
|||||||
"net-utils-framework-common",
|
"net-utils-framework-common",
|
||||||
"app-usage-event-protos-lite",
|
"app-usage-event-protos-lite",
|
||||||
"battery-event-protos-lite",
|
"battery-event-protos-lite",
|
||||||
|
"battery-usage-slot-protos-lite",
|
||||||
"power-anomaly-event-protos-lite",
|
"power-anomaly-event-protos-lite",
|
||||||
"settings-contextual-card-protos-lite",
|
"settings-contextual-card-protos-lite",
|
||||||
"settings-log-bridge-protos-lite",
|
"settings-log-bridge-protos-lite",
|
||||||
|
@@ -16,6 +16,8 @@
|
|||||||
|
|
||||||
package com.android.settings.fuelgauge;
|
package com.android.settings.fuelgauge;
|
||||||
|
|
||||||
|
import static com.android.settings.fuelgauge.batteryusage.ConvertUtils.isUserConsumer;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.app.ActivityManager;
|
import android.app.ActivityManager;
|
||||||
import android.app.backup.BackupManager;
|
import android.app.backup.BackupManager;
|
||||||
@@ -41,7 +43,6 @@ import com.android.settings.dashboard.DashboardFragment;
|
|||||||
import com.android.settings.fuelgauge.BatteryOptimizeHistoricalLogEntry.Action;
|
import com.android.settings.fuelgauge.BatteryOptimizeHistoricalLogEntry.Action;
|
||||||
import com.android.settings.fuelgauge.batteryusage.BatteryDiffEntry;
|
import com.android.settings.fuelgauge.batteryusage.BatteryDiffEntry;
|
||||||
import com.android.settings.fuelgauge.batteryusage.BatteryEntry;
|
import com.android.settings.fuelgauge.batteryusage.BatteryEntry;
|
||||||
import com.android.settings.fuelgauge.batteryusage.BatteryHistEntry;
|
|
||||||
import com.android.settings.overlay.FeatureFactory;
|
import com.android.settings.overlay.FeatureFactory;
|
||||||
import com.android.settings.widget.EntityHeaderController;
|
import com.android.settings.widget.EntityHeaderController;
|
||||||
import com.android.settingslib.HelpUtils;
|
import com.android.settingslib.HelpUtils;
|
||||||
@@ -149,14 +150,13 @@ public class AdvancedPowerUsageDetail extends DashboardFragment implements
|
|||||||
Context context, int sourceMetricsCategory,
|
Context context, int sourceMetricsCategory,
|
||||||
BatteryDiffEntry diffEntry, String usagePercent, String slotInformation,
|
BatteryDiffEntry diffEntry, String usagePercent, String slotInformation,
|
||||||
boolean showTimeInformation) {
|
boolean showTimeInformation) {
|
||||||
final BatteryHistEntry histEntry = diffEntry.mBatteryHistEntry;
|
|
||||||
final LaunchBatteryDetailPageArgs launchArgs = new LaunchBatteryDetailPageArgs();
|
final LaunchBatteryDetailPageArgs launchArgs = new LaunchBatteryDetailPageArgs();
|
||||||
// configure the launch argument.
|
// configure the launch argument.
|
||||||
launchArgs.mUsagePercent = usagePercent;
|
launchArgs.mUsagePercent = usagePercent;
|
||||||
launchArgs.mPackageName = diffEntry.getPackageName();
|
launchArgs.mPackageName = diffEntry.getPackageName();
|
||||||
launchArgs.mAppLabel = diffEntry.getAppLabel();
|
launchArgs.mAppLabel = diffEntry.getAppLabel();
|
||||||
launchArgs.mSlotInformation = slotInformation;
|
launchArgs.mSlotInformation = slotInformation;
|
||||||
launchArgs.mUid = (int) histEntry.mUid;
|
launchArgs.mUid = (int) diffEntry.mUid;
|
||||||
launchArgs.mIconId = diffEntry.getAppIconId();
|
launchArgs.mIconId = diffEntry.getAppIconId();
|
||||||
launchArgs.mConsumedPower = (int) diffEntry.mConsumePower;
|
launchArgs.mConsumedPower = (int) diffEntry.mConsumePower;
|
||||||
if (showTimeInformation) {
|
if (showTimeInformation) {
|
||||||
@@ -164,7 +164,7 @@ public class AdvancedPowerUsageDetail extends DashboardFragment implements
|
|||||||
launchArgs.mBackgroundTimeMs = diffEntry.mBackgroundUsageTimeInMs;
|
launchArgs.mBackgroundTimeMs = diffEntry.mBackgroundUsageTimeInMs;
|
||||||
launchArgs.mScreenOnTimeMs = diffEntry.mScreenOnTimeInMs;
|
launchArgs.mScreenOnTimeMs = diffEntry.mScreenOnTimeInMs;
|
||||||
}
|
}
|
||||||
launchArgs.mIsUserEntry = histEntry.isUserEntry();
|
launchArgs.mIsUserEntry = isUserConsumer(diffEntry.mConsumerType);
|
||||||
startBatteryDetailPage(context, sourceMetricsCategory, launchArgs);
|
startBatteryDetailPage(context, sourceMetricsCategory, launchArgs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,83 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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 android.app.usage.UsageEvents;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.os.AsyncTask;
|
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
import androidx.annotation.VisibleForTesting;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.function.Supplier;
|
|
||||||
|
|
||||||
/** Load app usage events data in the background. */
|
|
||||||
public final class AppUsageDataLoader {
|
|
||||||
private static final String TAG = "AppUsageDataLoader";
|
|
||||||
|
|
||||||
// For testing only.
|
|
||||||
@VisibleForTesting
|
|
||||||
static Supplier<Map<Long, UsageEvents>> sFakeAppUsageEventsSupplier;
|
|
||||||
@VisibleForTesting
|
|
||||||
static Supplier<List<AppUsageEvent>> sFakeUsageEventsListSupplier;
|
|
||||||
|
|
||||||
private AppUsageDataLoader() {}
|
|
||||||
|
|
||||||
static void enqueueWork(final Context context) {
|
|
||||||
AsyncTask.execute(() -> {
|
|
||||||
Log.d(TAG, "loadAppUsageDataSafely() in the AsyncTask");
|
|
||||||
loadAppUsageDataSafely(context.getApplicationContext());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@VisibleForTesting
|
|
||||||
static void loadAppUsageData(final Context context) {
|
|
||||||
final long start = System.currentTimeMillis();
|
|
||||||
final Map<Long, UsageEvents> appUsageEvents =
|
|
||||||
sFakeAppUsageEventsSupplier != null
|
|
||||||
? sFakeAppUsageEventsSupplier.get()
|
|
||||||
: DataProcessor.getAppUsageEvents(context);
|
|
||||||
if (appUsageEvents == null) {
|
|
||||||
Log.w(TAG, "loadAppUsageData() returns null");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
final List<AppUsageEvent> appUsageEventList =
|
|
||||||
sFakeUsageEventsListSupplier != null
|
|
||||||
? sFakeUsageEventsListSupplier.get()
|
|
||||||
: DataProcessor.generateAppUsageEventListFromUsageEvents(
|
|
||||||
context, appUsageEvents);
|
|
||||||
if (appUsageEventList == null || appUsageEventList.isEmpty()) {
|
|
||||||
Log.w(TAG, "loadAppUsageData() returns null or empty content");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
final long elapsedTime = System.currentTimeMillis() - start;
|
|
||||||
Log.d(TAG, String.format("loadAppUsageData() size=%d in %d/ms", appUsageEventList.size(),
|
|
||||||
elapsedTime));
|
|
||||||
// Uploads the AppUsageEvent data into database.
|
|
||||||
DatabaseUtils.sendAppUsageEventData(context, appUsageEventList);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void loadAppUsageDataSafely(final Context context) {
|
|
||||||
try {
|
|
||||||
loadAppUsageData(context);
|
|
||||||
} catch (RuntimeException e) {
|
|
||||||
Log.e(TAG, "loadAppUsageData:" + e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -132,7 +132,6 @@ public class BatteryChartPreferenceController extends AbstractPreferenceControll
|
|||||||
Map<Integer, Map<Integer, BatteryDiffData>> mBatteryUsageMap;
|
Map<Integer, Map<Integer, BatteryDiffData>> mBatteryUsageMap;
|
||||||
|
|
||||||
private boolean mIs24HourFormat;
|
private boolean mIs24HourFormat;
|
||||||
private boolean mHourlyChartVisible = true;
|
|
||||||
private View mBatteryChartViewGroup;
|
private View mBatteryChartViewGroup;
|
||||||
private TextView mChartSummaryTextView;
|
private TextView mChartSummaryTextView;
|
||||||
private BatteryChartViewModel mDailyViewModel;
|
private BatteryChartViewModel mDailyViewModel;
|
||||||
@@ -245,20 +244,8 @@ public class BatteryChartPreferenceController extends AbstractPreferenceControll
|
|||||||
mOnBatteryTipsUpdatedListener = listener;
|
mOnBatteryTipsUpdatedListener = listener;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setBatteryHistoryMap(
|
void onBatteryLevelDataUpdate(final BatteryLevelData batteryLevelData) {
|
||||||
final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap) {
|
Log.d(TAG, "onBatteryLevelDataUpdate: " + batteryLevelData);
|
||||||
Log.d(TAG, "setBatteryHistoryMap() " + (batteryHistoryMap == null ? "null"
|
|
||||||
: ("size=" + batteryHistoryMap.size())));
|
|
||||||
// Ensure the battery chart group is visible for users.
|
|
||||||
animateBatteryChartViewGroup();
|
|
||||||
final BatteryLevelData batteryLevelData =
|
|
||||||
DataProcessManager.getBatteryLevelData(mContext, mHandler, batteryHistoryMap,
|
|
||||||
batteryUsageMap -> {
|
|
||||||
mBatteryUsageMap = batteryUsageMap;
|
|
||||||
logScreenUsageTime();
|
|
||||||
refreshUi();
|
|
||||||
});
|
|
||||||
Log.d(TAG, "getBatteryLevelData: " + batteryLevelData);
|
|
||||||
mMetricsFeatureProvider.action(
|
mMetricsFeatureProvider.action(
|
||||||
mPrefContext,
|
mPrefContext,
|
||||||
SettingsEnums.ACTION_BATTERY_HISTORY_LOADED,
|
SettingsEnums.ACTION_BATTERY_HISTORY_LOADED,
|
||||||
@@ -289,6 +276,13 @@ public class BatteryChartPreferenceController extends AbstractPreferenceControll
|
|||||||
refreshUi();
|
refreshUi();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void onBatteryUsageMapUpdate(Map<Integer, Map<Integer, BatteryDiffData>> batteryUsageMap) {
|
||||||
|
Log.d(TAG, "onBatteryUsageMapUpdate: " + batteryUsageMap);
|
||||||
|
mBatteryUsageMap = batteryUsageMap;
|
||||||
|
logScreenUsageTime();
|
||||||
|
refreshUi();
|
||||||
|
}
|
||||||
|
|
||||||
void setBatteryChartView(@NonNull final BatteryChartView dailyChartView,
|
void setBatteryChartView(@NonNull final BatteryChartView dailyChartView,
|
||||||
@NonNull final BatteryChartView hourlyChartView) {
|
@NonNull final BatteryChartView hourlyChartView) {
|
||||||
final View parentView = (View) dailyChartView.getParent();
|
final View parentView = (View) dailyChartView.getParent();
|
||||||
@@ -512,10 +506,10 @@ public class BatteryChartPreferenceController extends AbstractPreferenceControll
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void animateBatteryHourlyChartView(final boolean visible) {
|
private void animateBatteryHourlyChartView(final boolean visible) {
|
||||||
if (mHourlyChartView == null || mHourlyChartVisible == visible) {
|
if (mHourlyChartView == null
|
||||||
|
|| (mHourlyChartView.getVisibility() == View.VISIBLE) == visible) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
mHourlyChartVisible = visible;
|
|
||||||
|
|
||||||
if (visible) {
|
if (visible) {
|
||||||
mHourlyChartView.setVisibility(View.VISIBLE);
|
mHourlyChartView.setVisibility(View.VISIBLE);
|
||||||
@@ -672,10 +666,8 @@ public class BatteryChartPreferenceController extends AbstractPreferenceControll
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
for (BatteryDiffEntry entry : entries) {
|
for (BatteryDiffEntry entry : entries) {
|
||||||
final BatteryHistEntry batteryHistEntry = entry.mBatteryHistEntry;
|
if (!entry.isSystemEntry()
|
||||||
if (batteryHistEntry != null
|
&& entry.mUserId == userId
|
||||||
&& batteryHistEntry.mConsumerType == ConvertUtils.CONSUMER_TYPE_UID_BATTERY
|
|
||||||
&& batteryHistEntry.mUserId == userId
|
|
||||||
&& packageName.equals(entry.getPackageName())) {
|
&& packageName.equals(entry.getPackageName())) {
|
||||||
return entry;
|
return entry;
|
||||||
}
|
}
|
||||||
|
@@ -17,6 +17,7 @@ package com.android.settings.fuelgauge.batteryusage;
|
|||||||
|
|
||||||
import static com.android.settings.Utils.formatPercentage;
|
import static com.android.settings.Utils.formatPercentage;
|
||||||
import static com.android.settings.fuelgauge.batteryusage.BatteryChartViewModel.AxisLabelPosition.BETWEEN_TRAPEZOIDS;
|
import static com.android.settings.fuelgauge.batteryusage.BatteryChartViewModel.AxisLabelPosition.BETWEEN_TRAPEZOIDS;
|
||||||
|
import static com.android.settingslib.fuelgauge.BatteryStatus.BATTERY_LEVEL_UNKNOWN;
|
||||||
|
|
||||||
import static java.lang.Math.abs;
|
import static java.lang.Math.abs;
|
||||||
import static java.lang.Math.round;
|
import static java.lang.Math.round;
|
||||||
@@ -615,8 +616,8 @@ public class BatteryChartView extends AppCompatImageView implements View.OnClick
|
|||||||
|
|
||||||
private static boolean isTrapezoidValid(
|
private static boolean isTrapezoidValid(
|
||||||
@NonNull BatteryChartViewModel viewModel, int trapezoidIndex) {
|
@NonNull BatteryChartViewModel viewModel, int trapezoidIndex) {
|
||||||
return viewModel.getLevel(trapezoidIndex) != null
|
return viewModel.getLevel(trapezoidIndex) != BATTERY_LEVEL_UNKNOWN
|
||||||
&& viewModel.getLevel(trapezoidIndex + 1) != null;
|
&& viewModel.getLevel(trapezoidIndex + 1) != BATTERY_LEVEL_UNKNOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isTrapezoidIndexValid(
|
private static boolean isTrapezoidIndexValid(
|
||||||
|
@@ -16,6 +16,8 @@
|
|||||||
|
|
||||||
package com.android.settings.fuelgauge.batteryusage;
|
package com.android.settings.fuelgauge.batteryusage;
|
||||||
|
|
||||||
|
import static com.android.settings.fuelgauge.batteryusage.ConvertUtils.utcToLocalTimeForLogging;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.os.BatteryConsumer;
|
import android.os.BatteryConsumer;
|
||||||
|
|
||||||
@@ -34,6 +36,10 @@ import java.util.Set;
|
|||||||
public class BatteryDiffData {
|
public class BatteryDiffData {
|
||||||
static final double SMALL_PERCENTAGE_THRESHOLD = 1f;
|
static final double SMALL_PERCENTAGE_THRESHOLD = 1f;
|
||||||
|
|
||||||
|
private final long mStartTimestamp;
|
||||||
|
private final long mEndTimestamp;
|
||||||
|
private final int mStartBatteryLevel;
|
||||||
|
private final int mEndBatteryLevel;
|
||||||
private final long mScreenOnTime;
|
private final long mScreenOnTime;
|
||||||
private final List<BatteryDiffEntry> mAppEntries;
|
private final List<BatteryDiffEntry> mAppEntries;
|
||||||
private final List<BatteryDiffEntry> mSystemEntries;
|
private final List<BatteryDiffEntry> mSystemEntries;
|
||||||
@@ -41,12 +47,20 @@ public class BatteryDiffData {
|
|||||||
/** Constructor for the diff entries. */
|
/** Constructor for the diff entries. */
|
||||||
public BatteryDiffData(
|
public BatteryDiffData(
|
||||||
final Context context,
|
final Context context,
|
||||||
|
final long startTimestamp,
|
||||||
|
final long endTimestamp,
|
||||||
|
final int startBatteryLevel,
|
||||||
|
final int endBatteryLevel,
|
||||||
final long screenOnTime,
|
final long screenOnTime,
|
||||||
final @NonNull List<BatteryDiffEntry> appDiffEntries,
|
final @NonNull List<BatteryDiffEntry> appDiffEntries,
|
||||||
final @NonNull List<BatteryDiffEntry> systemDiffEntries,
|
final @NonNull List<BatteryDiffEntry> systemDiffEntries,
|
||||||
final @NonNull Set<String> systemAppsPackageNames,
|
final @NonNull Set<String> systemAppsPackageNames,
|
||||||
final @NonNull Set<Integer> systemAppsUids,
|
final @NonNull Set<Integer> systemAppsUids,
|
||||||
final boolean isAccumulated) {
|
final boolean isAccumulated) {
|
||||||
|
mStartTimestamp = startTimestamp;
|
||||||
|
mEndTimestamp = endTimestamp;
|
||||||
|
mStartBatteryLevel = startBatteryLevel;
|
||||||
|
mEndBatteryLevel = endBatteryLevel;
|
||||||
mScreenOnTime = screenOnTime;
|
mScreenOnTime = screenOnTime;
|
||||||
mAppEntries = appDiffEntries;
|
mAppEntries = appDiffEntries;
|
||||||
mSystemEntries = systemDiffEntries;
|
mSystemEntries = systemDiffEntries;
|
||||||
@@ -63,18 +77,48 @@ public class BatteryDiffData {
|
|||||||
processAndSortEntries(mSystemEntries);
|
processAndSortEntries(mSystemEntries);
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getScreenOnTime() {
|
long getStartTimestamp() {
|
||||||
|
return mStartTimestamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
long getEndTimestamp() {
|
||||||
|
return mEndTimestamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
int getStartBatteryLevel() {
|
||||||
|
return mStartBatteryLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
int getEndBatteryLevel() {
|
||||||
|
return mEndBatteryLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
long getScreenOnTime() {
|
||||||
return mScreenOnTime;
|
return mScreenOnTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<BatteryDiffEntry> getAppDiffEntryList() {
|
List<BatteryDiffEntry> getAppDiffEntryList() {
|
||||||
return mAppEntries;
|
return mAppEntries;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<BatteryDiffEntry> getSystemDiffEntryList() {
|
List<BatteryDiffEntry> getSystemDiffEntryList() {
|
||||||
return mSystemEntries;
|
return mSystemEntries;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return new StringBuilder("BatteryDiffData{")
|
||||||
|
.append("startTimestamp:" + utcToLocalTimeForLogging(mStartTimestamp))
|
||||||
|
.append("|endTimestamp:" + utcToLocalTimeForLogging(mEndTimestamp))
|
||||||
|
.append("|startLevel:" + mStartBatteryLevel)
|
||||||
|
.append("|endLevel:" + mEndBatteryLevel)
|
||||||
|
.append("|screenOnTime:" + mScreenOnTime)
|
||||||
|
.append("|appEntries.size:" + mAppEntries.size())
|
||||||
|
.append("|systemEntries.size:" + mSystemEntries.size())
|
||||||
|
.append("}")
|
||||||
|
.toString();
|
||||||
|
}
|
||||||
|
|
||||||
/** Removes fake usage data and hidden packages. */
|
/** Removes fake usage data and hidden packages. */
|
||||||
private void purgeBatteryDiffData(final PowerUsageFeatureProvider featureProvider) {
|
private void purgeBatteryDiffData(final PowerUsageFeatureProvider featureProvider) {
|
||||||
purgeBatteryDiffData(featureProvider, mAppEntries);
|
purgeBatteryDiffData(featureProvider, mAppEntries);
|
||||||
@@ -109,7 +153,7 @@ public class BatteryDiffData {
|
|||||||
final long screenOnTimeInMs = entry.mScreenOnTimeInMs;
|
final long screenOnTimeInMs = entry.mScreenOnTimeInMs;
|
||||||
final double comsumePower = entry.mConsumePower;
|
final double comsumePower = entry.mConsumePower;
|
||||||
final String packageName = entry.getPackageName();
|
final String packageName = entry.getPackageName();
|
||||||
final Integer componentId = entry.mBatteryHistEntry.mDrainType;
|
final Integer componentId = entry.mComponentId;
|
||||||
if ((screenOnTimeInMs < screenOnTimeThresholdInMs
|
if ((screenOnTimeInMs < screenOnTimeThresholdInMs
|
||||||
&& comsumePower < consumePowerThreshold)
|
&& comsumePower < consumePowerThreshold)
|
||||||
|| ConvertUtils.FAKE_PACKAGE_NAME.equals(packageName)
|
|| ConvertUtils.FAKE_PACKAGE_NAME.equals(packageName)
|
||||||
@@ -130,14 +174,16 @@ public class BatteryDiffData {
|
|||||||
final @NonNull Set<Integer> systemAppsUids,
|
final @NonNull Set<Integer> systemAppsUids,
|
||||||
final @NonNull List<BatteryDiffEntry> appEntries) {
|
final @NonNull List<BatteryDiffEntry> appEntries) {
|
||||||
final List<String> systemAppsAllowlist = featureProvider.getSystemAppsAllowlist();
|
final List<String> systemAppsAllowlist = featureProvider.getSystemAppsAllowlist();
|
||||||
BatteryDiffEntry.SystemAppsBatteryDiffEntry systemAppsDiffEntry = null;
|
BatteryDiffEntry systemAppsDiffEntry = null;
|
||||||
final Iterator<BatteryDiffEntry> appListIterator = appEntries.iterator();
|
final Iterator<BatteryDiffEntry> appListIterator = appEntries.iterator();
|
||||||
while (appListIterator.hasNext()) {
|
while (appListIterator.hasNext()) {
|
||||||
final BatteryDiffEntry batteryDiffEntry = appListIterator.next();
|
final BatteryDiffEntry batteryDiffEntry = appListIterator.next();
|
||||||
if (needsCombineInSystemApp(batteryDiffEntry, systemAppsAllowlist,
|
if (needsCombineInSystemApp(batteryDiffEntry, systemAppsAllowlist,
|
||||||
systemAppsPackageNames, systemAppsUids)) {
|
systemAppsPackageNames, systemAppsUids)) {
|
||||||
if (systemAppsDiffEntry == null) {
|
if (systemAppsDiffEntry == null) {
|
||||||
systemAppsDiffEntry = new BatteryDiffEntry.SystemAppsBatteryDiffEntry(context);
|
systemAppsDiffEntry = new BatteryDiffEntry(context,
|
||||||
|
BatteryDiffEntry.SYSTEM_APPS_KEY, BatteryDiffEntry.SYSTEM_APPS_KEY,
|
||||||
|
ConvertUtils.CONSUMER_TYPE_UID_BATTERY);
|
||||||
}
|
}
|
||||||
systemAppsDiffEntry.mConsumePower += batteryDiffEntry.mConsumePower;
|
systemAppsDiffEntry.mConsumePower += batteryDiffEntry.mConsumePower;
|
||||||
systemAppsDiffEntry.mForegroundUsageTimeInMs +=
|
systemAppsDiffEntry.mForegroundUsageTimeInMs +=
|
||||||
@@ -159,17 +205,18 @@ public class BatteryDiffData {
|
|||||||
final Set<Integer> othersSystemComponentSet = featureProvider.getOthersSystemComponentSet();
|
final Set<Integer> othersSystemComponentSet = featureProvider.getOthersSystemComponentSet();
|
||||||
final Set<String> othersCustomComponentNameSet =
|
final Set<String> othersCustomComponentNameSet =
|
||||||
featureProvider.getOthersCustomComponentNameSet();
|
featureProvider.getOthersCustomComponentNameSet();
|
||||||
BatteryDiffEntry.OthersBatteryDiffEntry othersDiffEntry = null;
|
BatteryDiffEntry othersDiffEntry = null;
|
||||||
final Iterator<BatteryDiffEntry> systemListIterator = systemEntries.iterator();
|
final Iterator<BatteryDiffEntry> systemListIterator = systemEntries.iterator();
|
||||||
while (systemListIterator.hasNext()) {
|
while (systemListIterator.hasNext()) {
|
||||||
final BatteryDiffEntry batteryDiffEntry = systemListIterator.next();
|
final BatteryDiffEntry batteryDiffEntry = systemListIterator.next();
|
||||||
final int componentId = batteryDiffEntry.mBatteryHistEntry.mDrainType;
|
final int componentId = batteryDiffEntry.mComponentId;
|
||||||
if (othersSystemComponentSet.contains(componentId) || (
|
if (othersSystemComponentSet.contains(componentId) || (
|
||||||
componentId >= BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID
|
componentId >= BatteryConsumer.FIRST_CUSTOM_POWER_COMPONENT_ID
|
||||||
&& othersCustomComponentNameSet.contains(
|
&& othersCustomComponentNameSet.contains(
|
||||||
batteryDiffEntry.getAppLabel()))) {
|
batteryDiffEntry.getAppLabel()))) {
|
||||||
if (othersDiffEntry == null) {
|
if (othersDiffEntry == null) {
|
||||||
othersDiffEntry = new BatteryDiffEntry.OthersBatteryDiffEntry(context);
|
othersDiffEntry = new BatteryDiffEntry(context, BatteryDiffEntry.OTHERS_KEY,
|
||||||
|
BatteryDiffEntry.OTHERS_KEY, ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY);
|
||||||
}
|
}
|
||||||
othersDiffEntry.mConsumePower += batteryDiffEntry.mConsumePower;
|
othersDiffEntry.mConsumePower += batteryDiffEntry.mConsumePower;
|
||||||
othersDiffEntry.setTotalConsumePower(
|
othersDiffEntry.setTotalConsumePower(
|
||||||
@@ -188,7 +235,7 @@ public class BatteryDiffData {
|
|||||||
final @NonNull List<String> systemAppsAllowlist,
|
final @NonNull List<String> systemAppsAllowlist,
|
||||||
final @NonNull Set<String> systemAppsPackageNames,
|
final @NonNull Set<String> systemAppsPackageNames,
|
||||||
final @NonNull Set<Integer> systemAppsUids) {
|
final @NonNull Set<Integer> systemAppsUids) {
|
||||||
if (batteryDiffEntry.mBatteryHistEntry.mIsHidden) {
|
if (batteryDiffEntry.mIsHidden) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -201,7 +248,7 @@ public class BatteryDiffData {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int uid = (int) batteryDiffEntry.mBatteryHistEntry.mUid;
|
int uid = (int) batteryDiffEntry.mUid;
|
||||||
return systemAppsPackageNames.contains(packageName) || systemAppsUids.contains(uid);
|
return systemAppsPackageNames.contains(packageName) || systemAppsUids.contains(uid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -15,7 +15,6 @@
|
|||||||
*/
|
*/
|
||||||
package com.android.settings.fuelgauge.batteryusage;
|
package com.android.settings.fuelgauge.batteryusage;
|
||||||
|
|
||||||
import android.content.ContentValues;
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.pm.ApplicationInfo;
|
import android.content.pm.ApplicationInfo;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
@@ -24,6 +23,7 @@ import android.graphics.drawable.Drawable;
|
|||||||
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 android.util.Pair;
|
||||||
|
|
||||||
import androidx.annotation.VisibleForTesting;
|
import androidx.annotation.VisibleForTesting;
|
||||||
|
|
||||||
@@ -45,12 +45,29 @@ public class BatteryDiffEntry {
|
|||||||
static final Map<String, BatteryEntry.NameAndIcon> sResourceCache = new HashMap<>();
|
static final Map<String, BatteryEntry.NameAndIcon> sResourceCache = new HashMap<>();
|
||||||
// Whether a specific item is valid to launch restriction page?
|
// Whether a specific item is valid to launch restriction page?
|
||||||
@VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
|
@VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
|
||||||
public static final Map<String, Boolean> sValidForRestriction = new HashMap<>();
|
static final Map<String, Boolean> sValidForRestriction = new HashMap<>();
|
||||||
|
|
||||||
/** A comparator for {@link BatteryDiffEntry} based on the sorting key. */
|
/** A comparator for {@link BatteryDiffEntry} based on the sorting key. */
|
||||||
public static final Comparator<BatteryDiffEntry> COMPARATOR =
|
static final Comparator<BatteryDiffEntry> COMPARATOR =
|
||||||
(a, b) -> Double.compare(b.getSortingKey(), a.getSortingKey());
|
(a, b) -> Double.compare(b.getSortingKey(), a.getSortingKey());
|
||||||
|
static final String SYSTEM_APPS_KEY = "A|SystemApps";
|
||||||
|
static final String OTHERS_KEY = "S|Others";
|
||||||
|
|
||||||
|
// key -> (label_id, icon_id)
|
||||||
|
private static final Map<String, Pair<Integer, Integer>> SPECIAL_ENTRY_MAP = Map.of(
|
||||||
|
SYSTEM_APPS_KEY,
|
||||||
|
Pair.create(R.string.battery_usage_system_apps, R.drawable.ic_power_system),
|
||||||
|
OTHERS_KEY,
|
||||||
|
Pair.create(R.string.battery_usage_others,
|
||||||
|
R.drawable.ic_settings_battery_usage_others));
|
||||||
|
|
||||||
|
public long mUid;
|
||||||
|
public long mUserId;
|
||||||
|
public String mKey;
|
||||||
|
public boolean mIsHidden;
|
||||||
|
public int mComponentId;
|
||||||
|
public String mLegacyPackageName;
|
||||||
|
public String mLegacyLabel;
|
||||||
|
public int mConsumerType;
|
||||||
public long mForegroundUsageTimeInMs;
|
public long mForegroundUsageTimeInMs;
|
||||||
public long mBackgroundUsageTimeInMs;
|
public long mBackgroundUsageTimeInMs;
|
||||||
public long mScreenOnTimeInMs;
|
public long mScreenOnTimeInMs;
|
||||||
@@ -59,8 +76,6 @@ public class BatteryDiffEntry {
|
|||||||
public double mForegroundServiceUsageConsumePower;
|
public double mForegroundServiceUsageConsumePower;
|
||||||
public double mBackgroundUsageConsumePower;
|
public double mBackgroundUsageConsumePower;
|
||||||
public double mCachedUsageConsumePower;
|
public double mCachedUsageConsumePower;
|
||||||
// A BatteryHistEntry corresponding to this diff usage data.
|
|
||||||
public final BatteryHistEntry mBatteryHistEntry;
|
|
||||||
|
|
||||||
protected Context mContext;
|
protected Context mContext;
|
||||||
|
|
||||||
@@ -83,6 +98,14 @@ public class BatteryDiffEntry {
|
|||||||
|
|
||||||
public BatteryDiffEntry(
|
public BatteryDiffEntry(
|
||||||
Context context,
|
Context context,
|
||||||
|
long uid,
|
||||||
|
long userId,
|
||||||
|
String key,
|
||||||
|
boolean isHidden,
|
||||||
|
int componentId,
|
||||||
|
String legacyPackageName,
|
||||||
|
String legacyLabel,
|
||||||
|
int consumerType,
|
||||||
long foregroundUsageTimeInMs,
|
long foregroundUsageTimeInMs,
|
||||||
long backgroundUsageTimeInMs,
|
long backgroundUsageTimeInMs,
|
||||||
long screenOnTimeInMs,
|
long screenOnTimeInMs,
|
||||||
@@ -90,21 +113,36 @@ public class BatteryDiffEntry {
|
|||||||
double foregroundUsageConsumePower,
|
double foregroundUsageConsumePower,
|
||||||
double foregroundServiceUsageConsumePower,
|
double foregroundServiceUsageConsumePower,
|
||||||
double backgroundUsageConsumePower,
|
double backgroundUsageConsumePower,
|
||||||
double cachedUsageConsumePower,
|
double cachedUsageConsumePower) {
|
||||||
BatteryHistEntry batteryHistEntry) {
|
|
||||||
mContext = context;
|
mContext = context;
|
||||||
|
mUid = uid;
|
||||||
|
mUserId = userId;
|
||||||
|
mKey = key;
|
||||||
|
mIsHidden = isHidden;
|
||||||
|
mComponentId = componentId;
|
||||||
|
mLegacyPackageName = legacyPackageName;
|
||||||
|
mLegacyLabel = legacyLabel;
|
||||||
|
mConsumerType = consumerType;
|
||||||
|
mForegroundUsageTimeInMs = foregroundUsageTimeInMs;
|
||||||
|
mBackgroundUsageTimeInMs = backgroundUsageTimeInMs;
|
||||||
|
mScreenOnTimeInMs = screenOnTimeInMs;
|
||||||
mConsumePower = consumePower;
|
mConsumePower = consumePower;
|
||||||
mForegroundUsageConsumePower = foregroundUsageConsumePower;
|
mForegroundUsageConsumePower = foregroundUsageConsumePower;
|
||||||
mForegroundServiceUsageConsumePower = foregroundServiceUsageConsumePower;
|
mForegroundServiceUsageConsumePower = foregroundServiceUsageConsumePower;
|
||||||
mBackgroundUsageConsumePower = backgroundUsageConsumePower;
|
mBackgroundUsageConsumePower = backgroundUsageConsumePower;
|
||||||
mCachedUsageConsumePower = cachedUsageConsumePower;
|
mCachedUsageConsumePower = cachedUsageConsumePower;
|
||||||
mForegroundUsageTimeInMs = foregroundUsageTimeInMs;
|
|
||||||
mBackgroundUsageTimeInMs = backgroundUsageTimeInMs;
|
|
||||||
mScreenOnTimeInMs = screenOnTimeInMs;
|
|
||||||
mBatteryHistEntry = batteryHistEntry;
|
|
||||||
mUserManager = context.getSystemService(UserManager.class);
|
mUserManager = context.getSystemService(UserManager.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public BatteryDiffEntry(Context context, String key, String legacyLabel, int consumerType) {
|
||||||
|
this(context, /*uid=*/ 0, /*userId=*/ 0, key, /*isHidden=*/ false, /*componentId=*/ -1,
|
||||||
|
/*legacyPackageName=*/ null, legacyLabel, consumerType,
|
||||||
|
/*foregroundUsageTimeInMs=*/ 0, /*backgroundUsageTimeInMs=*/ 0,
|
||||||
|
/*screenOnTimeInMs=*/ 0, /*consumePower=*/ 0, /*foregroundUsageConsumePower=*/ 0,
|
||||||
|
/*foregroundServiceUsageConsumePower=*/ 0, /*backgroundUsageConsumePower=*/ 0,
|
||||||
|
/*cachedUsageConsumePower=*/ 0);
|
||||||
|
}
|
||||||
|
|
||||||
/** Sets the total consumed power in a specific time slot. */
|
/** Sets the total consumed power in a specific time slot. */
|
||||||
public void setTotalConsumePower(double totalConsumePower) {
|
public void setTotalConsumePower(double totalConsumePower) {
|
||||||
mTotalConsumePower = totalConsumePower;
|
mTotalConsumePower = totalConsumePower;
|
||||||
@@ -135,13 +173,22 @@ public class BatteryDiffEntry {
|
|||||||
|
|
||||||
/** Gets the key for sorting */
|
/** Gets the key for sorting */
|
||||||
public double getSortingKey() {
|
public double getSortingKey() {
|
||||||
return getPercentage() + getAdjustPercentageOffset();
|
return getKey() != null && SPECIAL_ENTRY_MAP.containsKey(getKey())
|
||||||
|
? -1 : getPercentage() + getAdjustPercentageOffset();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Clones a new instance. */
|
/** Clones a new instance. */
|
||||||
public BatteryDiffEntry clone() {
|
public BatteryDiffEntry clone() {
|
||||||
return new BatteryDiffEntry(
|
return new BatteryDiffEntry(
|
||||||
this.mContext,
|
this.mContext,
|
||||||
|
this.mUid,
|
||||||
|
this.mUserId,
|
||||||
|
this.mKey,
|
||||||
|
this.mIsHidden,
|
||||||
|
this.mComponentId,
|
||||||
|
this.mLegacyPackageName,
|
||||||
|
this.mLegacyLabel,
|
||||||
|
this.mConsumerType,
|
||||||
this.mForegroundUsageTimeInMs,
|
this.mForegroundUsageTimeInMs,
|
||||||
this.mBackgroundUsageTimeInMs,
|
this.mBackgroundUsageTimeInMs,
|
||||||
this.mScreenOnTimeInMs,
|
this.mScreenOnTimeInMs,
|
||||||
@@ -149,17 +196,14 @@ public class BatteryDiffEntry {
|
|||||||
this.mForegroundUsageConsumePower,
|
this.mForegroundUsageConsumePower,
|
||||||
this.mForegroundServiceUsageConsumePower,
|
this.mForegroundServiceUsageConsumePower,
|
||||||
this.mBackgroundUsageConsumePower,
|
this.mBackgroundUsageConsumePower,
|
||||||
this.mCachedUsageConsumePower,
|
this.mCachedUsageConsumePower);
|
||||||
this.mBatteryHistEntry /*same instance*/);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Gets the app label name for this entry. */
|
/** Gets the app label name for this entry. */
|
||||||
public String getAppLabel() {
|
public String getAppLabel() {
|
||||||
loadLabelAndIcon();
|
loadLabelAndIcon();
|
||||||
// Returns default applicationn label if we cannot find it.
|
// Returns default application label if we cannot find it.
|
||||||
return mAppLabel == null || mAppLabel.length() == 0
|
return mAppLabel == null || mAppLabel.length() == 0 ? mLegacyLabel : mAppLabel;
|
||||||
? mBatteryHistEntry.mAppLabel
|
|
||||||
: mAppLabel;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Gets the app icon {@link Drawable} for this entry. */
|
/** Gets the app icon {@link Drawable} for this entry. */
|
||||||
@@ -179,7 +223,7 @@ public class BatteryDiffEntry {
|
|||||||
/** Gets the searching package name for UID battery type. */
|
/** Gets the searching package name for UID battery type. */
|
||||||
public String getPackageName() {
|
public String getPackageName() {
|
||||||
final String packageName = mDefaultPackageName != null
|
final String packageName = mDefaultPackageName != null
|
||||||
? mDefaultPackageName : mBatteryHistEntry.mPackageName;
|
? mDefaultPackageName : mLegacyPackageName;
|
||||||
if (packageName == null) {
|
if (packageName == null) {
|
||||||
return packageName;
|
return packageName;
|
||||||
}
|
}
|
||||||
@@ -198,10 +242,10 @@ public class BatteryDiffEntry {
|
|||||||
|
|
||||||
/** Whether the current BatteryDiffEntry is system component or not. */
|
/** Whether the current BatteryDiffEntry is system component or not. */
|
||||||
public boolean isSystemEntry() {
|
public boolean isSystemEntry() {
|
||||||
if (mBatteryHistEntry.mIsHidden) {
|
if (mIsHidden) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
switch (mBatteryHistEntry.mConsumerType) {
|
switch (mConsumerType) {
|
||||||
case ConvertUtils.CONSUMER_TYPE_USER_BATTERY:
|
case ConvertUtils.CONSUMER_TYPE_USER_BATTERY:
|
||||||
case ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY:
|
case ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY:
|
||||||
return true;
|
return true;
|
||||||
@@ -236,12 +280,22 @@ public class BatteryDiffEntry {
|
|||||||
updateRestrictionFlagState();
|
updateRestrictionFlagState();
|
||||||
sValidForRestriction.put(getKey(), Boolean.valueOf(mValidForRestriction));
|
sValidForRestriction.put(getKey(), Boolean.valueOf(mValidForRestriction));
|
||||||
|
|
||||||
|
if (getKey() != null && SPECIAL_ENTRY_MAP.containsKey(getKey())) {
|
||||||
|
Pair<Integer, Integer> pair = SPECIAL_ENTRY_MAP.get(getKey());
|
||||||
|
mAppLabel = mContext.getString(pair.first);
|
||||||
|
mAppIconId = pair.second;
|
||||||
|
mAppIcon = mContext.getDrawable(mAppIconId);
|
||||||
|
sResourceCache.put(
|
||||||
|
getKey(),
|
||||||
|
new BatteryEntry.NameAndIcon(mAppLabel, mAppIcon, mAppIconId));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Loads application icon and label based on consumer type.
|
// Loads application icon and label based on consumer type.
|
||||||
switch (mBatteryHistEntry.mConsumerType) {
|
switch (mConsumerType) {
|
||||||
case ConvertUtils.CONSUMER_TYPE_USER_BATTERY:
|
case ConvertUtils.CONSUMER_TYPE_USER_BATTERY:
|
||||||
final BatteryEntry.NameAndIcon nameAndIconForUser =
|
final BatteryEntry.NameAndIcon nameAndIconForUser =
|
||||||
BatteryEntry.getNameAndIconFromUserId(
|
BatteryEntry.getNameAndIconFromUserId(mContext, (int) mUserId);
|
||||||
mContext, (int) mBatteryHistEntry.mUserId);
|
|
||||||
if (nameAndIconForUser != null) {
|
if (nameAndIconForUser != null) {
|
||||||
mAppIcon = nameAndIconForUser.mIcon;
|
mAppIcon = nameAndIconForUser.mIcon;
|
||||||
mAppLabel = nameAndIconForUser.mName;
|
mAppLabel = nameAndIconForUser.mName;
|
||||||
@@ -252,8 +306,7 @@ public class BatteryDiffEntry {
|
|||||||
break;
|
break;
|
||||||
case ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY:
|
case ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY:
|
||||||
final BatteryEntry.NameAndIcon nameAndIconForSystem =
|
final BatteryEntry.NameAndIcon nameAndIconForSystem =
|
||||||
BatteryEntry.getNameAndIconFromPowerComponent(
|
BatteryEntry.getNameAndIconFromPowerComponent(mContext, mComponentId);
|
||||||
mContext, mBatteryHistEntry.mDrainType);
|
|
||||||
if (nameAndIconForSystem != null) {
|
if (nameAndIconForSystem != null) {
|
||||||
mAppLabel = nameAndIconForSystem.mName;
|
mAppLabel = nameAndIconForSystem.mName;
|
||||||
if (nameAndIconForSystem.mIconId != 0) {
|
if (nameAndIconForSystem.mIconId != 0) {
|
||||||
@@ -283,12 +336,12 @@ public class BatteryDiffEntry {
|
|||||||
}
|
}
|
||||||
|
|
||||||
String getKey() {
|
String getKey() {
|
||||||
return mBatteryHistEntry.getKey();
|
return mKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
void updateRestrictionFlagState() {
|
void updateRestrictionFlagState() {
|
||||||
if (!mBatteryHistEntry.isAppEntry()) {
|
if (isSystemEntry()) {
|
||||||
mValidForRestriction = false;
|
mValidForRestriction = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -348,7 +401,7 @@ public class BatteryDiffEntry {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final int uid = (int) mBatteryHistEntry.mUid;
|
final int uid = (int) mUid;
|
||||||
final String[] packages = packageManager.getPackagesForUid(uid);
|
final String[] packages = packageManager.getPackagesForUid(uid);
|
||||||
// Loads special defined application label and icon if available.
|
// Loads special defined application label and icon if available.
|
||||||
if (packages == null || packages.length == 0) {
|
if (packages == null || packages.length == 0) {
|
||||||
@@ -394,8 +447,7 @@ public class BatteryDiffEntry {
|
|||||||
StringUtil.formatElapsedTime(mContext, (double) mScreenOnTimeInMs,
|
StringUtil.formatElapsedTime(mContext, (double) mScreenOnTimeInMs,
|
||||||
/*withSeconds=*/ true, /*collapseTimeUnit=*/ false)))
|
/*withSeconds=*/ true, /*collapseTimeUnit=*/ false)))
|
||||||
.append(String.format("\n\tpackage:%s|%s uid:%d userId:%d",
|
.append(String.format("\n\tpackage:%s|%s uid:%d userId:%d",
|
||||||
mBatteryHistEntry.mPackageName, getPackageName(),
|
mLegacyPackageName, getPackageName(), mUid, mUserId));
|
||||||
mBatteryHistEntry.mUid, mBatteryHistEntry.mUserId));
|
|
||||||
return builder.toString();
|
return builder.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -406,130 +458,8 @@ public class BatteryDiffEntry {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Drawable getBadgeIconForUser(Drawable icon) {
|
private Drawable getBadgeIconForUser(Drawable icon) {
|
||||||
final int userId = UserHandle.getUserId((int) mBatteryHistEntry.mUid);
|
final int userId = UserHandle.getUserId((int) mUid);
|
||||||
return userId == UserHandle.USER_OWNER ? icon :
|
return userId == UserHandle.USER_OWNER ? icon :
|
||||||
mUserManager.getBadgedIconForUser(icon, new UserHandle(userId));
|
mUserManager.getBadgedIconForUser(icon, new UserHandle(userId));
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Specific battery diff entry for system apps. */
|
|
||||||
static class SystemAppsBatteryDiffEntry extends BatteryDiffEntry {
|
|
||||||
SystemAppsBatteryDiffEntry(Context context) {
|
|
||||||
super(context,
|
|
||||||
/*foregroundUsageTimeInMs=*/ 0,
|
|
||||||
/*backgroundUsageTimeInMs=*/ 0,
|
|
||||||
/*screenOnTimeInMs=*/ 0,
|
|
||||||
/*consumePower=*/ 0,
|
|
||||||
/*foregroundUsageConsumePower=*/ 0,
|
|
||||||
/*foregroundServiceUsageConsumePower=*/ 0,
|
|
||||||
/*backgroundUsageConsumePower=*/ 0,
|
|
||||||
/*cachedUsageConsumePower=*/ 0,
|
|
||||||
new BatteryHistEntry(new ContentValues()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getKey() {
|
|
||||||
return "A|SystemApps";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getAppLabel() {
|
|
||||||
return mContext.getString(R.string.battery_usage_system_apps);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Drawable getAppIcon() {
|
|
||||||
return mContext.getDrawable(R.drawable.ic_power_system);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean validForRestriction() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isSystemEntry() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public double getSortingKey() {
|
|
||||||
// Always on the bottom of the app list.
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public BatteryDiffEntry clone() {
|
|
||||||
SystemAppsBatteryDiffEntry newEntry = new SystemAppsBatteryDiffEntry(this.mContext);
|
|
||||||
newEntry.mForegroundUsageTimeInMs = this.mForegroundUsageTimeInMs;
|
|
||||||
newEntry.mBackgroundUsageTimeInMs = this.mBackgroundUsageTimeInMs;
|
|
||||||
newEntry.mScreenOnTimeInMs = this.mScreenOnTimeInMs;
|
|
||||||
newEntry.mConsumePower = this.mConsumePower;
|
|
||||||
newEntry.mForegroundUsageConsumePower = this.mForegroundUsageConsumePower;
|
|
||||||
newEntry.mForegroundServiceUsageConsumePower = this.mForegroundServiceUsageConsumePower;
|
|
||||||
newEntry.mBackgroundUsageConsumePower = this.mBackgroundUsageConsumePower;
|
|
||||||
newEntry.mCachedUsageConsumePower = this.mCachedUsageConsumePower;
|
|
||||||
return newEntry;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Specific battery diff entry for others. */
|
|
||||||
static class OthersBatteryDiffEntry extends BatteryDiffEntry {
|
|
||||||
OthersBatteryDiffEntry(Context context) {
|
|
||||||
super(context,
|
|
||||||
/*foregroundUsageTimeInMs=*/ 0,
|
|
||||||
/*backgroundUsageTimeInMs=*/ 0,
|
|
||||||
/*screenOnTimeInMs=*/ 0,
|
|
||||||
/*consumePower=*/ 0,
|
|
||||||
/*foregroundUsageConsumePower=*/ 0,
|
|
||||||
/*foregroundServiceUsageConsumePower=*/ 0,
|
|
||||||
/*backgroundUsageConsumePower=*/ 0,
|
|
||||||
/*cachedUsageConsumePower=*/ 0,
|
|
||||||
new BatteryHistEntry(new ContentValues()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getKey() {
|
|
||||||
return "S|Others";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getAppLabel() {
|
|
||||||
return mContext.getString(R.string.battery_usage_others);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Drawable getAppIcon() {
|
|
||||||
return mContext.getDrawable(R.drawable.ic_settings_battery_usage_others);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean validForRestriction() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isSystemEntry() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public double getSortingKey() {
|
|
||||||
// Always on the bottom of the system list.
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public BatteryDiffEntry clone() {
|
|
||||||
OthersBatteryDiffEntry newEntry = new OthersBatteryDiffEntry(this.mContext);
|
|
||||||
newEntry.mForegroundUsageTimeInMs = this.mForegroundUsageTimeInMs;
|
|
||||||
newEntry.mBackgroundUsageTimeInMs = this.mBackgroundUsageTimeInMs;
|
|
||||||
newEntry.mScreenOnTimeInMs = this.mScreenOnTimeInMs;
|
|
||||||
newEntry.mConsumePower = this.mConsumePower;
|
|
||||||
newEntry.mForegroundUsageConsumePower = this.mForegroundUsageConsumePower;
|
|
||||||
newEntry.mForegroundServiceUsageConsumePower = this.mForegroundServiceUsageConsumePower;
|
|
||||||
newEntry.mBackgroundUsageConsumePower = this.mBackgroundUsageConsumePower;
|
|
||||||
newEntry.mCachedUsageConsumePower = this.mCachedUsageConsumePower;
|
|
||||||
return newEntry;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@@ -169,21 +169,6 @@ public class BatteryHistEntry {
|
|||||||
return mIsValidEntry;
|
return mIsValidEntry;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Whether this {@link BatteryHistEntry} is user consumer or not. */
|
|
||||||
public boolean isUserEntry() {
|
|
||||||
return mConsumerType == ConvertUtils.CONSUMER_TYPE_USER_BATTERY;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Whether this {@link BatteryHistEntry} is app consumer or not. */
|
|
||||||
public boolean isAppEntry() {
|
|
||||||
return mConsumerType == ConvertUtils.CONSUMER_TYPE_UID_BATTERY;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Whether this {@link BatteryHistEntry} is system consumer or not. */
|
|
||||||
public boolean isSystemEntry() {
|
|
||||||
return mConsumerType == ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Gets an identifier to represent this {@link BatteryHistEntry}. */
|
/** Gets an identifier to represent this {@link BatteryHistEntry}. */
|
||||||
public String getKey() {
|
public String getKey() {
|
||||||
if (mKey == null) {
|
if (mKey == null) {
|
||||||
|
@@ -1,45 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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 android.content.Context;
|
|
||||||
|
|
||||||
import com.android.settingslib.utils.AsyncLoaderCompat;
|
|
||||||
|
|
||||||
import java.util.Calendar;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/** Loader that can be used to load battery history information. */
|
|
||||||
public class BatteryHistoryLoader
|
|
||||||
extends AsyncLoaderCompat<Map<Long, Map<String, BatteryHistEntry>>> {
|
|
||||||
private static final String TAG = "BatteryHistoryLoader";
|
|
||||||
|
|
||||||
private final Context mContext;
|
|
||||||
|
|
||||||
public BatteryHistoryLoader(Context context) {
|
|
||||||
super(context);
|
|
||||||
mContext = context;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onDiscardResult(Map<Long, Map<String, BatteryHistEntry>> result) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Map<Long, Map<String, BatteryHistEntry>> loadInBackground() {
|
|
||||||
return DatabaseUtils.getHistoryMapSinceLastFullCharge(mContext, Calendar.getInstance());
|
|
||||||
}
|
|
||||||
}
|
|
@@ -17,17 +17,13 @@
|
|||||||
package com.android.settings.fuelgauge.batteryusage;
|
package com.android.settings.fuelgauge.batteryusage;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.os.BatteryUsageStats;
|
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.annotation.VisibleForTesting;
|
|
||||||
import androidx.preference.Preference;
|
import androidx.preference.Preference;
|
||||||
import androidx.preference.PreferenceViewHolder;
|
import androidx.preference.PreferenceViewHolder;
|
||||||
|
|
||||||
import com.android.settings.R;
|
import com.android.settings.R;
|
||||||
import com.android.settings.fuelgauge.BatteryInfo;
|
|
||||||
import com.android.settings.fuelgauge.BatteryUtils;
|
import com.android.settings.fuelgauge.BatteryUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -36,9 +32,6 @@ import com.android.settings.fuelgauge.BatteryUtils;
|
|||||||
public class BatteryHistoryPreference extends Preference {
|
public class BatteryHistoryPreference extends Preference {
|
||||||
private static final String TAG = "BatteryHistoryPreference";
|
private static final String TAG = "BatteryHistoryPreference";
|
||||||
|
|
||||||
@VisibleForTesting
|
|
||||||
BatteryInfo mBatteryInfo;
|
|
||||||
|
|
||||||
private BatteryChartView mDailyChartView;
|
private BatteryChartView mDailyChartView;
|
||||||
private BatteryChartView mHourlyChartView;
|
private BatteryChartView mHourlyChartView;
|
||||||
private BatteryChartPreferenceController mChartPreferenceController;
|
private BatteryChartPreferenceController mChartPreferenceController;
|
||||||
@@ -49,13 +42,6 @@ public class BatteryHistoryPreference extends Preference {
|
|||||||
setSelectable(false);
|
setSelectable(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setBatteryUsageStats(@NonNull BatteryUsageStats batteryUsageStats) {
|
|
||||||
BatteryInfo.getBatteryInfo(getContext(), info -> {
|
|
||||||
mBatteryInfo = info;
|
|
||||||
notifyChanged();
|
|
||||||
}, batteryUsageStats, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
void setChartPreferenceController(BatteryChartPreferenceController controller) {
|
void setChartPreferenceController(BatteryChartPreferenceController controller) {
|
||||||
mChartPreferenceController = controller;
|
mChartPreferenceController = controller;
|
||||||
if (mDailyChartView != null && mHourlyChartView != null) {
|
if (mDailyChartView != null && mHourlyChartView != null) {
|
||||||
@@ -67,9 +53,6 @@ public class BatteryHistoryPreference extends Preference {
|
|||||||
public void onBindViewHolder(PreferenceViewHolder view) {
|
public void onBindViewHolder(PreferenceViewHolder view) {
|
||||||
super.onBindViewHolder(view);
|
super.onBindViewHolder(view);
|
||||||
final long startTime = System.currentTimeMillis();
|
final long startTime = System.currentTimeMillis();
|
||||||
if (mBatteryInfo == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
final TextView companionTextView = (TextView) view.findViewById(R.id.companion_text);
|
final TextView companionTextView = (TextView) view.findViewById(R.id.companion_text);
|
||||||
mDailyChartView = (BatteryChartView) view.findViewById(R.id.daily_battery_chart);
|
mDailyChartView = (BatteryChartView) view.findViewById(R.id.daily_battery_chart);
|
||||||
mDailyChartView.setCompanionTextView(companionTextView);
|
mDailyChartView.setCompanionTextView(companionTextView);
|
||||||
|
@@ -16,15 +16,28 @@
|
|||||||
|
|
||||||
package com.android.settings.fuelgauge.batteryusage;
|
package com.android.settings.fuelgauge.batteryusage;
|
||||||
|
|
||||||
|
import static com.android.settingslib.fuelgauge.BatteryStatus.BATTERY_LEVEL_UNKNOWN;
|
||||||
|
|
||||||
|
import android.text.format.DateUtils;
|
||||||
|
import android.util.ArrayMap;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.annotation.VisibleForTesting;
|
||||||
import androidx.core.util.Preconditions;
|
import androidx.core.util.Preconditions;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
/** Wraps the battery timestamp and level data used for battery usage chart. */
|
/** Wraps the battery timestamp and level data used for battery usage chart. */
|
||||||
public final class BatteryLevelData {
|
public final class BatteryLevelData {
|
||||||
|
private static final long MIN_SIZE = 2;
|
||||||
|
private static final long TIME_SLOT = DateUtils.HOUR_IN_MILLIS * 2;
|
||||||
|
|
||||||
/** A container for the battery timestamp and level data. */
|
/** A container for the battery timestamp and level data. */
|
||||||
public static final class PeriodBatteryLevelData {
|
public static final class PeriodBatteryLevelData {
|
||||||
// The length of mTimestamps and mLevels must be the same. mLevels[index] might be null when
|
// The length of mTimestamps and mLevels must be the same. mLevels[index] might be null when
|
||||||
@@ -33,12 +46,14 @@ public final class BatteryLevelData {
|
|||||||
private final List<Integer> mLevels;
|
private final List<Integer> mLevels;
|
||||||
|
|
||||||
public PeriodBatteryLevelData(
|
public PeriodBatteryLevelData(
|
||||||
@NonNull List<Long> timestamps, @NonNull List<Integer> levels) {
|
@NonNull Map<Long, Integer> batteryLevelMap,
|
||||||
Preconditions.checkArgument(timestamps.size() == levels.size(),
|
@NonNull List<Long> timestamps) {
|
||||||
/* errorMessage= */ "Timestamp: " + timestamps.size() + ", Level: "
|
|
||||||
+ levels.size());
|
|
||||||
mTimestamps = timestamps;
|
mTimestamps = timestamps;
|
||||||
mLevels = levels;
|
mLevels = new ArrayList<>(timestamps.size());
|
||||||
|
for (Long timestamp : timestamps) {
|
||||||
|
mLevels.add(batteryLevelMap.containsKey(timestamp)
|
||||||
|
? batteryLevelMap.get(timestamp) : BATTERY_LEVEL_UNKNOWN);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Long> getTimestamps() {
|
public List<Long> getTimestamps() {
|
||||||
@@ -68,15 +83,21 @@ public final class BatteryLevelData {
|
|||||||
// The size of hourly data must be the size of daily data - 1.
|
// The size of hourly data must be the size of daily data - 1.
|
||||||
private final List<PeriodBatteryLevelData> mHourlyBatteryLevelsPerDay;
|
private final List<PeriodBatteryLevelData> mHourlyBatteryLevelsPerDay;
|
||||||
|
|
||||||
public BatteryLevelData(
|
public BatteryLevelData(@NonNull Map<Long, Integer> batteryLevelMap) {
|
||||||
@NonNull PeriodBatteryLevelData dailyBatteryLevels,
|
final int mapSize = batteryLevelMap.size();
|
||||||
@NonNull List<PeriodBatteryLevelData> hourlyBatteryLevelsPerDay) {
|
Preconditions.checkArgument(mapSize >= MIN_SIZE, "batteryLevelMap size:" + mapSize);
|
||||||
final long dailySize = dailyBatteryLevels.getTimestamps().size();
|
|
||||||
final long hourlySize = hourlyBatteryLevelsPerDay.size();
|
final List<Long> timestampList = new ArrayList<>(batteryLevelMap.keySet());
|
||||||
Preconditions.checkArgument(hourlySize == dailySize - 1,
|
Collections.sort(timestampList);
|
||||||
/* errorMessage= */ "DailySize: " + dailySize + ", HourlySize: " + hourlySize);
|
final List<Long> dailyTimestamps = getDailyTimestamps(timestampList);
|
||||||
mDailyBatteryLevels = dailyBatteryLevels;
|
final List<List<Long>> hourlyTimestamps = getHourlyTimestamps(dailyTimestamps);
|
||||||
mHourlyBatteryLevelsPerDay = hourlyBatteryLevelsPerDay;
|
|
||||||
|
mDailyBatteryLevels = new PeriodBatteryLevelData(batteryLevelMap, dailyTimestamps);
|
||||||
|
mHourlyBatteryLevelsPerDay = new ArrayList<>(hourlyTimestamps.size());
|
||||||
|
for (List<Long> hourlyTimestampsPerDay : hourlyTimestamps) {
|
||||||
|
mHourlyBatteryLevelsPerDay.add(
|
||||||
|
new PeriodBatteryLevelData(batteryLevelMap, hourlyTimestampsPerDay));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public PeriodBatteryLevelData getDailyBatteryLevels() {
|
public PeriodBatteryLevelData getDailyBatteryLevels() {
|
||||||
@@ -94,5 +115,69 @@ public final class BatteryLevelData {
|
|||||||
Objects.toString(mDailyBatteryLevels),
|
Objects.toString(mDailyBatteryLevels),
|
||||||
Objects.toString(mHourlyBatteryLevelsPerDay));
|
Objects.toString(mHourlyBatteryLevelsPerDay));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
static BatteryLevelData combine(@Nullable BatteryLevelData existingBatteryLevelData,
|
||||||
|
List<BatteryEvent> batteryLevelRecordEvents) {
|
||||||
|
final Map<Long, Integer> batteryLevelMap = new ArrayMap<>(batteryLevelRecordEvents.size());
|
||||||
|
for (BatteryEvent event : batteryLevelRecordEvents) {
|
||||||
|
batteryLevelMap.put(event.getTimestamp(), event.getBatteryLevel());
|
||||||
|
}
|
||||||
|
if (existingBatteryLevelData != null) {
|
||||||
|
List<PeriodBatteryLevelData> multiDaysData =
|
||||||
|
existingBatteryLevelData.getHourlyBatteryLevelsPerDay();
|
||||||
|
for (int dayIndex = 0; dayIndex < multiDaysData.size(); dayIndex++) {
|
||||||
|
PeriodBatteryLevelData oneDayData = multiDaysData.get(dayIndex);
|
||||||
|
for (int hourIndex = 0; hourIndex < oneDayData.getLevels().size(); hourIndex++) {
|
||||||
|
batteryLevelMap.put(oneDayData.getTimestamps().get(hourIndex),
|
||||||
|
oneDayData.getLevels().get(hourIndex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return batteryLevelMap.size() < MIN_SIZE ? null : new BatteryLevelData(batteryLevelMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Computes expected daily timestamp slots.
|
||||||
|
*
|
||||||
|
* The valid result should be composed of 3 parts:
|
||||||
|
* 1) start timestamp
|
||||||
|
* 2) every 00:00 timestamp (default timezone) between the start and end
|
||||||
|
* 3) end timestamp
|
||||||
|
* Otherwise, returns an empty list.
|
||||||
|
*/
|
||||||
|
@VisibleForTesting
|
||||||
|
static List<Long> getDailyTimestamps(final List<Long> timestampList) {
|
||||||
|
Preconditions.checkArgument(
|
||||||
|
timestampList.size() >= MIN_SIZE, "timestampList size:" + timestampList.size());
|
||||||
|
final List<Long> dailyTimestampList = new ArrayList<>();
|
||||||
|
final long startTimestamp = timestampList.get(0);
|
||||||
|
final long endTimestamp = timestampList.get(timestampList.size() - 1);
|
||||||
|
for (long timestamp = startTimestamp; timestamp < endTimestamp;
|
||||||
|
timestamp = TimestampUtils.getNextDayTimestamp(timestamp)) {
|
||||||
|
dailyTimestampList.add(timestamp);
|
||||||
|
}
|
||||||
|
dailyTimestampList.add(endTimestamp);
|
||||||
|
return dailyTimestampList;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<List<Long>> getHourlyTimestamps(final List<Long> dailyTimestamps) {
|
||||||
|
final List<List<Long>> hourlyTimestamps = new ArrayList<>();
|
||||||
|
for (int dailyIndex = 0; dailyIndex < dailyTimestamps.size() - 1; dailyIndex++) {
|
||||||
|
final List<Long> hourlyTimestampsPerDay = new ArrayList<>();
|
||||||
|
final long startTime = dailyTimestamps.get(dailyIndex);
|
||||||
|
final long endTime = dailyTimestamps.get(dailyIndex + 1);
|
||||||
|
|
||||||
|
hourlyTimestampsPerDay.add(startTime);
|
||||||
|
for (long timestamp = TimestampUtils.getNextEvenHourTimestamp(startTime);
|
||||||
|
timestamp < endTime; timestamp += TIME_SLOT) {
|
||||||
|
hourlyTimestampsPerDay.add(timestamp);
|
||||||
|
}
|
||||||
|
hourlyTimestampsPerDay.add(endTime);
|
||||||
|
|
||||||
|
hourlyTimestamps.add(hourlyTimestampsPerDay);
|
||||||
|
}
|
||||||
|
return hourlyTimestamps;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -144,19 +144,17 @@ public class BatteryUsageBreakdownController extends BasePreferenceController
|
|||||||
}
|
}
|
||||||
final PowerGaugePreference powerPref = (PowerGaugePreference) preference;
|
final PowerGaugePreference powerPref = (PowerGaugePreference) preference;
|
||||||
final BatteryDiffEntry diffEntry = powerPref.getBatteryDiffEntry();
|
final BatteryDiffEntry diffEntry = powerPref.getBatteryDiffEntry();
|
||||||
final BatteryHistEntry histEntry = diffEntry.mBatteryHistEntry;
|
final String packageName = diffEntry.getPackageName();
|
||||||
final String packageName = histEntry.mPackageName;
|
|
||||||
final boolean isAppEntry = histEntry.isAppEntry();
|
|
||||||
mMetricsFeatureProvider.action(
|
mMetricsFeatureProvider.action(
|
||||||
/* attribution */ SettingsEnums.OPEN_BATTERY_USAGE,
|
/* attribution */ SettingsEnums.OPEN_BATTERY_USAGE,
|
||||||
/* action */ isAppEntry
|
/* action */ diffEntry.isSystemEntry()
|
||||||
? SettingsEnums.ACTION_BATTERY_USAGE_APP_ITEM
|
? SettingsEnums.ACTION_BATTERY_USAGE_SYSTEM_ITEM
|
||||||
: SettingsEnums.ACTION_BATTERY_USAGE_SYSTEM_ITEM,
|
: SettingsEnums.ACTION_BATTERY_USAGE_APP_ITEM,
|
||||||
/* pageId */ SettingsEnums.OPEN_BATTERY_USAGE,
|
/* pageId */ SettingsEnums.OPEN_BATTERY_USAGE,
|
||||||
TextUtils.isEmpty(packageName) ? PACKAGE_NAME_NONE : packageName,
|
TextUtils.isEmpty(packageName) ? PACKAGE_NAME_NONE : packageName,
|
||||||
(int) Math.round(diffEntry.getPercentage()));
|
(int) Math.round(diffEntry.getPercentage()));
|
||||||
Log.d(TAG, String.format("handleClick() label=%s key=%s package=%s",
|
Log.d(TAG, String.format("handleClick() label=%s key=%s package=%s",
|
||||||
diffEntry.getAppLabel(), histEntry.getKey(), histEntry.mPackageName));
|
diffEntry.getAppLabel(), diffEntry.getKey(), packageName));
|
||||||
AdvancedPowerUsageDetail.startBatteryDetailPage(
|
AdvancedPowerUsageDetail.startBatteryDetailPage(
|
||||||
mActivity, mFragment, diffEntry, powerPref.getPercentage(), mSlotTimestamp);
|
mActivity, mFragment, diffEntry, powerPref.getPercentage(), mSlotTimestamp);
|
||||||
return true;
|
return true;
|
||||||
|
@@ -21,7 +21,6 @@ import android.content.ContentValues;
|
|||||||
import android.content.UriMatcher;
|
import android.content.UriMatcher;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.AsyncTask;
|
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
@@ -36,12 +35,14 @@ import com.android.settings.fuelgauge.batteryusage.db.BatteryEventEntity;
|
|||||||
import com.android.settings.fuelgauge.batteryusage.db.BatteryState;
|
import com.android.settings.fuelgauge.batteryusage.db.BatteryState;
|
||||||
import com.android.settings.fuelgauge.batteryusage.db.BatteryStateDao;
|
import com.android.settings.fuelgauge.batteryusage.db.BatteryStateDao;
|
||||||
import com.android.settings.fuelgauge.batteryusage.db.BatteryStateDatabase;
|
import com.android.settings.fuelgauge.batteryusage.db.BatteryStateDatabase;
|
||||||
|
import com.android.settings.fuelgauge.batteryusage.db.BatteryUsageSlotDao;
|
||||||
|
import com.android.settings.fuelgauge.batteryusage.db.BatteryUsageSlotEntity;
|
||||||
|
|
||||||
import java.time.Clock;
|
import java.time.Clock;
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
/** {@link ContentProvider} class to fetch battery usage data. */
|
/** {@link ContentProvider} class to fetch battery usage data. */
|
||||||
public class BatteryUsageContentProvider extends ContentProvider {
|
public class BatteryUsageContentProvider extends ContentProvider {
|
||||||
@@ -55,7 +56,12 @@ public class BatteryUsageContentProvider extends ContentProvider {
|
|||||||
private static final int APP_USAGE_LATEST_TIMESTAMP_CODE = 2;
|
private static final int APP_USAGE_LATEST_TIMESTAMP_CODE = 2;
|
||||||
private static final int APP_USAGE_EVENT_CODE = 3;
|
private static final int APP_USAGE_EVENT_CODE = 3;
|
||||||
private static final int BATTERY_EVENT_CODE = 4;
|
private static final int BATTERY_EVENT_CODE = 4;
|
||||||
|
private static final int LAST_FULL_CHARGE_TIMESTAMP_CODE = 5;
|
||||||
|
private static final int BATTERY_STATE_LATEST_TIMESTAMP_CODE = 6;
|
||||||
|
private static final int BATTERY_USAGE_SLOT_CODE = 7;
|
||||||
|
|
||||||
|
private static final List<Integer> ALL_BATTERY_EVENT_TYPES =
|
||||||
|
Arrays.stream(BatteryEventType.values()).map(type -> type.getNumber()).toList();
|
||||||
private static final UriMatcher sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
|
private static final UriMatcher sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
|
||||||
|
|
||||||
static {
|
static {
|
||||||
@@ -75,12 +81,25 @@ public class BatteryUsageContentProvider extends ContentProvider {
|
|||||||
DatabaseUtils.AUTHORITY,
|
DatabaseUtils.AUTHORITY,
|
||||||
/*path=*/ DatabaseUtils.BATTERY_EVENT_TABLE,
|
/*path=*/ DatabaseUtils.BATTERY_EVENT_TABLE,
|
||||||
/*code=*/ BATTERY_EVENT_CODE);
|
/*code=*/ BATTERY_EVENT_CODE);
|
||||||
|
sUriMatcher.addURI(
|
||||||
|
DatabaseUtils.AUTHORITY,
|
||||||
|
/*path=*/ DatabaseUtils.LAST_FULL_CHARGE_TIMESTAMP_PATH,
|
||||||
|
/*code=*/ LAST_FULL_CHARGE_TIMESTAMP_CODE);
|
||||||
|
sUriMatcher.addURI(
|
||||||
|
DatabaseUtils.AUTHORITY,
|
||||||
|
/*path=*/ DatabaseUtils.BATTERY_STATE_LATEST_TIMESTAMP_PATH,
|
||||||
|
/*code=*/ BATTERY_STATE_LATEST_TIMESTAMP_CODE);
|
||||||
|
sUriMatcher.addURI(
|
||||||
|
DatabaseUtils.AUTHORITY,
|
||||||
|
/*path=*/ DatabaseUtils.BATTERY_USAGE_SLOT_TABLE,
|
||||||
|
/*code=*/ BATTERY_USAGE_SLOT_CODE);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Clock mClock;
|
private Clock mClock;
|
||||||
private BatteryStateDao mBatteryStateDao;
|
private BatteryStateDao mBatteryStateDao;
|
||||||
private AppUsageEventDao mAppUsageEventDao;
|
private AppUsageEventDao mAppUsageEventDao;
|
||||||
private BatteryEventDao mBatteryEventDao;
|
private BatteryEventDao mBatteryEventDao;
|
||||||
|
private BatteryUsageSlotDao mBatteryUsageSlotDao;
|
||||||
|
|
||||||
@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
|
@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
|
||||||
public void setClock(Clock clock) {
|
public void setClock(Clock clock) {
|
||||||
@@ -94,9 +113,11 @@ public class BatteryUsageContentProvider extends ContentProvider {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
mClock = Clock.systemUTC();
|
mClock = Clock.systemUTC();
|
||||||
mBatteryStateDao = BatteryStateDatabase.getInstance(getContext()).batteryStateDao();
|
final BatteryStateDatabase database = BatteryStateDatabase.getInstance(getContext());
|
||||||
mAppUsageEventDao = BatteryStateDatabase.getInstance(getContext()).appUsageEventDao();
|
mBatteryStateDao = database.batteryStateDao();
|
||||||
mBatteryEventDao = BatteryStateDatabase.getInstance(getContext()).batteryEventDao();
|
mAppUsageEventDao = database.appUsageEventDao();
|
||||||
|
mBatteryEventDao = database.batteryEventDao();
|
||||||
|
mBatteryUsageSlotDao = database.batteryUsageSlotDao();
|
||||||
Log.w(TAG, "create content provider from " + getCallingPackage());
|
Log.w(TAG, "create content provider from " + getCallingPackage());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -118,6 +139,12 @@ public class BatteryUsageContentProvider extends ContentProvider {
|
|||||||
return getAppUsageLatestTimestamp(uri);
|
return getAppUsageLatestTimestamp(uri);
|
||||||
case BATTERY_EVENT_CODE:
|
case BATTERY_EVENT_CODE:
|
||||||
return getBatteryEvents(uri);
|
return getBatteryEvents(uri);
|
||||||
|
case LAST_FULL_CHARGE_TIMESTAMP_CODE:
|
||||||
|
return getLastFullChargeTimestamp(uri);
|
||||||
|
case BATTERY_STATE_LATEST_TIMESTAMP_CODE:
|
||||||
|
return getBatteryStateLatestTimestamp(uri);
|
||||||
|
case BATTERY_USAGE_SLOT_CODE:
|
||||||
|
return getBatteryUsageSlots(uri);
|
||||||
default:
|
default:
|
||||||
throw new IllegalArgumentException("unknown URI: " + uri);
|
throw new IllegalArgumentException("unknown URI: " + uri);
|
||||||
}
|
}
|
||||||
@@ -132,34 +159,31 @@ public class BatteryUsageContentProvider extends ContentProvider {
|
|||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public Uri insert(@NonNull Uri uri, @Nullable ContentValues contentValues) {
|
public Uri insert(@NonNull Uri uri, @Nullable ContentValues contentValues) {
|
||||||
switch (sUriMatcher.match(uri)) {
|
try {
|
||||||
case BATTERY_STATE_CODE:
|
switch (sUriMatcher.match(uri)) {
|
||||||
try {
|
case BATTERY_STATE_CODE:
|
||||||
mBatteryStateDao.insert(BatteryState.create(contentValues));
|
mBatteryStateDao.insert(BatteryState.create(contentValues));
|
||||||
return uri;
|
break;
|
||||||
} catch (RuntimeException e) {
|
case APP_USAGE_EVENT_CODE:
|
||||||
Log.e(TAG, "insert() from:" + uri + " error:" + e);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
case APP_USAGE_EVENT_CODE:
|
|
||||||
try {
|
|
||||||
mAppUsageEventDao.insert(AppUsageEventEntity.create(contentValues));
|
mAppUsageEventDao.insert(AppUsageEventEntity.create(contentValues));
|
||||||
return uri;
|
break;
|
||||||
} catch (RuntimeException e) {
|
case BATTERY_EVENT_CODE:
|
||||||
Log.e(TAG, "insert() from:" + uri + " error:" + e);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
case BATTERY_EVENT_CODE:
|
|
||||||
try {
|
|
||||||
mBatteryEventDao.insert(BatteryEventEntity.create(contentValues));
|
mBatteryEventDao.insert(BatteryEventEntity.create(contentValues));
|
||||||
return uri;
|
break;
|
||||||
} catch (RuntimeException e) {
|
case BATTERY_USAGE_SLOT_CODE:
|
||||||
Log.e(TAG, "insert() from:" + uri + " error:" + e);
|
mBatteryUsageSlotDao.insert(BatteryUsageSlotEntity.create(contentValues));
|
||||||
return null;
|
break;
|
||||||
}
|
default:
|
||||||
default:
|
throw new IllegalArgumentException("unknown URI: " + uri);
|
||||||
throw new IllegalArgumentException("unknown URI: " + uri);
|
}
|
||||||
|
} catch (RuntimeException e) {
|
||||||
|
if (e instanceof IllegalArgumentException) {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
Log.e(TAG, "insert() from:" + uri + " error:", e);
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
return uri;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -176,21 +200,44 @@ public class BatteryUsageContentProvider extends ContentProvider {
|
|||||||
throw new UnsupportedOperationException("unsupported!");
|
throw new UnsupportedOperationException("unsupported!");
|
||||||
}
|
}
|
||||||
|
|
||||||
private Cursor getBatteryStates(Uri uri) {
|
private Cursor getLastFullChargeTimestamp(Uri uri) {
|
||||||
final long queryTimestamp = getQueryTimestamp(uri);
|
|
||||||
return getBatteryStates(uri, queryTimestamp);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Cursor getBatteryStates(Uri uri, long firstTimestamp) {
|
|
||||||
final long timestamp = mClock.millis();
|
final long timestamp = mClock.millis();
|
||||||
Cursor cursor = null;
|
Cursor cursor = null;
|
||||||
try {
|
try {
|
||||||
cursor = mBatteryStateDao.getCursorSinceLastFullCharge(firstTimestamp);
|
cursor = mBatteryEventDao.getLastFullChargeTimestamp();
|
||||||
} catch (RuntimeException e) {
|
} catch (RuntimeException e) {
|
||||||
Log.e(TAG, "query() from:" + uri + " error:" + e);
|
Log.e(TAG, "query() from:" + uri + " error:", e);
|
||||||
}
|
}
|
||||||
AsyncTask.execute(() -> BootBroadcastReceiver.invokeJobRecheck(getContext()));
|
Log.d(TAG, String.format("getLastFullChargeTimestamp() in %d/ms",
|
||||||
Log.d(TAG, "query battery states in " + (mClock.millis() - timestamp) + "/ms");
|
mClock.millis() - timestamp));
|
||||||
|
return cursor;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Cursor getBatteryStateLatestTimestamp(Uri uri) {
|
||||||
|
final long queryTimestamp = getQueryTimestamp(uri);
|
||||||
|
final long timestamp = mClock.millis();
|
||||||
|
Cursor cursor = null;
|
||||||
|
try {
|
||||||
|
cursor = mBatteryStateDao.getLatestTimestampBefore(queryTimestamp);
|
||||||
|
} catch (RuntimeException e) {
|
||||||
|
Log.e(TAG, "query() from:" + uri + " error:", e);
|
||||||
|
}
|
||||||
|
Log.d(TAG, String.format("getBatteryStateLatestTimestamp() no later than %d in %d/ms",
|
||||||
|
queryTimestamp, mClock.millis() - timestamp));
|
||||||
|
return cursor;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Cursor getBatteryStates(Uri uri) {
|
||||||
|
final long queryTimestamp = getQueryTimestamp(uri);
|
||||||
|
final long timestamp = mClock.millis();
|
||||||
|
Cursor cursor = null;
|
||||||
|
try {
|
||||||
|
cursor = mBatteryStateDao.getBatteryStatesAfter(queryTimestamp);
|
||||||
|
} catch (RuntimeException e) {
|
||||||
|
Log.e(TAG, "query() from:" + uri + " error:", e);
|
||||||
|
}
|
||||||
|
Log.d(TAG, String.format("getBatteryStates() after %d in %d/ms",
|
||||||
|
queryTimestamp, mClock.millis() - timestamp));
|
||||||
return cursor;
|
return cursor;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -205,9 +252,9 @@ public class BatteryUsageContentProvider extends ContentProvider {
|
|||||||
try {
|
try {
|
||||||
cursor = mAppUsageEventDao.getAllForUsersAfter(queryUserIds, queryTimestamp);
|
cursor = mAppUsageEventDao.getAllForUsersAfter(queryUserIds, queryTimestamp);
|
||||||
} catch (RuntimeException e) {
|
} catch (RuntimeException e) {
|
||||||
Log.e(TAG, "query() from:" + uri + " error:" + e);
|
Log.e(TAG, "query() from:" + uri + " error:", e);
|
||||||
}
|
}
|
||||||
Log.w(TAG, "query app usage events in " + (mClock.millis() - timestamp) + "/ms");
|
Log.w(TAG, "getAppUsageEvents() in " + (mClock.millis() - timestamp) + "/ms");
|
||||||
return cursor;
|
return cursor;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -221,42 +268,78 @@ public class BatteryUsageContentProvider extends ContentProvider {
|
|||||||
try {
|
try {
|
||||||
cursor = mAppUsageEventDao.getLatestTimestampOfUser(queryUserId);
|
cursor = mAppUsageEventDao.getLatestTimestampOfUser(queryUserId);
|
||||||
} catch (RuntimeException e) {
|
} catch (RuntimeException e) {
|
||||||
Log.e(TAG, "query() from:" + uri + " error:" + e);
|
Log.e(TAG, "query() from:" + uri + " error:", e);
|
||||||
}
|
}
|
||||||
Log.d(TAG, String.format("query app usage latest timestamp %d for user %d in %d/ms",
|
Log.d(TAG, String.format("getAppUsageLatestTimestamp() for user %d in %d/ms",
|
||||||
timestamp, queryUserId, (mClock.millis() - timestamp)));
|
queryUserId, (mClock.millis() - timestamp)));
|
||||||
return cursor;
|
return cursor;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Cursor getBatteryEvents(Uri uri) {
|
private Cursor getBatteryEvents(Uri uri) {
|
||||||
|
List<Integer> queryBatteryEventTypes = getQueryBatteryEventTypes(uri);
|
||||||
|
if (queryBatteryEventTypes == null || queryBatteryEventTypes.isEmpty()) {
|
||||||
|
queryBatteryEventTypes = ALL_BATTERY_EVENT_TYPES;
|
||||||
|
}
|
||||||
final long queryTimestamp = getQueryTimestamp(uri);
|
final long queryTimestamp = getQueryTimestamp(uri);
|
||||||
final long timestamp = mClock.millis();
|
final long timestamp = mClock.millis();
|
||||||
Cursor cursor = null;
|
Cursor cursor = null;
|
||||||
try {
|
try {
|
||||||
cursor = mBatteryEventDao.getAllAfter(queryTimestamp);
|
cursor = mBatteryEventDao.getAllAfter(queryTimestamp, queryBatteryEventTypes);
|
||||||
} catch (RuntimeException e) {
|
} catch (RuntimeException e) {
|
||||||
Log.e(TAG, "query() from:" + uri + " error:" + e);
|
Log.e(TAG, "query() from:" + uri + " error:", e);
|
||||||
}
|
}
|
||||||
Log.w(TAG, "query app usage events in " + (mClock.millis() - timestamp) + "/ms");
|
Log.w(TAG, "getBatteryEvents() in " + (mClock.millis() - timestamp) + "/ms");
|
||||||
return cursor;
|
return cursor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Cursor getBatteryUsageSlots(Uri uri) {
|
||||||
|
final long queryTimestamp = getQueryTimestamp(uri);
|
||||||
|
final long timestamp = mClock.millis();
|
||||||
|
Cursor cursor = null;
|
||||||
|
try {
|
||||||
|
cursor = mBatteryUsageSlotDao.getAllAfter(queryTimestamp);
|
||||||
|
} catch (RuntimeException e) {
|
||||||
|
Log.e(TAG, "query() from:" + uri + " error:", e);
|
||||||
|
}
|
||||||
|
Log.w(TAG, "getBatteryUsageSlots() in " + (mClock.millis() - timestamp) + "/ms");
|
||||||
|
return cursor;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<Integer> getQueryBatteryEventTypes(Uri uri) {
|
||||||
|
Log.d(TAG, "getQueryBatteryEventTypes from uri: " + uri);
|
||||||
|
final String batteryEventTypesParameter =
|
||||||
|
uri.getQueryParameter(DatabaseUtils.QUERY_BATTERY_EVENT_TYPE);
|
||||||
|
if (TextUtils.isEmpty(batteryEventTypesParameter)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
List<Integer> batteryEventTypes = new ArrayList<>();
|
||||||
|
for (String typeString : batteryEventTypesParameter.split(",")) {
|
||||||
|
batteryEventTypes.add(Integer.parseInt(typeString.trim()));
|
||||||
|
}
|
||||||
|
return batteryEventTypes;
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
Log.e(TAG, "invalid query value: " + batteryEventTypesParameter, e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// If URI contains query parameter QUERY_KEY_USERID, use the value directly.
|
// If URI contains query parameter QUERY_KEY_USERID, use the value directly.
|
||||||
// Otherwise, return null.
|
// Otherwise, return null.
|
||||||
private List<Long> getQueryUserIds(Uri uri) {
|
private List<Long> getQueryUserIds(Uri uri) {
|
||||||
Log.d(TAG, "getQueryUserIds from uri: " + uri);
|
Log.d(TAG, "getQueryUserIds from uri: " + uri);
|
||||||
final String value = uri.getQueryParameter(DatabaseUtils.QUERY_KEY_USERID);
|
final String userIdsParameter = uri.getQueryParameter(DatabaseUtils.QUERY_KEY_USERID);
|
||||||
if (TextUtils.isEmpty(value)) {
|
if (TextUtils.isEmpty(userIdsParameter)) {
|
||||||
Log.w(TAG, "empty query value");
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
return Arrays.asList(value.split(","))
|
List<Long> userIds = new ArrayList<>();
|
||||||
.stream()
|
for (String idString : userIdsParameter.split(",")) {
|
||||||
.map(s -> Long.parseLong(s.trim()))
|
userIds.add(Long.parseLong(idString.trim()));
|
||||||
.collect(Collectors.toList());
|
}
|
||||||
|
return userIds;
|
||||||
} catch (NumberFormatException e) {
|
} catch (NumberFormatException e) {
|
||||||
Log.e(TAG, "invalid query value: " + value, e);
|
Log.e(TAG, "invalid query value: " + userIdsParameter, e);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -16,9 +16,12 @@
|
|||||||
|
|
||||||
package com.android.settings.fuelgauge.batteryusage;
|
package com.android.settings.fuelgauge.batteryusage;
|
||||||
|
|
||||||
|
import android.app.usage.UsageEvents;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.os.AsyncTask;
|
import android.os.AsyncTask;
|
||||||
import android.os.BatteryUsageStats;
|
import android.os.BatteryUsageStats;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.os.Looper;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import androidx.annotation.VisibleForTesting;
|
import androidx.annotation.VisibleForTesting;
|
||||||
@@ -27,6 +30,7 @@ import com.android.settings.fuelgauge.BatteryUsageHistoricalLogEntry.Action;
|
|||||||
import com.android.settings.fuelgauge.batteryusage.bugreport.BatteryUsageLogUtils;
|
import com.android.settings.fuelgauge.batteryusage.bugreport.BatteryUsageLogUtils;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
/** Load battery usage data in the background. */
|
/** Load battery usage data in the background. */
|
||||||
@@ -36,6 +40,10 @@ public final class BatteryUsageDataLoader {
|
|||||||
// For testing only.
|
// For testing only.
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
static Supplier<List<BatteryEntry>> sFakeBatteryEntryListSupplier;
|
static Supplier<List<BatteryEntry>> sFakeBatteryEntryListSupplier;
|
||||||
|
@VisibleForTesting
|
||||||
|
static Supplier<Map<Long, UsageEvents>> sFakeAppUsageEventsSupplier;
|
||||||
|
@VisibleForTesting
|
||||||
|
static Supplier<List<AppUsageEvent>> sFakeUsageEventsListSupplier;
|
||||||
|
|
||||||
private BatteryUsageDataLoader() {
|
private BatteryUsageDataLoader() {
|
||||||
}
|
}
|
||||||
@@ -48,9 +56,9 @@ public final class BatteryUsageDataLoader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
static void loadUsageData(final Context context, final boolean isFullChargeStart) {
|
static void loadBatteryStatsData(final Context context, final boolean isFullChargeStart) {
|
||||||
BatteryUsageLogUtils.writeLog(context, Action.FETCH_USAGE_DATA, "");
|
BatteryUsageLogUtils.writeLog(context, Action.FETCH_USAGE_DATA, "");
|
||||||
final long start = System.currentTimeMillis();
|
final long currentTime = System.currentTimeMillis();
|
||||||
final BatteryUsageStats batteryUsageStats = DataProcessor.getBatteryUsageStats(context);
|
final BatteryUsageStats batteryUsageStats = DataProcessor.getBatteryUsageStats(context);
|
||||||
final List<BatteryEntry> batteryEntryList =
|
final List<BatteryEntry> batteryEntryList =
|
||||||
sFakeBatteryEntryListSupplier != null ? sFakeBatteryEntryListSupplier.get()
|
sFakeBatteryEntryListSupplier != null ? sFakeBatteryEntryListSupplier.get()
|
||||||
@@ -59,25 +67,81 @@ public final class BatteryUsageDataLoader {
|
|||||||
if (batteryEntryList == null || batteryEntryList.isEmpty()) {
|
if (batteryEntryList == null || batteryEntryList.isEmpty()) {
|
||||||
Log.w(TAG, "getBatteryEntryList() returns null or empty content");
|
Log.w(TAG, "getBatteryEntryList() returns null or empty content");
|
||||||
}
|
}
|
||||||
final long elapsedTime = System.currentTimeMillis() - start;
|
final long elapsedTime = System.currentTimeMillis() - currentTime;
|
||||||
Log.d(TAG, String.format("getBatteryUsageStats() in %d/ms", elapsedTime));
|
Log.d(TAG, String.format("getBatteryUsageStats() in %d/ms", elapsedTime));
|
||||||
if (isFullChargeStart) {
|
if (isFullChargeStart) {
|
||||||
DatabaseUtils.recordDateTime(
|
DatabaseUtils.recordDateTime(
|
||||||
context, DatabaseUtils.KEY_LAST_LOAD_FULL_CHARGE_TIME);
|
context, DatabaseUtils.KEY_LAST_LOAD_FULL_CHARGE_TIME);
|
||||||
|
DatabaseUtils.sendBatteryEventData(context, ConvertUtils.convertToBatteryEvent(
|
||||||
|
currentTime, BatteryEventType.FULL_CHARGED, 100));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Uploads the BatteryEntry data into database.
|
// Uploads the BatteryEntry data into database.
|
||||||
DatabaseUtils.sendBatteryEntryData(
|
DatabaseUtils.sendBatteryEntryData(
|
||||||
context, batteryEntryList, batteryUsageStats, isFullChargeStart);
|
context, currentTime, batteryEntryList, batteryUsageStats, isFullChargeStart);
|
||||||
DataProcessor.closeBatteryUsageStats(batteryUsageStats);
|
DataProcessor.closeBatteryUsageStats(batteryUsageStats);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
static void loadAppUsageData(final Context context) {
|
||||||
|
final long start = System.currentTimeMillis();
|
||||||
|
final Map<Long, UsageEvents> appUsageEvents =
|
||||||
|
sFakeAppUsageEventsSupplier != null
|
||||||
|
? sFakeAppUsageEventsSupplier.get()
|
||||||
|
: DataProcessor.getAppUsageEvents(context);
|
||||||
|
if (appUsageEvents == null) {
|
||||||
|
Log.w(TAG, "loadAppUsageData() returns null");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final List<AppUsageEvent> appUsageEventList =
|
||||||
|
sFakeUsageEventsListSupplier != null
|
||||||
|
? sFakeUsageEventsListSupplier.get()
|
||||||
|
: DataProcessor.generateAppUsageEventListFromUsageEvents(
|
||||||
|
context, appUsageEvents);
|
||||||
|
if (appUsageEventList == null || appUsageEventList.isEmpty()) {
|
||||||
|
Log.w(TAG, "loadAppUsageData() returns null or empty content");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final long elapsedTime = System.currentTimeMillis() - start;
|
||||||
|
Log.d(TAG, String.format("loadAppUsageData() size=%d in %d/ms", appUsageEventList.size(),
|
||||||
|
elapsedTime));
|
||||||
|
// Uploads the AppUsageEvent data into database.
|
||||||
|
DatabaseUtils.sendAppUsageEventData(context, appUsageEventList);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void preprocessBatteryUsageSlots(final Context context) {
|
||||||
|
final long start = System.currentTimeMillis();
|
||||||
|
final Handler handler = new Handler(Looper.getMainLooper());
|
||||||
|
final BatteryLevelData batteryLevelData = DataProcessManager.getBatteryLevelData(
|
||||||
|
context, handler, /*isFromPeriodJob=*/ true,
|
||||||
|
batteryDiffDataMap -> DatabaseUtils.sendBatteryUsageSlotData(context,
|
||||||
|
ConvertUtils.convertToBatteryUsageSlotList(batteryDiffDataMap)));
|
||||||
|
if (batteryLevelData == null) {
|
||||||
|
Log.d(TAG, "preprocessBatteryUsageSlots() no new battery usage data.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
DatabaseUtils.sendBatteryEventData(
|
||||||
|
context, ConvertUtils.convertToBatteryEventList(batteryLevelData));
|
||||||
|
Log.d(TAG, String.format(
|
||||||
|
"preprocessBatteryUsageSlots() batteryLevelData=%s in %d/ms",
|
||||||
|
batteryLevelData, System.currentTimeMillis() - start));
|
||||||
|
}
|
||||||
|
|
||||||
private static void loadUsageDataSafely(
|
private static void loadUsageDataSafely(
|
||||||
final Context context, final boolean isFullChargeStart) {
|
final Context context, final boolean isFullChargeStart) {
|
||||||
try {
|
try {
|
||||||
loadUsageData(context, isFullChargeStart);
|
final long start = System.currentTimeMillis();
|
||||||
|
loadBatteryStatsData(context, isFullChargeStart);
|
||||||
|
if (!isFullChargeStart) {
|
||||||
|
// No app usage data or battery diff data at this time.
|
||||||
|
loadAppUsageData(context);
|
||||||
|
preprocessBatteryUsageSlots(context);
|
||||||
|
}
|
||||||
|
Log.d(TAG, String.format(
|
||||||
|
"loadUsageDataSafely() in %d/ms", System.currentTimeMillis() - start));
|
||||||
} catch (RuntimeException e) {
|
} catch (RuntimeException e) {
|
||||||
Log.e(TAG, "loadUsageData:" + e);
|
Log.e(TAG, "loadUsageData:", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -33,15 +33,21 @@ import android.text.format.DateFormat;
|
|||||||
import android.util.Base64;
|
import android.util.Base64;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.VisibleForTesting;
|
import androidx.annotation.VisibleForTesting;
|
||||||
|
|
||||||
import com.android.settings.fuelgauge.BatteryUtils;
|
import com.android.settings.fuelgauge.BatteryUtils;
|
||||||
import com.android.settings.fuelgauge.batteryusage.db.AppUsageEventEntity;
|
import com.android.settings.fuelgauge.batteryusage.db.AppUsageEventEntity;
|
||||||
import com.android.settings.fuelgauge.batteryusage.db.BatteryEventEntity;
|
import com.android.settings.fuelgauge.batteryusage.db.BatteryEventEntity;
|
||||||
|
import com.android.settings.fuelgauge.batteryusage.db.BatteryUsageSlotEntity;
|
||||||
|
|
||||||
import java.lang.annotation.Retention;
|
import java.lang.annotation.Retention;
|
||||||
import java.lang.annotation.RetentionPolicy;
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.TimeZone;
|
import java.util.TimeZone;
|
||||||
|
|
||||||
/** A utility class to convert data into another types. */
|
/** A utility class to convert data into another types. */
|
||||||
@@ -75,7 +81,22 @@ public final class ConvertUtils {
|
|||||||
private ConvertUtils() {
|
private ConvertUtils() {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Converts {@link BatteryEntry} to content values */
|
/** Whether {@code consumerType} is app consumer or not. */
|
||||||
|
public static boolean isUidConsumer(final int consumerType) {
|
||||||
|
return consumerType == CONSUMER_TYPE_UID_BATTERY;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Whether {@code consumerType} is user consumer or not. */
|
||||||
|
public static boolean isUserConsumer(final int consumerType) {
|
||||||
|
return consumerType == CONSUMER_TYPE_USER_BATTERY;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Whether {@code consumerType} is system consumer or not. */
|
||||||
|
public static boolean isSystemConsumer(final int consumerType) {
|
||||||
|
return consumerType == CONSUMER_TYPE_SYSTEM_BATTERY;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Converts {@link BatteryEntry} to {@link ContentValues} */
|
||||||
public static ContentValues convertBatteryEntryToContentValues(
|
public static ContentValues convertBatteryEntryToContentValues(
|
||||||
final BatteryEntry entry,
|
final BatteryEntry entry,
|
||||||
final BatteryUsageStats batteryUsageStats,
|
final BatteryUsageStats batteryUsageStats,
|
||||||
@@ -118,7 +139,7 @@ public final class ConvertUtils {
|
|||||||
return values;
|
return values;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Converts {@link AppUsageEvent} to content values */
|
/** Converts {@link AppUsageEvent} to {@link ContentValues} */
|
||||||
public static ContentValues convertAppUsageEventToContentValues(final AppUsageEvent event) {
|
public static ContentValues convertAppUsageEventToContentValues(final AppUsageEvent event) {
|
||||||
final ContentValues values = new ContentValues();
|
final ContentValues values = new ContentValues();
|
||||||
values.put(AppUsageEventEntity.KEY_UID, event.getUid());
|
values.put(AppUsageEventEntity.KEY_UID, event.getUid());
|
||||||
@@ -131,7 +152,7 @@ public final class ConvertUtils {
|
|||||||
return values;
|
return values;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Converts {@link BatteryEvent} to content values */
|
/** Converts {@link BatteryEvent} to {@link ContentValues} */
|
||||||
public static ContentValues convertBatteryEventToContentValues(final BatteryEvent event) {
|
public static ContentValues convertBatteryEventToContentValues(final BatteryEvent event) {
|
||||||
final ContentValues values = new ContentValues();
|
final ContentValues values = new ContentValues();
|
||||||
values.put(BatteryEventEntity.KEY_TIMESTAMP, event.getTimestamp());
|
values.put(BatteryEventEntity.KEY_TIMESTAMP, event.getTimestamp());
|
||||||
@@ -140,6 +161,16 @@ public final class ConvertUtils {
|
|||||||
return values;
|
return values;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Converts {@link BatteryUsageSlot} to {@link ContentValues} */
|
||||||
|
public static ContentValues convertBatteryUsageSlotToContentValues(
|
||||||
|
final BatteryUsageSlot batteryUsageSlot) {
|
||||||
|
final ContentValues values = new ContentValues(2);
|
||||||
|
values.put(BatteryUsageSlotEntity.KEY_TIMESTAMP, batteryUsageSlot.getStartTimestamp());
|
||||||
|
values.put(BatteryUsageSlotEntity.KEY_BATTERY_USAGE_SLOT,
|
||||||
|
Base64.encodeToString(batteryUsageSlot.toByteArray(), Base64.DEFAULT));
|
||||||
|
return values;
|
||||||
|
}
|
||||||
|
|
||||||
/** Gets the encoded string from {@link BatteryInformation} instance. */
|
/** Gets the encoded string from {@link BatteryInformation} instance. */
|
||||||
public static String convertBatteryInformationToString(
|
public static String convertBatteryInformationToString(
|
||||||
final BatteryInformation batteryInformation) {
|
final BatteryInformation batteryInformation) {
|
||||||
@@ -183,7 +214,7 @@ public final class ConvertUtils {
|
|||||||
/*isFullChargeStart=*/ false));
|
/*isFullChargeStart=*/ false));
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Converts to {@link AppUsageEvent} from {@link Event} */
|
/** Converts from {@link Event} to {@link AppUsageEvent} */
|
||||||
@Nullable
|
@Nullable
|
||||||
public static AppUsageEvent convertToAppUsageEvent(
|
public static AppUsageEvent convertToAppUsageEvent(
|
||||||
Context context, IUsageStatsManager usageStatsManager, final Event event,
|
Context context, IUsageStatsManager usageStatsManager, final Event event,
|
||||||
@@ -234,8 +265,8 @@ public final class ConvertUtils {
|
|||||||
return appUsageEventBuilder.build();
|
return appUsageEventBuilder.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Converts to {@link AppUsageEvent} from {@link Cursor} */
|
/** Converts from {@link Cursor} to {@link AppUsageEvent} */
|
||||||
public static AppUsageEvent convertToAppUsageEventFromCursor(final Cursor cursor) {
|
public static AppUsageEvent convertToAppUsageEvent(final Cursor cursor) {
|
||||||
final AppUsageEvent.Builder eventBuilder = AppUsageEvent.newBuilder();
|
final AppUsageEvent.Builder eventBuilder = AppUsageEvent.newBuilder();
|
||||||
eventBuilder.setTimestamp(getLongFromCursor(cursor, AppUsageEventEntity.KEY_TIMESTAMP));
|
eventBuilder.setTimestamp(getLongFromCursor(cursor, AppUsageEventEntity.KEY_TIMESTAMP));
|
||||||
eventBuilder.setType(
|
eventBuilder.setType(
|
||||||
@@ -253,7 +284,7 @@ public final class ConvertUtils {
|
|||||||
return eventBuilder.build();
|
return eventBuilder.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Converts to {@link BatteryEvent} from {@link BatteryEventType} */
|
/** Converts from {@link BatteryEventType} to {@link BatteryEvent} */
|
||||||
public static BatteryEvent convertToBatteryEvent(
|
public static BatteryEvent convertToBatteryEvent(
|
||||||
long timestamp, BatteryEventType type, int batteryLevel) {
|
long timestamp, BatteryEventType type, int batteryLevel) {
|
||||||
final BatteryEvent.Builder eventBuilder = BatteryEvent.newBuilder();
|
final BatteryEvent.Builder eventBuilder = BatteryEvent.newBuilder();
|
||||||
@@ -263,8 +294,8 @@ public final class ConvertUtils {
|
|||||||
return eventBuilder.build();
|
return eventBuilder.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Converts to {@link BatteryEvent} from {@link Cursor} */
|
/** Converts from {@link Cursor} to {@link BatteryEvent} */
|
||||||
public static BatteryEvent convertToBatteryEventFromCursor(final Cursor cursor) {
|
public static BatteryEvent convertToBatteryEvent(final Cursor cursor) {
|
||||||
final BatteryEvent.Builder eventBuilder = BatteryEvent.newBuilder();
|
final BatteryEvent.Builder eventBuilder = BatteryEvent.newBuilder();
|
||||||
eventBuilder.setTimestamp(getLongFromCursor(cursor, BatteryEventEntity.KEY_TIMESTAMP));
|
eventBuilder.setTimestamp(getLongFromCursor(cursor, BatteryEventEntity.KEY_TIMESTAMP));
|
||||||
eventBuilder.setType(
|
eventBuilder.setType(
|
||||||
@@ -276,6 +307,42 @@ public final class ConvertUtils {
|
|||||||
return eventBuilder.build();
|
return eventBuilder.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Converts from {@link BatteryLevelData} to {@link List<BatteryEvent>} */
|
||||||
|
public static List<BatteryEvent> convertToBatteryEventList(
|
||||||
|
final BatteryLevelData batteryLevelData) {
|
||||||
|
final List<BatteryEvent> batteryEventList = new ArrayList<>();
|
||||||
|
final List<BatteryLevelData.PeriodBatteryLevelData> levelDataList =
|
||||||
|
batteryLevelData.getHourlyBatteryLevelsPerDay();
|
||||||
|
for (BatteryLevelData.PeriodBatteryLevelData oneDayData : levelDataList) {
|
||||||
|
for (int hourIndex = 0; hourIndex < oneDayData.getLevels().size() - 1; hourIndex++) {
|
||||||
|
batteryEventList.add(convertToBatteryEvent(
|
||||||
|
oneDayData.getTimestamps().get(hourIndex),
|
||||||
|
BatteryEventType.EVEN_HOUR,
|
||||||
|
oneDayData.getLevels().get(hourIndex)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return batteryEventList;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Converts from {@link Cursor} to {@link BatteryUsageSlot} */
|
||||||
|
public static BatteryUsageSlot convertToBatteryUsageSlot(final Cursor cursor) {
|
||||||
|
final BatteryUsageSlot defaultInstance = BatteryUsageSlot.getDefaultInstance();
|
||||||
|
final int columnIndex =
|
||||||
|
cursor.getColumnIndex(BatteryUsageSlotEntity.KEY_BATTERY_USAGE_SLOT);
|
||||||
|
return columnIndex < 0 ? defaultInstance : BatteryUtils.parseProtoFromString(
|
||||||
|
cursor.getString(columnIndex), defaultInstance);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Converts from {@link Map<Long, BatteryDiffData>} to {@link List<BatteryUsageSlot>} */
|
||||||
|
public static List<BatteryUsageSlot> convertToBatteryUsageSlotList(
|
||||||
|
final Map<Long, BatteryDiffData> batteryDiffDataMap) {
|
||||||
|
List<BatteryUsageSlot> batteryUsageSlotList = new ArrayList<>();
|
||||||
|
for (BatteryDiffData batteryDiffData : batteryDiffDataMap.values()) {
|
||||||
|
batteryUsageSlotList.add(convertToBatteryUsageSlot(batteryDiffData));
|
||||||
|
}
|
||||||
|
return batteryUsageSlotList;
|
||||||
|
}
|
||||||
|
|
||||||
/** Converts UTC timestamp to local time string for logging only, so use the US locale for
|
/** Converts UTC timestamp to local time string for logging only, so use the US locale for
|
||||||
* better readability in debugging. */
|
* better readability in debugging. */
|
||||||
public static String utcToLocalTimeForLogging(long timestamp) {
|
public static String utcToLocalTimeForLogging(long timestamp) {
|
||||||
@@ -396,6 +463,100 @@ public final class ConvertUtils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static BatteryUsageDiff convertToBatteryUsageDiff(BatteryDiffEntry batteryDiffEntry) {
|
||||||
|
BatteryUsageDiff.Builder builder = BatteryUsageDiff.newBuilder()
|
||||||
|
.setUid(batteryDiffEntry.mUid)
|
||||||
|
.setUserId(batteryDiffEntry.mUserId)
|
||||||
|
.setIsHidden(batteryDiffEntry.mIsHidden)
|
||||||
|
.setComponentId(batteryDiffEntry.mComponentId)
|
||||||
|
.setConsumerType(batteryDiffEntry.mConsumerType)
|
||||||
|
.setConsumePower(batteryDiffEntry.mConsumePower)
|
||||||
|
.setForegroundUsageConsumePower(batteryDiffEntry.mForegroundUsageConsumePower)
|
||||||
|
.setBackgroundUsageConsumePower(batteryDiffEntry.mBackgroundUsageConsumePower)
|
||||||
|
.setForegroundUsageTime(batteryDiffEntry.mForegroundUsageTimeInMs)
|
||||||
|
.setBackgroundUsageTime(batteryDiffEntry.mBackgroundUsageTimeInMs)
|
||||||
|
.setScreenOnTime(batteryDiffEntry.mScreenOnTimeInMs);
|
||||||
|
if (batteryDiffEntry.mKey != null) {
|
||||||
|
builder.setKey(batteryDiffEntry.mKey);
|
||||||
|
}
|
||||||
|
if (batteryDiffEntry.mLegacyPackageName != null) {
|
||||||
|
builder.setPackageName(batteryDiffEntry.mLegacyPackageName);
|
||||||
|
}
|
||||||
|
if (batteryDiffEntry.mLegacyLabel != null) {
|
||||||
|
builder.setLabel(batteryDiffEntry.mLegacyLabel);
|
||||||
|
}
|
||||||
|
return builder.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static BatteryUsageSlot convertToBatteryUsageSlot(
|
||||||
|
final BatteryDiffData batteryDiffData) {
|
||||||
|
if (batteryDiffData == null) {
|
||||||
|
return BatteryUsageSlot.getDefaultInstance();
|
||||||
|
}
|
||||||
|
final BatteryUsageSlot.Builder builder = BatteryUsageSlot.newBuilder()
|
||||||
|
.setStartTimestamp(batteryDiffData.getStartTimestamp())
|
||||||
|
.setEndTimestamp(batteryDiffData.getEndTimestamp())
|
||||||
|
.setStartBatteryLevel(batteryDiffData.getStartBatteryLevel())
|
||||||
|
.setEndBatteryLevel(batteryDiffData.getEndBatteryLevel())
|
||||||
|
.setScreenOnTime(batteryDiffData.getScreenOnTime());
|
||||||
|
for (BatteryDiffEntry batteryDiffEntry : batteryDiffData.getAppDiffEntryList()) {
|
||||||
|
builder.addAppUsage(convertToBatteryUsageDiff(batteryDiffEntry));
|
||||||
|
}
|
||||||
|
for (BatteryDiffEntry batteryDiffEntry : batteryDiffData.getSystemDiffEntryList()) {
|
||||||
|
builder.addSystemUsage(convertToBatteryUsageDiff(batteryDiffEntry));
|
||||||
|
}
|
||||||
|
return builder.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static BatteryDiffEntry convertToBatteryDiffEntry(
|
||||||
|
Context context, final BatteryUsageDiff batteryUsageDiff) {
|
||||||
|
return new BatteryDiffEntry(
|
||||||
|
context,
|
||||||
|
batteryUsageDiff.getUid(),
|
||||||
|
batteryUsageDiff.getUserId(),
|
||||||
|
batteryUsageDiff.getKey(),
|
||||||
|
batteryUsageDiff.getIsHidden(),
|
||||||
|
batteryUsageDiff.getComponentId(),
|
||||||
|
batteryUsageDiff.getPackageName(),
|
||||||
|
batteryUsageDiff.getLabel(),
|
||||||
|
batteryUsageDiff.getConsumerType(),
|
||||||
|
batteryUsageDiff.getForegroundUsageTime(),
|
||||||
|
batteryUsageDiff.getBackgroundUsageTime(),
|
||||||
|
batteryUsageDiff.getScreenOnTime(),
|
||||||
|
batteryUsageDiff.getConsumePower(),
|
||||||
|
batteryUsageDiff.getForegroundUsageConsumePower(),
|
||||||
|
/*foregroundServiceUsageConsumePower=*/ 0,
|
||||||
|
batteryUsageDiff.getBackgroundUsageConsumePower(),
|
||||||
|
/*cachedUsageConsumePower=*/ 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static BatteryDiffData convertToBatteryDiffData(
|
||||||
|
Context context,
|
||||||
|
final BatteryUsageSlot batteryUsageSlot,
|
||||||
|
@NonNull final Set<String> systemAppsPackageNames,
|
||||||
|
@NonNull final Set<Integer> systemAppsUids) {
|
||||||
|
final List<BatteryDiffEntry> appDiffEntries = new ArrayList<>();
|
||||||
|
final List<BatteryDiffEntry> systemDiffEntries = new ArrayList<>();
|
||||||
|
for (BatteryUsageDiff batteryUsageDiff : batteryUsageSlot.getAppUsageList()) {
|
||||||
|
appDiffEntries.add(convertToBatteryDiffEntry(context, batteryUsageDiff));
|
||||||
|
}
|
||||||
|
for (BatteryUsageDiff batteryUsageDiff : batteryUsageSlot.getSystemUsageList()) {
|
||||||
|
systemDiffEntries.add(convertToBatteryDiffEntry(context, batteryUsageDiff));
|
||||||
|
}
|
||||||
|
return new BatteryDiffData(
|
||||||
|
context,
|
||||||
|
batteryUsageSlot.getStartTimestamp(),
|
||||||
|
batteryUsageSlot.getEndTimestamp(),
|
||||||
|
batteryUsageSlot.getStartBatteryLevel(),
|
||||||
|
batteryUsageSlot.getEndBatteryLevel(),
|
||||||
|
batteryUsageSlot.getScreenOnTime(),
|
||||||
|
appDiffEntries,
|
||||||
|
systemDiffEntries,
|
||||||
|
systemAppsPackageNames,
|
||||||
|
systemAppsUids,
|
||||||
|
/*isAccumulated=*/ false);
|
||||||
|
}
|
||||||
|
|
||||||
private static BatteryInformation constructBatteryInformation(
|
private static BatteryInformation constructBatteryInformation(
|
||||||
final BatteryEntry entry,
|
final BatteryEntry entry,
|
||||||
final BatteryUsageStats batteryUsageStats,
|
final BatteryUsageStats batteryUsageStats,
|
||||||
|
@@ -23,6 +23,7 @@ import android.os.Handler;
|
|||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
import android.os.UserHandle;
|
import android.os.UserHandle;
|
||||||
import android.os.UserManager;
|
import android.os.UserManager;
|
||||||
|
import android.util.ArrayMap;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
@@ -33,10 +34,10 @@ import com.android.settings.Utils;
|
|||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Manages the async tasks to process battery and app usage data.
|
* Manages the async tasks to process battery and app usage data.
|
||||||
@@ -69,28 +70,37 @@ import java.util.Map;
|
|||||||
*/
|
*/
|
||||||
public class DataProcessManager {
|
public class DataProcessManager {
|
||||||
private static final String TAG = "DataProcessManager";
|
private static final String TAG = "DataProcessManager";
|
||||||
|
private static final List<BatteryEventType> POWER_CONNECTION_EVENTS =
|
||||||
|
List.of(BatteryEventType.POWER_CONNECTED, BatteryEventType.POWER_DISCONNECTED);
|
||||||
|
private static final List<BatteryEventType> BATTERY_LEVEL_RECORD_EVENTS =
|
||||||
|
List.of(BatteryEventType.FULL_CHARGED, BatteryEventType.EVEN_HOUR);
|
||||||
|
|
||||||
private final Handler mHandler;
|
// For testing only.
|
||||||
private final DataProcessor.UsageMapAsyncResponse mCallbackFunction;
|
@VisibleForTesting
|
||||||
private final List<AppUsageEvent> mAppUsageEventList = new ArrayList<>();
|
static Map<Long, Map<String, BatteryHistEntry>> sFakeBatteryHistoryMap;
|
||||||
private final List<BatteryEvent> mBatteryEventList = new ArrayList<>();
|
|
||||||
|
|
||||||
private Context mContext;
|
|
||||||
private UserManager mUserManager;
|
|
||||||
private List<BatteryLevelData.PeriodBatteryLevelData> mHourlyBatteryLevelsPerDay;
|
|
||||||
private Map<Long, Map<String, BatteryHistEntry>> mBatteryHistoryMap;
|
|
||||||
|
|
||||||
// Raw start timestamp with round to the nearest hour.
|
// Raw start timestamp with round to the nearest hour.
|
||||||
private long mRawStartTimestamp;
|
private final long mRawStartTimestamp;
|
||||||
|
private final long mLastFullChargeTimestamp;
|
||||||
|
private final Context mContext;
|
||||||
|
private final Handler mHandler;
|
||||||
|
private final UserManager mUserManager;
|
||||||
|
private final OnBatteryDiffDataMapLoadedListener mCallbackFunction;
|
||||||
|
private final List<AppUsageEvent> mAppUsageEventList = new ArrayList<>();
|
||||||
|
private final List<BatteryEvent> mBatteryEventList = new ArrayList<>();
|
||||||
|
private final List<BatteryUsageSlot> mBatteryUsageSlotList = new ArrayList<>();
|
||||||
|
private final List<BatteryLevelData.PeriodBatteryLevelData> mHourlyBatteryLevelsPerDay;
|
||||||
|
private final Map<Long, Map<String, BatteryHistEntry>> mBatteryHistoryMap;
|
||||||
|
|
||||||
private boolean mIsCurrentBatteryHistoryLoaded = false;
|
private boolean mIsCurrentBatteryHistoryLoaded = false;
|
||||||
private boolean mIsCurrentAppUsageLoaded = false;
|
private boolean mIsCurrentAppUsageLoaded = false;
|
||||||
private boolean mIsDatabaseAppUsageLoaded = false;
|
private boolean mIsDatabaseAppUsageLoaded = false;
|
||||||
private boolean mIsBatteryEventLoaded = false;
|
private boolean mIsBatteryEventLoaded = false;
|
||||||
|
private boolean mIsBatteryUsageSlotLoaded = 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 Set<String> mSystemAppsPackageNames = null;
|
||||||
private boolean mShowBatteryLevel = true;
|
private Set<Integer> mSystemAppsUids = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The indexed {@link AppUsagePeriod} list data for each corresponding time slot.
|
* The indexed {@link AppUsagePeriod} list data for each corresponding time slot.
|
||||||
@@ -100,6 +110,15 @@ public class DataProcessManager {
|
|||||||
private Map<Integer, Map<Integer, Map<Long, Map<String, List<AppUsagePeriod>>>>>
|
private Map<Integer, Map<Integer, Map<Long, Map<String, List<AppUsagePeriod>>>>>
|
||||||
mAppUsagePeriodMap;
|
mAppUsagePeriodMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A callback listener when all the data is processed.
|
||||||
|
* This happens when all the async tasks complete and generate the final callback.
|
||||||
|
*/
|
||||||
|
public interface OnBatteryDiffDataMapLoadedListener {
|
||||||
|
/** The callback function when all the data is processed. */
|
||||||
|
void onBatteryDiffDataMapLoaded(Map<Long, BatteryDiffData> batteryDiffDataMap);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor when there exists battery level data.
|
* Constructor when there exists battery level data.
|
||||||
*/
|
*/
|
||||||
@@ -107,16 +126,18 @@ public class DataProcessManager {
|
|||||||
Context context,
|
Context context,
|
||||||
Handler handler,
|
Handler handler,
|
||||||
final long rawStartTimestamp,
|
final long rawStartTimestamp,
|
||||||
@NonNull final DataProcessor.UsageMapAsyncResponse callbackFunction,
|
final long lastFullChargeTimestamp,
|
||||||
|
@NonNull final OnBatteryDiffDataMapLoadedListener 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();
|
||||||
mHandler = handler;
|
mHandler = handler;
|
||||||
mUserManager = mContext.getSystemService(UserManager.class);
|
mUserManager = mContext.getSystemService(UserManager.class);
|
||||||
|
mRawStartTimestamp = rawStartTimestamp;
|
||||||
|
mLastFullChargeTimestamp = lastFullChargeTimestamp;
|
||||||
mCallbackFunction = callbackFunction;
|
mCallbackFunction = callbackFunction;
|
||||||
mHourlyBatteryLevelsPerDay = hourlyBatteryLevelsPerDay;
|
mHourlyBatteryLevelsPerDay = hourlyBatteryLevelsPerDay;
|
||||||
mBatteryHistoryMap = batteryHistoryMap;
|
mBatteryHistoryMap = batteryHistoryMap;
|
||||||
mRawStartTimestamp = rawStartTimestamp;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -125,31 +146,49 @@ public class DataProcessManager {
|
|||||||
DataProcessManager(
|
DataProcessManager(
|
||||||
Context context,
|
Context context,
|
||||||
Handler handler,
|
Handler handler,
|
||||||
@NonNull final DataProcessor.UsageMapAsyncResponse callbackFunction) {
|
@NonNull final OnBatteryDiffDataMapLoadedListener callbackFunction) {
|
||||||
mContext = context.getApplicationContext();
|
mContext = context.getApplicationContext();
|
||||||
mHandler = handler;
|
mHandler = handler;
|
||||||
mUserManager = mContext.getSystemService(UserManager.class);
|
mUserManager = mContext.getSystemService(UserManager.class);
|
||||||
mCallbackFunction = callbackFunction;
|
mCallbackFunction = callbackFunction;
|
||||||
|
mRawStartTimestamp = 0L;
|
||||||
|
mLastFullChargeTimestamp = 0L;
|
||||||
|
mHourlyBatteryLevelsPerDay = null;
|
||||||
|
mBatteryHistoryMap = null;
|
||||||
// When there is no battery level data, don't show screen-on time and battery level chart on
|
// When there is no battery level data, don't show screen-on time and battery level chart on
|
||||||
// the UI.
|
// the UI.
|
||||||
mShowScreenOnTime = false;
|
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() {
|
||||||
|
start(/*isFromPeriodJob=*/ false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts the async tasks to load battery history data and app usage data.
|
||||||
|
*/
|
||||||
|
public void start(boolean isFromPeriodJob) {
|
||||||
// If we have battery level data, load the battery history map and app usage simultaneously.
|
// If we have battery level data, load the battery history map and app usage simultaneously.
|
||||||
if (mShowBatteryLevel) {
|
if (mHourlyBatteryLevelsPerDay != null) {
|
||||||
// Loads the latest battery history data from the service.
|
if (isFromPeriodJob) {
|
||||||
loadCurrentBatteryHistoryMap();
|
mIsCurrentBatteryHistoryLoaded = true;
|
||||||
|
mIsCurrentAppUsageLoaded = true;
|
||||||
|
mIsBatteryUsageSlotLoaded = true;
|
||||||
|
} else {
|
||||||
|
// Loads the latest battery history data from the service.
|
||||||
|
loadCurrentBatteryHistoryMap();
|
||||||
|
// Loads the latest app usage list from the service.
|
||||||
|
loadCurrentAppUsageList();
|
||||||
|
// Loads existing battery usage slots from database.
|
||||||
|
loadBatteryUsageSlotList();
|
||||||
|
}
|
||||||
// Loads app usage list from database.
|
// Loads app usage list from database.
|
||||||
loadDatabaseAppUsageList();
|
loadDatabaseAppUsageList();
|
||||||
// Loads the latest app usage list from the service.
|
|
||||||
loadCurrentAppUsageList();
|
|
||||||
// Loads the battery event list from database.
|
// Loads the battery event list from database.
|
||||||
loadBatteryEventList();
|
loadPowerConnectionBatteryEventList();
|
||||||
} else {
|
} else {
|
||||||
// If there is no battery level data, only load the battery history data from service
|
// If there is no battery level data, only load the battery history data from service
|
||||||
// and show it as the app list directly.
|
// and show it as the app list directly.
|
||||||
@@ -193,11 +232,6 @@ 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
|
||||||
@@ -323,7 +357,7 @@ public class DataProcessManager {
|
|||||||
}.execute();
|
}.execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loadBatteryEventList() {
|
private void loadPowerConnectionBatteryEventList() {
|
||||||
new AsyncTask<Void, Void, List<BatteryEvent>>() {
|
new AsyncTask<Void, Void, List<BatteryEvent>>() {
|
||||||
@Override
|
@Override
|
||||||
protected List<BatteryEvent> doInBackground(Void... voids) {
|
protected List<BatteryEvent> doInBackground(Void... voids) {
|
||||||
@@ -331,8 +365,10 @@ public class DataProcessManager {
|
|||||||
// Loads the battery event data from the database.
|
// Loads the battery event data from the database.
|
||||||
final List<BatteryEvent> batteryEventList =
|
final List<BatteryEvent> batteryEventList =
|
||||||
DatabaseUtils.getBatteryEvents(
|
DatabaseUtils.getBatteryEvents(
|
||||||
mContext, Calendar.getInstance(), mRawStartTimestamp);
|
mContext, Calendar.getInstance(), mRawStartTimestamp,
|
||||||
Log.d(TAG, String.format("execute loadBatteryEventList size=%d in %d/ms",
|
POWER_CONNECTION_EVENTS);
|
||||||
|
Log.d(TAG, String.format(
|
||||||
|
"execute loadPowerConnectionBatteryEventList size=%d in %d/ms",
|
||||||
batteryEventList.size(), (System.currentTimeMillis() - startTime)));
|
batteryEventList.size(), (System.currentTimeMillis() - startTime)));
|
||||||
return batteryEventList;
|
return batteryEventList;
|
||||||
}
|
}
|
||||||
@@ -352,29 +388,55 @@ public class DataProcessManager {
|
|||||||
}.execute();
|
}.execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loadAndApplyBatteryMapFromServiceOnly() {
|
private void loadBatteryUsageSlotList() {
|
||||||
new AsyncTask<Void, Void, Map<Integer, Map<Integer, BatteryDiffData>>>() {
|
new AsyncTask<Void, Void, List<BatteryUsageSlot>>() {
|
||||||
@Override
|
@Override
|
||||||
protected Map<Integer, Map<Integer, BatteryDiffData>> doInBackground(Void... voids) {
|
protected List<BatteryUsageSlot> doInBackground(Void... voids) {
|
||||||
final long startTime = System.currentTimeMillis();
|
final long startTime = System.currentTimeMillis();
|
||||||
final Map<Integer, Map<Integer, BatteryDiffData>> batteryUsageMap =
|
// Loads the battery usage slot data from the database.
|
||||||
DataProcessor.getBatteryUsageMapFromStatsService(mContext);
|
final List<BatteryUsageSlot> batteryUsageSlotList =
|
||||||
DataProcessor.loadLabelAndIcon(batteryUsageMap);
|
DatabaseUtils.getBatteryUsageSlots(
|
||||||
Log.d(TAG, String.format(
|
mContext, Calendar.getInstance(), mLastFullChargeTimestamp);
|
||||||
"execute loadAndApplyBatteryMapFromServiceOnly size=%d in %d/ms",
|
Log.d(TAG, String.format("execute loadBatteryUsageSlotList size=%d in %d/ms",
|
||||||
batteryUsageMap.size(), (System.currentTimeMillis() - startTime)));
|
batteryUsageSlotList.size(), (System.currentTimeMillis() - startTime)));
|
||||||
return batteryUsageMap;
|
return batteryUsageSlotList;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onPostExecute(
|
protected void onPostExecute(final List<BatteryUsageSlot> batteryUsageSlotList) {
|
||||||
final Map<Integer, Map<Integer, BatteryDiffData>> batteryUsageMap) {
|
if (batteryUsageSlotList == null || batteryUsageSlotList.isEmpty()) {
|
||||||
// Set the unused variables to null.
|
Log.d(TAG, "batteryUsageSlotList is null or empty");
|
||||||
mContext = null;
|
} else {
|
||||||
|
mBatteryUsageSlotList.clear();
|
||||||
|
mBatteryUsageSlotList.addAll(batteryUsageSlotList);
|
||||||
|
}
|
||||||
|
mIsBatteryUsageSlotLoaded = true;
|
||||||
|
tryToGenerateFinalDataAndApplyCallback();
|
||||||
|
}
|
||||||
|
}.execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void loadAndApplyBatteryMapFromServiceOnly() {
|
||||||
|
new AsyncTask<Void, Void, Map<Long, BatteryDiffData>>() {
|
||||||
|
@Override
|
||||||
|
protected Map<Long, BatteryDiffData> doInBackground(Void... voids) {
|
||||||
|
final long startTime = System.currentTimeMillis();
|
||||||
|
final Map<Long, BatteryDiffData> batteryDiffDataMap =
|
||||||
|
DataProcessor.getBatteryDiffDataMapFromStatsService(
|
||||||
|
mContext, mRawStartTimestamp, getSystemAppsPackageNames(),
|
||||||
|
getSystemAppsUids());
|
||||||
|
Log.d(TAG, String.format(
|
||||||
|
"execute loadAndApplyBatteryMapFromServiceOnly size=%d in %d/ms",
|
||||||
|
batteryDiffDataMap.size(), (System.currentTimeMillis() - startTime)));
|
||||||
|
return batteryDiffDataMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPostExecute(final Map<Long, BatteryDiffData> batteryDiffDataMap) {
|
||||||
// Post results back to main thread to refresh UI.
|
// Post results back to main thread to refresh UI.
|
||||||
if (mHandler != null && mCallbackFunction != null) {
|
if (mHandler != null && mCallbackFunction != null) {
|
||||||
mHandler.post(() -> {
|
mHandler.post(() -> {
|
||||||
mCallbackFunction.onBatteryCallbackDataLoaded(batteryUsageMap);
|
mCallbackFunction.onBatteryDiffDataMapLoaded(batteryDiffDataMap);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -406,38 +468,41 @@ public class DataProcessManager {
|
|||||||
if (!mIsCurrentBatteryHistoryLoaded
|
if (!mIsCurrentBatteryHistoryLoaded
|
||||||
|| !mIsCurrentAppUsageLoaded
|
|| !mIsCurrentAppUsageLoaded
|
||||||
|| !mIsDatabaseAppUsageLoaded
|
|| !mIsDatabaseAppUsageLoaded
|
||||||
|| !mIsBatteryEventLoaded) {
|
|| !mIsBatteryEventLoaded
|
||||||
|
|| !mIsBatteryUsageSlotLoaded) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
generateFinalDataAndApplyCallback();
|
generateFinalDataAndApplyCallback();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void generateFinalDataAndApplyCallback() {
|
private synchronized void generateFinalDataAndApplyCallback() {
|
||||||
new AsyncTask<Void, Void, Map<Integer, Map<Integer, BatteryDiffData>>>() {
|
new AsyncTask<Void, Void, Map<Long, BatteryDiffData>>() {
|
||||||
@Override
|
@Override
|
||||||
protected Map<Integer, Map<Integer, BatteryDiffData>> doInBackground(Void... voids) {
|
protected Map<Long, BatteryDiffData> doInBackground(Void... voids) {
|
||||||
final long startTime = System.currentTimeMillis();
|
final long startTime = System.currentTimeMillis();
|
||||||
final Map<Integer, Map<Integer, BatteryDiffData>> batteryUsageMap =
|
final Map<Long, BatteryDiffData> batteryDiffDataMap = new ArrayMap<>();
|
||||||
DataProcessor.getBatteryUsageMap(
|
for (BatteryUsageSlot batteryUsageSlot : mBatteryUsageSlotList) {
|
||||||
mContext, mHourlyBatteryLevelsPerDay, mBatteryHistoryMap,
|
batteryDiffDataMap.put(batteryUsageSlot.getStartTimestamp(),
|
||||||
mAppUsagePeriodMap);
|
ConvertUtils.convertToBatteryDiffData(
|
||||||
DataProcessor.loadLabelAndIcon(batteryUsageMap);
|
mContext, batteryUsageSlot, getSystemAppsPackageNames(),
|
||||||
Log.d(TAG, String.format("execute generateFinalDataAndApplyCallback in %d/ms",
|
getSystemAppsUids()));
|
||||||
(System.currentTimeMillis() - startTime)));
|
}
|
||||||
return batteryUsageMap;
|
batteryDiffDataMap.putAll(DataProcessor.getBatteryDiffDataMap(mContext,
|
||||||
|
mHourlyBatteryLevelsPerDay, mBatteryHistoryMap, mAppUsagePeriodMap,
|
||||||
|
getSystemAppsPackageNames(), getSystemAppsUids()));
|
||||||
|
|
||||||
|
Log.d(TAG, String.format(
|
||||||
|
"execute generateFinalDataAndApplyCallback size=%d in %d/ms",
|
||||||
|
batteryDiffDataMap.size(), System.currentTimeMillis() - startTime));
|
||||||
|
return batteryDiffDataMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onPostExecute(
|
protected void onPostExecute(final Map<Long, BatteryDiffData> batteryDiffDataMap) {
|
||||||
final Map<Integer, Map<Integer, BatteryDiffData>> batteryUsageMap) {
|
|
||||||
// Set the unused variables to null.
|
|
||||||
mContext = null;
|
|
||||||
mHourlyBatteryLevelsPerDay = null;
|
|
||||||
mBatteryHistoryMap = null;
|
|
||||||
// Post results back to main thread to refresh UI.
|
// Post results back to main thread to refresh UI.
|
||||||
if (mHandler != null && mCallbackFunction != null) {
|
if (mHandler != null && mCallbackFunction != null) {
|
||||||
mHandler.post(() -> {
|
mHandler.post(() -> {
|
||||||
mCallbackFunction.onBatteryCallbackDataLoaded(batteryUsageMap);
|
mCallbackFunction.onBatteryDiffDataMapLoaded(batteryDiffDataMap);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -445,7 +510,7 @@ public class DataProcessManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Whether we should load app usage data from service or database.
|
// Whether we should load app usage data from service or database.
|
||||||
private boolean shouldLoadAppUsageData() {
|
private synchronized boolean shouldLoadAppUsageData() {
|
||||||
if (!mShowScreenOnTime) {
|
if (!mShowScreenOnTime) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -480,6 +545,20 @@ public class DataProcessManager {
|
|||||||
return userHandle != null ? userHandle.getIdentifier() : Integer.MIN_VALUE;
|
return userHandle != null ? userHandle.getIdentifier() : Integer.MIN_VALUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private synchronized Set<String> getSystemAppsPackageNames() {
|
||||||
|
if (mSystemAppsPackageNames == null) {
|
||||||
|
mSystemAppsPackageNames = DataProcessor.getSystemAppsPackageNames(mContext);
|
||||||
|
}
|
||||||
|
return mSystemAppsPackageNames;
|
||||||
|
}
|
||||||
|
|
||||||
|
private synchronized Set<Integer> getSystemAppsUids() {
|
||||||
|
if (mSystemAppsUids == null) {
|
||||||
|
mSystemAppsUids = DataProcessor.getSystemAppsUids(mContext);
|
||||||
|
}
|
||||||
|
return mSystemAppsUids;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return Returns battery level data and start async task to compute battery diff usage data
|
* @return Returns battery level data and start async task to compute battery diff usage data
|
||||||
* and load app labels + icons.
|
* and load app labels + icons.
|
||||||
@@ -489,14 +568,55 @@ public class DataProcessManager {
|
|||||||
public static BatteryLevelData getBatteryLevelData(
|
public static BatteryLevelData getBatteryLevelData(
|
||||||
Context context,
|
Context context,
|
||||||
@Nullable Handler handler,
|
@Nullable Handler handler,
|
||||||
@Nullable final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap,
|
final boolean isFromPeriodJob,
|
||||||
final DataProcessor.UsageMapAsyncResponse asyncResponseDelegate) {
|
final OnBatteryDiffDataMapLoadedListener onBatteryUsageMapLoadedListener) {
|
||||||
if (batteryHistoryMap == null || batteryHistoryMap.isEmpty()) {
|
final long start = System.currentTimeMillis();
|
||||||
Log.d(TAG, "batteryHistoryMap is null in getBatteryLevelData()");
|
final long lastFullChargeTime = DatabaseUtils.getLastFullChargeTime(context);
|
||||||
new DataProcessManager(context, handler, asyncResponseDelegate).start();
|
final List<BatteryEvent> batteryLevelRecordEvents =
|
||||||
|
DatabaseUtils.getBatteryEvents(
|
||||||
|
context, Calendar.getInstance(), lastFullChargeTime,
|
||||||
|
BATTERY_LEVEL_RECORD_EVENTS);
|
||||||
|
final long startTimestamp = batteryLevelRecordEvents.isEmpty()
|
||||||
|
? lastFullChargeTime : batteryLevelRecordEvents.get(0).getTimestamp();
|
||||||
|
final BatteryLevelData batteryLevelData = getPeriodBatteryLevelData(context, handler,
|
||||||
|
startTimestamp, lastFullChargeTime, isFromPeriodJob,
|
||||||
|
onBatteryUsageMapLoadedListener);
|
||||||
|
Log.d(TAG, String.format("execute getBatteryLevelData in %d/ms,"
|
||||||
|
+ " batteryLevelRecordEvents.size=%d",
|
||||||
|
(System.currentTimeMillis() - start), batteryLevelRecordEvents.size()));
|
||||||
|
|
||||||
|
return isFromPeriodJob
|
||||||
|
? batteryLevelData
|
||||||
|
: BatteryLevelData.combine(batteryLevelData, batteryLevelRecordEvents);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static BatteryLevelData getPeriodBatteryLevelData(
|
||||||
|
Context context,
|
||||||
|
@Nullable Handler handler,
|
||||||
|
final long startTimestamp,
|
||||||
|
final long lastFullChargeTime,
|
||||||
|
final boolean isFromPeriodJob,
|
||||||
|
final OnBatteryDiffDataMapLoadedListener onBatteryDiffDataMapLoadedListener) {
|
||||||
|
final long currentTime = System.currentTimeMillis();
|
||||||
|
Log.d(TAG, String.format("getPeriodBatteryLevelData() startTimestamp=%s",
|
||||||
|
ConvertUtils.utcToLocalTimeForLogging(startTimestamp)));
|
||||||
|
if (isFromPeriodJob
|
||||||
|
&& startTimestamp >= TimestampUtils.getLastEvenHourTimestamp(currentTime)) {
|
||||||
|
// Nothing needs to be loaded for period job.
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
handler = handler != null ? handler : new Handler(Looper.getMainLooper());
|
handler = handler != null ? handler : new Handler(Looper.getMainLooper());
|
||||||
|
final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap =
|
||||||
|
sFakeBatteryHistoryMap != null ? sFakeBatteryHistoryMap
|
||||||
|
: DatabaseUtils.getHistoryMapSinceLatestRecordBeforeQueryTimestamp(context,
|
||||||
|
Calendar.getInstance(), startTimestamp, lastFullChargeTime);
|
||||||
|
if (batteryHistoryMap == null || batteryHistoryMap.isEmpty()) {
|
||||||
|
Log.d(TAG, "batteryHistoryMap is null in getPeriodBatteryLevelData()");
|
||||||
|
new DataProcessManager(context, handler, onBatteryDiffDataMapLoadedListener).start();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
// Process raw history map data into hourly timestamps.
|
// Process raw history map data into hourly timestamps.
|
||||||
final Map<Long, Map<String, BatteryHistEntry>> processedBatteryHistoryMap =
|
final Map<Long, Map<String, BatteryHistEntry>> processedBatteryHistoryMap =
|
||||||
DataProcessor.getHistoryMapWithExpectedTimestamps(context, batteryHistoryMap);
|
DataProcessor.getHistoryMapWithExpectedTimestamps(context, batteryHistoryMap);
|
||||||
@@ -505,20 +625,20 @@ public class DataProcessManager {
|
|||||||
DataProcessor.getLevelDataThroughProcessedHistoryMap(
|
DataProcessor.getLevelDataThroughProcessedHistoryMap(
|
||||||
context, processedBatteryHistoryMap);
|
context, processedBatteryHistoryMap);
|
||||||
if (batteryLevelData == null) {
|
if (batteryLevelData == null) {
|
||||||
new DataProcessManager(context, handler, asyncResponseDelegate).start();
|
new DataProcessManager(context, handler, onBatteryDiffDataMapLoadedListener).start();
|
||||||
Log.d(TAG, "getBatteryLevelData() returns null");
|
Log.d(TAG, "getBatteryLevelData() returns null");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
final long rawStartTimestamp = Collections.min(batteryHistoryMap.keySet());
|
|
||||||
// Start the async task to compute diff usage data and load labels and icons.
|
// Start the async task to compute diff usage data and load labels and icons.
|
||||||
new DataProcessManager(
|
new DataProcessManager(
|
||||||
context,
|
context,
|
||||||
handler,
|
handler,
|
||||||
rawStartTimestamp,
|
startTimestamp,
|
||||||
asyncResponseDelegate,
|
lastFullChargeTime,
|
||||||
|
onBatteryDiffDataMapLoadedListener,
|
||||||
batteryLevelData.getHourlyBatteryLevelsPerDay(),
|
batteryLevelData.getHourlyBatteryLevelsPerDay(),
|
||||||
processedBatteryHistoryMap).start();
|
processedBatteryHistoryMap).start(isFromPeriodJob);
|
||||||
|
|
||||||
return batteryLevelData;
|
return batteryLevelData;
|
||||||
}
|
}
|
||||||
|
@@ -17,6 +17,9 @@
|
|||||||
package com.android.settings.fuelgauge.batteryusage;
|
package com.android.settings.fuelgauge.batteryusage;
|
||||||
|
|
||||||
import static com.android.settings.fuelgauge.batteryusage.ConvertUtils.getEffectivePackageName;
|
import static com.android.settings.fuelgauge.batteryusage.ConvertUtils.getEffectivePackageName;
|
||||||
|
import static com.android.settings.fuelgauge.batteryusage.ConvertUtils.isSystemConsumer;
|
||||||
|
import static com.android.settings.fuelgauge.batteryusage.ConvertUtils.isUidConsumer;
|
||||||
|
import static com.android.settingslib.fuelgauge.BatteryStatus.BATTERY_LEVEL_UNKNOWN;
|
||||||
|
|
||||||
import android.app.usage.IUsageStatsManager;
|
import android.app.usage.IUsageStatsManager;
|
||||||
import android.app.usage.UsageEvents;
|
import android.app.usage.UsageEvents;
|
||||||
@@ -44,6 +47,7 @@ import android.util.ArraySet;
|
|||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.util.SparseArray;
|
import android.util.SparseArray;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
import com.android.internal.annotations.VisibleForTesting;
|
import com.android.internal.annotations.VisibleForTesting;
|
||||||
@@ -54,6 +58,8 @@ import com.android.settings.overlay.FeatureFactory;
|
|||||||
import com.android.settingslib.fuelgauge.BatteryStatus;
|
import com.android.settingslib.fuelgauge.BatteryStatus;
|
||||||
import com.android.settingslib.spaprivileged.model.app.AppListRepositoryUtil;
|
import com.android.settingslib.spaprivileged.model.app.AppListRepositoryUtil;
|
||||||
|
|
||||||
|
import com.google.common.base.Preconditions;
|
||||||
|
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
@@ -76,9 +82,7 @@ public final class DataProcessor {
|
|||||||
private static final int POWER_COMPONENT_WAKELOCK = 12;
|
private static final int POWER_COMPONENT_WAKELOCK = 12;
|
||||||
private static final int MIN_AVERAGE_POWER_THRESHOLD_MILLI_AMP = 10;
|
private static final int MIN_AVERAGE_POWER_THRESHOLD_MILLI_AMP = 10;
|
||||||
private static final int MIN_DAILY_DATA_SIZE = 2;
|
private static final int MIN_DAILY_DATA_SIZE = 2;
|
||||||
private static final int MIN_TIMESTAMP_DATA_SIZE = 2;
|
|
||||||
private static final int MAX_DIFF_SECONDS_OF_UPPER_TIMESTAMP = 5;
|
private static final int MAX_DIFF_SECONDS_OF_UPPER_TIMESTAMP = 5;
|
||||||
private static final long MIN_TIME_SLOT = DateUtils.HOUR_IN_MILLIS * 2;
|
|
||||||
private static final String MEDIASERVER_PACKAGE_NAME = "mediaserver";
|
private static final String MEDIASERVER_PACKAGE_NAME = "mediaserver";
|
||||||
private static final String ANDROID_CORE_APPS_SHARED_USER_ID = "android.uid.shared";
|
private static final String ANDROID_CORE_APPS_SHARED_USER_ID = "android.uid.shared";
|
||||||
private static final Map<String, BatteryHistEntry> EMPTY_BATTERY_MAP = new ArrayMap<>();
|
private static final Map<String, BatteryHistEntry> EMPTY_BATTERY_MAP = new ArrayMap<>();
|
||||||
@@ -157,11 +161,14 @@ public final class DataProcessor {
|
|||||||
}
|
}
|
||||||
return batteryLevelData == null
|
return batteryLevelData == null
|
||||||
? null
|
? null
|
||||||
: getBatteryUsageMap(
|
: generateBatteryUsageMap(context,
|
||||||
context,
|
getBatteryDiffDataMap(context,
|
||||||
batteryLevelData.getHourlyBatteryLevelsPerDay(),
|
batteryLevelData.getHourlyBatteryLevelsPerDay(),
|
||||||
processedBatteryHistoryMap,
|
processedBatteryHistoryMap,
|
||||||
/*appUsagePeriodMap=*/ null);
|
/*appUsagePeriodMap=*/ null,
|
||||||
|
getSystemAppsPackageNames(context),
|
||||||
|
getSystemAppsUids(context)),
|
||||||
|
batteryLevelData);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -261,7 +268,7 @@ public final class DataProcessor {
|
|||||||
* </ul>
|
* </ul>
|
||||||
*
|
*
|
||||||
* <p>The structure is consistent with the battery usage map returned by
|
* <p>The structure is consistent with the battery usage map returned by
|
||||||
* {@code getBatteryUsageMap}.</p>
|
* {@code generateBatteryUsageMap}.</p>
|
||||||
*
|
*
|
||||||
* <p>{@code Long} stands for the userId.</p>
|
* <p>{@code Long} stands for the userId.</p>
|
||||||
* <p>{@code String} stands for the packageName.</p>
|
* <p>{@code String} stands for the packageName.</p>
|
||||||
@@ -403,8 +410,8 @@ public final class DataProcessor {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @return Returns the processed history map which has interpolated to every hour data.
|
* @return Returns the processed history map which has interpolated to every hour data.
|
||||||
* The start and end timestamp must be the even hours.
|
* The start timestamp is the first timestamp in batteryHistoryMap. The end timestamp is current
|
||||||
* The keys of processed history map should contain every hour between the start and end
|
* time. 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 map.
|
* timestamp. If there's no data in some key, the value will be the empty map.
|
||||||
*/
|
*/
|
||||||
static Map<Long, Map<String, BatteryHistEntry>> getHistoryMapWithExpectedTimestamps(
|
static Map<Long, Map<String, BatteryHistEntry>> getHistoryMapWithExpectedTimestamps(
|
||||||
@@ -431,28 +438,23 @@ public final class DataProcessor {
|
|||||||
static BatteryLevelData getLevelDataThroughProcessedHistoryMap(
|
static BatteryLevelData getLevelDataThroughProcessedHistoryMap(
|
||||||
Context context,
|
Context context,
|
||||||
final Map<Long, Map<String, BatteryHistEntry>> processedBatteryHistoryMap) {
|
final Map<Long, Map<String, BatteryHistEntry>> processedBatteryHistoryMap) {
|
||||||
final List<Long> timestampList = new ArrayList<>(processedBatteryHistoryMap.keySet());
|
|
||||||
Collections.sort(timestampList);
|
|
||||||
final List<Long> dailyTimestamps = getDailyTimestamps(timestampList);
|
|
||||||
// There should be at least the start and end timestamps. Otherwise, return null to not show
|
// There should be at least the start and end timestamps. Otherwise, return null to not show
|
||||||
// data in usage chart.
|
// data in usage chart.
|
||||||
if (dailyTimestamps.size() < MIN_DAILY_DATA_SIZE) {
|
if (processedBatteryHistoryMap.size() < MIN_DAILY_DATA_SIZE) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
Map<Long, Integer> batteryLevelMap = new ArrayMap<>();
|
||||||
final List<List<Long>> hourlyTimestamps = getHourlyTimestamps(dailyTimestamps);
|
for (Long timestamp : processedBatteryHistoryMap.keySet()) {
|
||||||
final BatteryLevelData.PeriodBatteryLevelData dailyLevelData =
|
batteryLevelMap.put(
|
||||||
getPeriodBatteryLevelData(context, processedBatteryHistoryMap, dailyTimestamps);
|
timestamp, getLevel(context, processedBatteryHistoryMap, timestamp));
|
||||||
final List<BatteryLevelData.PeriodBatteryLevelData> hourlyLevelData =
|
}
|
||||||
getHourlyPeriodBatteryLevelData(
|
return new BatteryLevelData(batteryLevelMap);
|
||||||
context, processedBatteryHistoryMap, hourlyTimestamps);
|
|
||||||
return new BatteryLevelData(dailyLevelData, hourlyLevelData);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Computes expected timestamp slots. The start timestamp is the last full charge time.
|
* Computes expected timestamp slots. The start timestamp is the first timestamp in
|
||||||
* The end timestamp is current time. The middle timestamps are the sharp hour timestamps
|
* rawTimestampList. The end timestamp is current time. The middle timestamps are the sharp hour
|
||||||
* between the start and end timestamps.
|
* timestamps between the start and end timestamps.
|
||||||
*/
|
*/
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
static List<Long> getTimestampSlots(final List<Long> rawTimestampList, final long currentTime) {
|
static List<Long> getTimestampSlots(final List<Long> rawTimestampList, final long currentTime) {
|
||||||
@@ -475,56 +477,6 @@ public final class DataProcessor {
|
|||||||
return timestampSlots;
|
return timestampSlots;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Computes expected daily timestamp slots.
|
|
||||||
*
|
|
||||||
* The valid result should be composed of 3 parts:
|
|
||||||
* 1) start timestamp
|
|
||||||
* 2) every 00:00 timestamp (default timezone) between the start and end
|
|
||||||
* 3) end timestamp
|
|
||||||
* Otherwise, returns an empty list.
|
|
||||||
*/
|
|
||||||
@VisibleForTesting
|
|
||||||
static List<Long> getDailyTimestamps(final List<Long> timestampList) {
|
|
||||||
final List<Long> dailyTimestampList = new ArrayList<>();
|
|
||||||
// If timestamp number is smaller than 2, the following computation is not necessary.
|
|
||||||
if (timestampList.size() < MIN_TIMESTAMP_DATA_SIZE) {
|
|
||||||
return dailyTimestampList;
|
|
||||||
}
|
|
||||||
final long startTime = timestampList.get(0);
|
|
||||||
final long endTime = timestampList.get(timestampList.size() - 1);
|
|
||||||
for (long timestamp = startTime; timestamp < endTime;
|
|
||||||
timestamp = TimestampUtils.getNextDayTimestamp(timestamp)) {
|
|
||||||
dailyTimestampList.add(timestamp);
|
|
||||||
}
|
|
||||||
dailyTimestampList.add(endTime);
|
|
||||||
return dailyTimestampList;
|
|
||||||
}
|
|
||||||
|
|
||||||
@VisibleForTesting
|
|
||||||
static List<List<Long>> getHourlyTimestamps(final List<Long> dailyTimestamps) {
|
|
||||||
final List<List<Long>> hourlyTimestamps = new ArrayList<>();
|
|
||||||
if (dailyTimestamps.size() < MIN_DAILY_DATA_SIZE) {
|
|
||||||
return hourlyTimestamps;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int dailyIndex = 0; dailyIndex < dailyTimestamps.size() - 1; dailyIndex++) {
|
|
||||||
final List<Long> hourlyTimestampsPerDay = new ArrayList<>();
|
|
||||||
final long startTime = dailyTimestamps.get(dailyIndex);
|
|
||||||
final long endTime = dailyTimestamps.get(dailyIndex + 1);
|
|
||||||
|
|
||||||
hourlyTimestampsPerDay.add(startTime);
|
|
||||||
for (long timestamp = TimestampUtils.getNextEvenHourTimestamp(startTime);
|
|
||||||
timestamp < endTime; timestamp += MIN_TIME_SLOT) {
|
|
||||||
hourlyTimestampsPerDay.add(timestamp);
|
|
||||||
}
|
|
||||||
hourlyTimestampsPerDay.add(endTime);
|
|
||||||
|
|
||||||
hourlyTimestamps.add(hourlyTimestampsPerDay);
|
|
||||||
}
|
|
||||||
return hourlyTimestamps;
|
|
||||||
}
|
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
static boolean isFromFullCharge(@Nullable final Map<String, BatteryHistEntry> entryList) {
|
static boolean isFromFullCharge(@Nullable final Map<String, BatteryHistEntry> entryList) {
|
||||||
if (entryList == null) {
|
if (entryList == null) {
|
||||||
@@ -560,34 +512,102 @@ public final class DataProcessor {
|
|||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Map<Long, BatteryDiffData> getBatteryDiffDataMap(
|
||||||
|
Context context,
|
||||||
|
final List<BatteryLevelData.PeriodBatteryLevelData> hourlyBatteryLevelsPerDay,
|
||||||
|
final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap,
|
||||||
|
final Map<Integer, Map<Integer, Map<Long, Map<String, List<AppUsagePeriod>>>>>
|
||||||
|
appUsagePeriodMap,
|
||||||
|
final @NonNull Set<String> systemAppsPackageNames,
|
||||||
|
final @NonNull Set<Integer> systemAppsUids) {
|
||||||
|
final Map<Long, BatteryDiffData> batteryDiffDataMap = new ArrayMap<>();
|
||||||
|
final int currentUserId = context.getUserId();
|
||||||
|
final UserHandle userHandle =
|
||||||
|
Utils.getManagedProfile(context.getSystemService(UserManager.class));
|
||||||
|
final int workProfileUserId =
|
||||||
|
userHandle != null ? userHandle.getIdentifier() : Integer.MIN_VALUE;
|
||||||
|
// Each time slot usage diff data =
|
||||||
|
// sum(Math.abs(timestamp[i+1] data - timestamp[i] data));
|
||||||
|
// since we want to aggregate every hour usage diff data into a single time slot.
|
||||||
|
for (int dailyIndex = 0; dailyIndex < hourlyBatteryLevelsPerDay.size(); dailyIndex++) {
|
||||||
|
if (hourlyBatteryLevelsPerDay.get(dailyIndex) == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
final List<Long> hourlyTimestamps =
|
||||||
|
hourlyBatteryLevelsPerDay.get(dailyIndex).getTimestamps();
|
||||||
|
for (int hourlyIndex = 0; hourlyIndex < hourlyTimestamps.size() - 1; hourlyIndex++) {
|
||||||
|
final Long startTimestamp = hourlyTimestamps.get(hourlyIndex);
|
||||||
|
final Long endTimestamp = hourlyTimestamps.get(hourlyIndex + 1);
|
||||||
|
final int startBatteryLevel =
|
||||||
|
hourlyBatteryLevelsPerDay.get(dailyIndex).getLevels().get(hourlyIndex);
|
||||||
|
final int endBatteryLevel =
|
||||||
|
hourlyBatteryLevelsPerDay.get(dailyIndex).getLevels().get(hourlyIndex + 1);
|
||||||
|
final long slotDuration = endTimestamp - startTimestamp;
|
||||||
|
List<Map<String, BatteryHistEntry>> slotBatteryHistoryList = new ArrayList<>();
|
||||||
|
slotBatteryHistoryList.add(
|
||||||
|
batteryHistoryMap.getOrDefault(startTimestamp, EMPTY_BATTERY_MAP));
|
||||||
|
for (Long timestamp = TimestampUtils.getNextHourTimestamp(startTimestamp);
|
||||||
|
timestamp < endTimestamp; timestamp += DateUtils.HOUR_IN_MILLIS) {
|
||||||
|
slotBatteryHistoryList.add(
|
||||||
|
batteryHistoryMap.getOrDefault(timestamp, EMPTY_BATTERY_MAP));
|
||||||
|
}
|
||||||
|
slotBatteryHistoryList.add(
|
||||||
|
batteryHistoryMap.getOrDefault(endTimestamp, EMPTY_BATTERY_MAP));
|
||||||
|
|
||||||
|
final BatteryDiffData hourlyBatteryDiffData =
|
||||||
|
insertHourlyUsageDiffDataPerSlot(
|
||||||
|
context,
|
||||||
|
startTimestamp,
|
||||||
|
endTimestamp,
|
||||||
|
startBatteryLevel,
|
||||||
|
endBatteryLevel,
|
||||||
|
currentUserId,
|
||||||
|
workProfileUserId,
|
||||||
|
slotDuration,
|
||||||
|
systemAppsPackageNames,
|
||||||
|
systemAppsUids,
|
||||||
|
appUsagePeriodMap == null
|
||||||
|
|| appUsagePeriodMap.get(dailyIndex) == null
|
||||||
|
? null
|
||||||
|
: appUsagePeriodMap.get(dailyIndex).get(hourlyIndex),
|
||||||
|
slotBatteryHistoryList);
|
||||||
|
batteryDiffDataMap.put(startTimestamp, hourlyBatteryDiffData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return batteryDiffDataMap;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return Returns the indexed battery usage data for each corresponding time slot.
|
* @return Returns the indexed battery usage data for each corresponding time slot.
|
||||||
*
|
*
|
||||||
* <p>There could be 2 cases of the returned value:</p>
|
* <p>There could be 2 cases of the returned value:</p>
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li>null: empty or invalid data.</li>
|
* <li> null: empty or invalid data.</li>
|
||||||
* <li>non-null: must be a 2d map and composed by 3 parts:</li>
|
* <li> 1 part: if batteryLevelData is null.</li>
|
||||||
|
* <p> [SELECTED_INDEX_ALL][SELECTED_INDEX_ALL]</p>
|
||||||
|
* <li> 3 parts: if batteryLevelData is not null.</li>
|
||||||
* <p> 1 - [SELECTED_INDEX_ALL][SELECTED_INDEX_ALL]</p>
|
* <p> 1 - [SELECTED_INDEX_ALL][SELECTED_INDEX_ALL]</p>
|
||||||
* <p> 2 - [0][SELECTED_INDEX_ALL] ~ [maxDailyIndex][SELECTED_INDEX_ALL]</p>
|
* <p> 2 - [0][SELECTED_INDEX_ALL] ~ [maxDailyIndex][SELECTED_INDEX_ALL]</p>
|
||||||
* <p> 3 - [0][0] ~ [maxDailyIndex][maxHourlyIndex]</p>
|
* <p> 3 - [0][0] ~ [maxDailyIndex][maxHourlyIndex]</p>
|
||||||
* </ul>
|
* </ul>
|
||||||
*/
|
*/
|
||||||
@Nullable
|
static Map<Integer, Map<Integer, BatteryDiffData>> generateBatteryUsageMap(
|
||||||
static Map<Integer, Map<Integer, BatteryDiffData>> getBatteryUsageMap(
|
|
||||||
final Context context,
|
final Context context,
|
||||||
final List<BatteryLevelData.PeriodBatteryLevelData> hourlyBatteryLevelsPerDay,
|
final Map<Long, BatteryDiffData> batteryDiffDataMap,
|
||||||
final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap,
|
final @Nullable BatteryLevelData batteryLevelData) {
|
||||||
final Map<Integer, Map<Integer, Map<Long, Map<String, List<AppUsagePeriod>>>>>
|
|
||||||
appUsagePeriodMap) {
|
|
||||||
if (batteryHistoryMap.isEmpty()) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
final Map<Integer, Map<Integer, BatteryDiffData>> resultMap = new ArrayMap<>();
|
final Map<Integer, Map<Integer, BatteryDiffData>> resultMap = new ArrayMap<>();
|
||||||
final Set<String> systemAppsPackageNames = getSystemAppsPackageNames(context);
|
if (batteryLevelData == null) {
|
||||||
final Set<Integer> systemAppsUids = getSystemAppsUids(context);
|
Preconditions.checkArgument(batteryDiffDataMap.size() == 1);
|
||||||
|
BatteryDiffData batteryDiffData = batteryDiffDataMap.values().stream().toList().get(0);
|
||||||
|
final Map<Integer, BatteryDiffData> allUsageMap = new ArrayMap<>();
|
||||||
|
allUsageMap.put(SELECTED_INDEX_ALL, batteryDiffData);
|
||||||
|
resultMap.put(SELECTED_INDEX_ALL, allUsageMap);
|
||||||
|
return resultMap;
|
||||||
|
}
|
||||||
|
List<BatteryLevelData.PeriodBatteryLevelData> hourlyBatteryLevelsPerDay =
|
||||||
|
batteryLevelData.getHourlyBatteryLevelsPerDay();
|
||||||
// Insert diff data from [0][0] to [maxDailyIndex][maxHourlyIndex].
|
// Insert diff data from [0][0] to [maxDailyIndex][maxHourlyIndex].
|
||||||
insertHourlyUsageDiffData(context, systemAppsPackageNames, systemAppsUids,
|
insertHourlyUsageDiffData(hourlyBatteryLevelsPerDay, batteryDiffDataMap, resultMap);
|
||||||
hourlyBatteryLevelsPerDay, batteryHistoryMap, appUsagePeriodMap, resultMap);
|
|
||||||
// Insert diff data from [0][SELECTED_INDEX_ALL] to [maxDailyIndex][SELECTED_INDEX_ALL].
|
// Insert diff data from [0][SELECTED_INDEX_ALL] to [maxDailyIndex][SELECTED_INDEX_ALL].
|
||||||
insertDailyUsageDiffData(context, hourlyBatteryLevelsPerDay, resultMap);
|
insertDailyUsageDiffData(context, hourlyBatteryLevelsPerDay, resultMap);
|
||||||
// Insert diff data [SELECTED_INDEX_ALL][SELECTED_INDEX_ALL].
|
// Insert diff data [SELECTED_INDEX_ALL][SELECTED_INDEX_ALL].
|
||||||
@@ -602,7 +622,10 @@ public final class DataProcessor {
|
|||||||
@Nullable
|
@Nullable
|
||||||
static BatteryDiffData generateBatteryDiffData(
|
static BatteryDiffData generateBatteryDiffData(
|
||||||
final Context context,
|
final Context context,
|
||||||
final List<BatteryHistEntry> batteryHistEntryList) {
|
final long startTimestamp,
|
||||||
|
final List<BatteryHistEntry> batteryHistEntryList,
|
||||||
|
final @NonNull Set<String> systemAppsPackageNames,
|
||||||
|
final @NonNull Set<Integer> systemAppsUids) {
|
||||||
if (batteryHistEntryList == null || batteryHistEntryList.isEmpty()) {
|
if (batteryHistEntryList == null || batteryHistEntryList.isEmpty()) {
|
||||||
Log.w(TAG, "batteryHistEntryList is null or empty in generateBatteryDiffData()");
|
Log.w(TAG, "batteryHistEntryList is null or empty in generateBatteryDiffData()");
|
||||||
return null;
|
return null;
|
||||||
@@ -624,6 +647,14 @@ public final class DataProcessor {
|
|||||||
} else {
|
} else {
|
||||||
final BatteryDiffEntry currentBatteryDiffEntry = new BatteryDiffEntry(
|
final BatteryDiffEntry currentBatteryDiffEntry = new BatteryDiffEntry(
|
||||||
context,
|
context,
|
||||||
|
entry.mUid,
|
||||||
|
entry.mUserId,
|
||||||
|
entry.getKey(),
|
||||||
|
entry.mIsHidden,
|
||||||
|
entry.mDrainType,
|
||||||
|
entry.mPackageName,
|
||||||
|
entry.mAppLabel,
|
||||||
|
entry.mConsumerType,
|
||||||
entry.mForegroundUsageTimeInMs,
|
entry.mForegroundUsageTimeInMs,
|
||||||
entry.mBackgroundUsageTimeInMs,
|
entry.mBackgroundUsageTimeInMs,
|
||||||
/*screenOnTimeInMs=*/ 0,
|
/*screenOnTimeInMs=*/ 0,
|
||||||
@@ -631,8 +662,7 @@ public final class DataProcessor {
|
|||||||
entry.mForegroundUsageConsumePower,
|
entry.mForegroundUsageConsumePower,
|
||||||
entry.mForegroundServiceUsageConsumePower,
|
entry.mForegroundServiceUsageConsumePower,
|
||||||
entry.mBackgroundUsageConsumePower,
|
entry.mBackgroundUsageConsumePower,
|
||||||
entry.mCachedUsageConsumePower,
|
entry.mCachedUsageConsumePower);
|
||||||
entry);
|
|
||||||
if (currentBatteryDiffEntry.isSystemEntry()) {
|
if (currentBatteryDiffEntry.isSystemEntry()) {
|
||||||
systemEntries.add(currentBatteryDiffEntry);
|
systemEntries.add(currentBatteryDiffEntry);
|
||||||
} else {
|
} else {
|
||||||
@@ -645,11 +675,10 @@ public final class DataProcessor {
|
|||||||
if (appEntries.isEmpty() && systemEntries.isEmpty()) {
|
if (appEntries.isEmpty() && systemEntries.isEmpty()) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
return new BatteryDiffData(context, startTimestamp, getCurrentTimeMillis(),
|
||||||
final Set<String> systemAppsPackageNames = getSystemAppsPackageNames(context);
|
/* startBatteryLevel =*/ 100, getCurrentLevel(context), /* screenOnTime= */ 0L,
|
||||||
final Set<Integer> systemAppsUids = getSystemAppsUids(context);
|
appEntries, systemEntries, systemAppsPackageNames, systemAppsUids,
|
||||||
return new BatteryDiffData(context, /* screenOnTime= */ 0L, appEntries, systemEntries,
|
/* isAccumulated= */ false);
|
||||||
systemAppsPackageNames, systemAppsUids, /* isAccumulated= */ false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -845,21 +874,15 @@ public final class DataProcessor {
|
|||||||
return getScreenOnTime(appUsageMap.get(userId).get(packageName));
|
return getScreenOnTime(appUsageMap.get(userId).get(packageName));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
static Map<Long, BatteryDiffData> getBatteryDiffDataMapFromStatsService(
|
||||||
* @return Returns the overall battery usage data from battery stats service directly.
|
final Context context, final long startTimestamp,
|
||||||
*
|
@NonNull final Set<String> systemAppsPackageNames,
|
||||||
* The returned value should be always a 2d map and composed by only 1 part:
|
@NonNull final Set<Integer> systemAppsUids) {
|
||||||
* - [SELECTED_INDEX_ALL][SELECTED_INDEX_ALL]
|
Map<Long, BatteryDiffData> batteryDiffDataMap = new ArrayMap<>(1);
|
||||||
*/
|
batteryDiffDataMap.put(startTimestamp, generateBatteryDiffData(
|
||||||
static Map<Integer, Map<Integer, BatteryDiffData>> getBatteryUsageMapFromStatsService(
|
context, startTimestamp, getBatteryHistListFromFromStatsService(context),
|
||||||
final Context context) {
|
systemAppsPackageNames, systemAppsUids));
|
||||||
final Map<Integer, Map<Integer, BatteryDiffData>> resultMap = new ArrayMap<>();
|
return batteryDiffDataMap;
|
||||||
final Map<Integer, BatteryDiffData> allUsageMap = new ArrayMap<>();
|
|
||||||
// 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);
|
|
||||||
return resultMap;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void loadLabelAndIcon(
|
static void loadLabelAndIcon(
|
||||||
@@ -878,6 +901,22 @@ public final class DataProcessor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Set<String> getSystemAppsPackageNames(Context context) {
|
||||||
|
return sTestSystemAppsPackageNames != null ? sTestSystemAppsPackageNames
|
||||||
|
: AppListRepositoryUtil.getSystemPackageNames(context, context.getUserId());
|
||||||
|
}
|
||||||
|
|
||||||
|
static Set<Integer> getSystemAppsUids(Context context) {
|
||||||
|
Set<Integer> result = new ArraySet<>(1);
|
||||||
|
try {
|
||||||
|
result.add(context.getPackageManager().getUidForSharedUser(
|
||||||
|
ANDROID_CORE_APPS_SHARED_USER_ID));
|
||||||
|
} catch (PackageManager.NameNotFoundException e) {
|
||||||
|
// No Android Core Apps
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates the list of {@link AppUsageEvent} within the specific time range.
|
* Generates the list of {@link AppUsageEvent} within the specific time range.
|
||||||
* The buffer is added to make sure the app usage calculation near the boundaries is correct.
|
* The buffer is added to make sure the app usage calculation near the boundaries is correct.
|
||||||
@@ -1158,28 +1197,6 @@ public final class DataProcessor {
|
|||||||
resultMap.put(currentSlot, newHistEntryMap);
|
resultMap.put(currentSlot, newHistEntryMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<BatteryLevelData.PeriodBatteryLevelData> getHourlyPeriodBatteryLevelData(
|
|
||||||
Context context,
|
|
||||||
final Map<Long, Map<String, BatteryHistEntry>> processedBatteryHistoryMap,
|
|
||||||
final List<List<Long>> timestamps) {
|
|
||||||
final List<BatteryLevelData.PeriodBatteryLevelData> levelData = new ArrayList<>();
|
|
||||||
timestamps.forEach(
|
|
||||||
timestampList -> levelData.add(
|
|
||||||
getPeriodBatteryLevelData(
|
|
||||||
context, processedBatteryHistoryMap, timestampList)));
|
|
||||||
return levelData;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static BatteryLevelData.PeriodBatteryLevelData getPeriodBatteryLevelData(
|
|
||||||
Context context,
|
|
||||||
final Map<Long, Map<String, BatteryHistEntry>> processedBatteryHistoryMap,
|
|
||||||
final List<Long> timestamps) {
|
|
||||||
final List<Integer> levels = new ArrayList<>();
|
|
||||||
timestamps.forEach(
|
|
||||||
timestamp -> levels.add(getLevel(context, processedBatteryHistoryMap, timestamp)));
|
|
||||||
return new BatteryLevelData.PeriodBatteryLevelData(timestamps, levels);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Integer getLevel(
|
private static Integer getLevel(
|
||||||
Context context,
|
Context context,
|
||||||
final Map<Long, Map<String, BatteryHistEntry>> processedBatteryHistoryMap,
|
final Map<Long, Map<String, BatteryHistEntry>> processedBatteryHistoryMap,
|
||||||
@@ -1188,13 +1205,12 @@ public final class DataProcessor {
|
|||||||
if (entryMap == null || entryMap.isEmpty()) {
|
if (entryMap == null || entryMap.isEmpty()) {
|
||||||
Log.e(TAG, "abnormal entry list in the timestamp:"
|
Log.e(TAG, "abnormal entry list in the timestamp:"
|
||||||
+ ConvertUtils.utcToLocalTimeForLogging(timestamp));
|
+ ConvertUtils.utcToLocalTimeForLogging(timestamp));
|
||||||
return null;
|
return BATTERY_LEVEL_UNKNOWN;
|
||||||
}
|
}
|
||||||
// The current time battery history hasn't been loaded yet, returns the current battery
|
// The current time battery history hasn't been loaded yet, returns the current battery
|
||||||
// level.
|
// level.
|
||||||
if (entryMap.containsKey(CURRENT_TIME_BATTERY_HISTORY_PLACEHOLDER)) {
|
if (entryMap.containsKey(CURRENT_TIME_BATTERY_HISTORY_PLACEHOLDER)) {
|
||||||
final Intent intent = BatteryUtils.getBatteryIntent(context);
|
return getCurrentLevel(context);
|
||||||
return BatteryStatus.getBatteryLevel(intent);
|
|
||||||
}
|
}
|
||||||
// Averages the battery level in each time slot to avoid corner conditions.
|
// Averages the battery level in each time slot to avoid corner conditions.
|
||||||
float batteryLevelCounter = 0;
|
float batteryLevelCounter = 0;
|
||||||
@@ -1204,20 +1220,15 @@ public final class DataProcessor {
|
|||||||
return Math.round(batteryLevelCounter / entryMap.size());
|
return Math.round(batteryLevelCounter / entryMap.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static int getCurrentLevel(Context context) {
|
||||||
|
final Intent intent = BatteryUtils.getBatteryIntent(context);
|
||||||
|
return BatteryStatus.getBatteryLevel(intent);
|
||||||
|
}
|
||||||
|
|
||||||
private static void insertHourlyUsageDiffData(
|
private static void insertHourlyUsageDiffData(
|
||||||
Context context,
|
|
||||||
final Set<String> systemAppsPackageNames,
|
|
||||||
final Set<Integer> systemAppsUids,
|
|
||||||
final List<BatteryLevelData.PeriodBatteryLevelData> hourlyBatteryLevelsPerDay,
|
final List<BatteryLevelData.PeriodBatteryLevelData> hourlyBatteryLevelsPerDay,
|
||||||
final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap,
|
final Map<Long, BatteryDiffData> batteryDiffDataMap,
|
||||||
final Map<Integer, Map<Integer, Map<Long, Map<String, List<AppUsagePeriod>>>>>
|
|
||||||
appUsagePeriodMap,
|
|
||||||
final Map<Integer, Map<Integer, BatteryDiffData>> resultMap) {
|
final Map<Integer, Map<Integer, BatteryDiffData>> resultMap) {
|
||||||
final int currentUserId = context.getUserId();
|
|
||||||
final UserHandle userHandle =
|
|
||||||
Utils.getManagedProfile(context.getSystemService(UserManager.class));
|
|
||||||
final int workProfileUserId =
|
|
||||||
userHandle != null ? userHandle.getIdentifier() : Integer.MIN_VALUE;
|
|
||||||
// Each time slot usage diff data =
|
// Each time slot usage diff data =
|
||||||
// sum(Math.abs(timestamp[i+1] data - timestamp[i] data));
|
// sum(Math.abs(timestamp[i+1] data - timestamp[i] data));
|
||||||
// since we want to aggregate every hour usage diff data into a single time slot.
|
// since we want to aggregate every hour usage diff data into a single time slot.
|
||||||
@@ -1231,33 +1242,7 @@ public final class DataProcessor {
|
|||||||
hourlyBatteryLevelsPerDay.get(dailyIndex).getTimestamps();
|
hourlyBatteryLevelsPerDay.get(dailyIndex).getTimestamps();
|
||||||
for (int hourlyIndex = 0; hourlyIndex < hourlyTimestamps.size() - 1; hourlyIndex++) {
|
for (int hourlyIndex = 0; hourlyIndex < hourlyTimestamps.size() - 1; hourlyIndex++) {
|
||||||
final Long startTimestamp = hourlyTimestamps.get(hourlyIndex);
|
final Long startTimestamp = hourlyTimestamps.get(hourlyIndex);
|
||||||
final Long endTimestamp = hourlyTimestamps.get(hourlyIndex + 1);
|
dailyDiffMap.put(hourlyIndex, batteryDiffDataMap.get(startTimestamp));
|
||||||
final long slotDuration = endTimestamp - startTimestamp;
|
|
||||||
List<Map<String, BatteryHistEntry>> slotBatteryHistoryList = new ArrayList<>();
|
|
||||||
slotBatteryHistoryList.add(
|
|
||||||
batteryHistoryMap.getOrDefault(startTimestamp, EMPTY_BATTERY_MAP));
|
|
||||||
for (Long timestamp = TimestampUtils.getNextHourTimestamp(startTimestamp);
|
|
||||||
timestamp < endTimestamp; timestamp += DateUtils.HOUR_IN_MILLIS) {
|
|
||||||
slotBatteryHistoryList.add(
|
|
||||||
batteryHistoryMap.getOrDefault(timestamp, EMPTY_BATTERY_MAP));
|
|
||||||
}
|
|
||||||
slotBatteryHistoryList.add(
|
|
||||||
batteryHistoryMap.getOrDefault(endTimestamp, EMPTY_BATTERY_MAP));
|
|
||||||
|
|
||||||
final BatteryDiffData hourlyBatteryDiffData =
|
|
||||||
insertHourlyUsageDiffDataPerSlot(
|
|
||||||
context,
|
|
||||||
currentUserId,
|
|
||||||
workProfileUserId,
|
|
||||||
slotDuration,
|
|
||||||
systemAppsPackageNames,
|
|
||||||
systemAppsUids,
|
|
||||||
appUsagePeriodMap == null
|
|
||||||
|| appUsagePeriodMap.get(dailyIndex) == null
|
|
||||||
? null
|
|
||||||
: appUsagePeriodMap.get(dailyIndex).get(hourlyIndex),
|
|
||||||
slotBatteryHistoryList);
|
|
||||||
dailyDiffMap.put(hourlyIndex, hourlyBatteryDiffData);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1292,6 +1277,10 @@ public final class DataProcessor {
|
|||||||
@Nullable
|
@Nullable
|
||||||
private static BatteryDiffData insertHourlyUsageDiffDataPerSlot(
|
private static BatteryDiffData insertHourlyUsageDiffDataPerSlot(
|
||||||
final Context context,
|
final Context context,
|
||||||
|
final long startTimestamp,
|
||||||
|
final long endTimestamp,
|
||||||
|
final int startBatteryLevel,
|
||||||
|
final int endBatteryLevel,
|
||||||
final int currentUserId,
|
final int currentUserId,
|
||||||
final int workProfileUserId,
|
final int workProfileUserId,
|
||||||
final long slotDuration,
|
final long slotDuration,
|
||||||
@@ -1401,7 +1390,7 @@ public final class DataProcessor {
|
|||||||
currentEntry.mCachedUsageConsumePower,
|
currentEntry.mCachedUsageConsumePower,
|
||||||
nextEntry.mCachedUsageConsumePower);
|
nextEntry.mCachedUsageConsumePower);
|
||||||
}
|
}
|
||||||
if (selectedBatteryEntry.isSystemEntry()
|
if (isSystemConsumer(selectedBatteryEntry.mConsumerType)
|
||||||
&& selectedBatteryEntry.mDrainType == BatteryConsumer.POWER_COMPONENT_SCREEN) {
|
&& selectedBatteryEntry.mDrainType == BatteryConsumer.POWER_COMPONENT_SCREEN) {
|
||||||
// Replace Screen system component time with screen on time.
|
// Replace Screen system component time with screen on time.
|
||||||
foregroundUsageTimeInMs = slotScreenOnTime;
|
foregroundUsageTimeInMs = slotScreenOnTime;
|
||||||
@@ -1447,6 +1436,14 @@ public final class DataProcessor {
|
|||||||
backgroundUsageTimeInMs, (long) slotDuration - screenOnTime);
|
backgroundUsageTimeInMs, (long) slotDuration - screenOnTime);
|
||||||
final BatteryDiffEntry currentBatteryDiffEntry = new BatteryDiffEntry(
|
final BatteryDiffEntry currentBatteryDiffEntry = new BatteryDiffEntry(
|
||||||
context,
|
context,
|
||||||
|
selectedBatteryEntry.mUid,
|
||||||
|
selectedBatteryEntry.mUserId,
|
||||||
|
selectedBatteryEntry.getKey(),
|
||||||
|
selectedBatteryEntry.mIsHidden,
|
||||||
|
selectedBatteryEntry.mDrainType,
|
||||||
|
selectedBatteryEntry.mPackageName,
|
||||||
|
selectedBatteryEntry.mAppLabel,
|
||||||
|
selectedBatteryEntry.mConsumerType,
|
||||||
foregroundUsageTimeInMs,
|
foregroundUsageTimeInMs,
|
||||||
backgroundUsageTimeInMs,
|
backgroundUsageTimeInMs,
|
||||||
screenOnTime,
|
screenOnTime,
|
||||||
@@ -1454,8 +1451,7 @@ public final class DataProcessor {
|
|||||||
foregroundUsageConsumePower,
|
foregroundUsageConsumePower,
|
||||||
foregroundServiceUsageConsumePower,
|
foregroundServiceUsageConsumePower,
|
||||||
backgroundUsageConsumePower,
|
backgroundUsageConsumePower,
|
||||||
cachedUsageConsumePower,
|
cachedUsageConsumePower);
|
||||||
selectedBatteryEntry);
|
|
||||||
if (currentBatteryDiffEntry.isSystemEntry()) {
|
if (currentBatteryDiffEntry.isSystemEntry()) {
|
||||||
systemEntries.add(currentBatteryDiffEntry);
|
systemEntries.add(currentBatteryDiffEntry);
|
||||||
} else {
|
} else {
|
||||||
@@ -1468,7 +1464,8 @@ public final class DataProcessor {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return new BatteryDiffData(context, slotScreenOnTime, appEntries, systemEntries,
|
return new BatteryDiffData(context, startTimestamp, endTimestamp, startBatteryLevel,
|
||||||
|
endBatteryLevel, slotScreenOnTime, appEntries, systemEntries,
|
||||||
systemAppsPackageNames, systemAppsUids, /* isAccumulated= */ false);
|
systemAppsPackageNames, systemAppsUids, /* isAccumulated= */ false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1519,7 +1516,7 @@ public final class DataProcessor {
|
|||||||
final int currentUserId,
|
final int currentUserId,
|
||||||
final int workProfileUserId,
|
final int workProfileUserId,
|
||||||
final BatteryHistEntry batteryHistEntry) {
|
final BatteryHistEntry batteryHistEntry) {
|
||||||
return batteryHistEntry.mConsumerType == ConvertUtils.CONSUMER_TYPE_UID_BATTERY
|
return isUidConsumer(batteryHistEntry.mConsumerType)
|
||||||
&& batteryHistEntry.mUserId != currentUserId
|
&& batteryHistEntry.mUserId != currentUserId
|
||||||
&& batteryHistEntry.mUserId != workProfileUserId;
|
&& batteryHistEntry.mUserId != workProfileUserId;
|
||||||
}
|
}
|
||||||
@@ -1531,11 +1528,23 @@ public final class DataProcessor {
|
|||||||
final List<BatteryDiffEntry> appEntries = new ArrayList<>();
|
final List<BatteryDiffEntry> appEntries = new ArrayList<>();
|
||||||
final List<BatteryDiffEntry> systemEntries = new ArrayList<>();
|
final List<BatteryDiffEntry> systemEntries = new ArrayList<>();
|
||||||
|
|
||||||
|
long startTimestamp = Long.MAX_VALUE;
|
||||||
|
long endTimestamp = 0;
|
||||||
|
int startBatteryLevel = BATTERY_LEVEL_UNKNOWN;
|
||||||
|
int endBatteryLevel = BATTERY_LEVEL_UNKNOWN;
|
||||||
long totalScreenOnTime = 0;
|
long totalScreenOnTime = 0;
|
||||||
for (BatteryDiffData batteryDiffData : batteryDiffDataList) {
|
for (BatteryDiffData batteryDiffData : batteryDiffDataList) {
|
||||||
if (batteryDiffData == null) {
|
if (batteryDiffData == null) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (startTimestamp > batteryDiffData.getStartTimestamp()) {
|
||||||
|
startTimestamp = batteryDiffData.getStartTimestamp();
|
||||||
|
startBatteryLevel = batteryDiffData.getStartBatteryLevel();
|
||||||
|
}
|
||||||
|
if (endTimestamp > batteryDiffData.getEndTimestamp()) {
|
||||||
|
endTimestamp = batteryDiffData.getEndTimestamp();
|
||||||
|
endBatteryLevel = batteryDiffData.getEndBatteryLevel();
|
||||||
|
}
|
||||||
totalScreenOnTime += batteryDiffData.getScreenOnTime();
|
totalScreenOnTime += batteryDiffData.getScreenOnTime();
|
||||||
for (BatteryDiffEntry entry : batteryDiffData.getAppDiffEntryList()) {
|
for (BatteryDiffEntry entry : batteryDiffData.getAppDiffEntryList()) {
|
||||||
computeUsageDiffDataPerEntry(entry, diffEntryMap);
|
computeUsageDiffDataPerEntry(entry, diffEntryMap);
|
||||||
@@ -1554,8 +1563,9 @@ public final class DataProcessor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return diffEntryList.isEmpty() ? null : new BatteryDiffData(context, totalScreenOnTime,
|
return diffEntryList.isEmpty() ? null : new BatteryDiffData(context, startTimestamp,
|
||||||
appEntries, systemEntries, /* systemAppsPackageNames= */ new ArraySet<>(),
|
endTimestamp, startBatteryLevel, endBatteryLevel, totalScreenOnTime, appEntries,
|
||||||
|
systemEntries, /* systemAppsPackageNames= */ new ArraySet<>(),
|
||||||
/* systemAppsUids= */ new ArraySet<>(), /* isAccumulated= */ true);
|
/* systemAppsUids= */ new ArraySet<>(), /* isAccumulated= */ true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1751,22 +1761,6 @@ public final class DataProcessor {
|
|||||||
return v2 > v1 ? v2 - v1 : 0;
|
return v2 > v1 ? v2 - v1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Set<String> getSystemAppsPackageNames(Context context) {
|
|
||||||
return sTestSystemAppsPackageNames != null ? sTestSystemAppsPackageNames
|
|
||||||
: AppListRepositoryUtil.getSystemPackageNames(context, context.getUserId());
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Set<Integer> getSystemAppsUids(Context context) {
|
|
||||||
Set<Integer> result = new ArraySet<>();
|
|
||||||
try {
|
|
||||||
result.add(context.getPackageManager().getUidForSharedUser(
|
|
||||||
ANDROID_CORE_APPS_SHARED_USER_ID));
|
|
||||||
} catch (PackageManager.NameNotFoundException e) {
|
|
||||||
// No Android Core Apps
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static long getCurrentTimeMillis() {
|
private static long getCurrentTimeMillis() {
|
||||||
return sTestCurrentTimeMillis > 0 ? sTestCurrentTimeMillis : System.currentTimeMillis();
|
return sTestCurrentTimeMillis > 0 ? sTestCurrentTimeMillis : System.currentTimeMillis();
|
||||||
}
|
}
|
||||||
|
@@ -15,6 +15,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
package com.android.settings.fuelgauge.batteryusage;
|
package com.android.settings.fuelgauge.batteryusage;
|
||||||
|
import static com.android.settings.fuelgauge.batteryusage.ConvertUtils.utcToLocalTimeForLogging;
|
||||||
|
|
||||||
import android.app.usage.IUsageStatsManager;
|
import android.app.usage.IUsageStatsManager;
|
||||||
import android.app.usage.UsageStatsManager;
|
import android.app.usage.UsageStatsManager;
|
||||||
import android.content.ContentResolver;
|
import android.content.ContentResolver;
|
||||||
@@ -76,12 +78,20 @@ public final class DatabaseUtils {
|
|||||||
public static final String BATTERY_EVENT_TABLE = "BatteryEvent";
|
public static final String BATTERY_EVENT_TABLE = "BatteryEvent";
|
||||||
/** A table name for battery usage history. */
|
/** A table name for battery usage history. */
|
||||||
public static final String BATTERY_STATE_TABLE = "BatteryState";
|
public static final String BATTERY_STATE_TABLE = "BatteryState";
|
||||||
|
/** A table name for battery usage slot. */
|
||||||
|
public static final String BATTERY_USAGE_SLOT_TABLE = "BatteryUsageSlot";
|
||||||
|
/** A path name for last full charge time query. */
|
||||||
|
public static final String LAST_FULL_CHARGE_TIMESTAMP_PATH = "lastFullChargeTimestamp";
|
||||||
|
/** A path name for querying the latest record timestamp in battery state table. */
|
||||||
|
public static final String BATTERY_STATE_LATEST_TIMESTAMP_PATH = "batteryStateLatestTimestamp";
|
||||||
/** A path name for app usage latest timestamp query. */
|
/** A path name for app usage latest timestamp query. */
|
||||||
public static final String APP_USAGE_LATEST_TIMESTAMP_PATH = "appUsageLatestTimestamp";
|
public static final String APP_USAGE_LATEST_TIMESTAMP_PATH = "appUsageLatestTimestamp";
|
||||||
/** Key for query parameter timestamp used in BATTERY_CONTENT_URI **/
|
/** Key for query parameter timestamp used in BATTERY_CONTENT_URI **/
|
||||||
public static final String QUERY_KEY_TIMESTAMP = "timestamp";
|
public static final String QUERY_KEY_TIMESTAMP = "timestamp";
|
||||||
/** Key for query parameter userid used in APP_USAGE_EVENT_URI **/
|
/** Key for query parameter userid used in APP_USAGE_EVENT_URI **/
|
||||||
public static final String QUERY_KEY_USERID = "userid";
|
public static final String QUERY_KEY_USERID = "userid";
|
||||||
|
/** Key for query parameter battery event type used in BATTERY_EVENT_URI **/
|
||||||
|
public static final String QUERY_BATTERY_EVENT_TYPE = "batteryEventType";
|
||||||
|
|
||||||
public static final long INVALID_USER_ID = Integer.MIN_VALUE;
|
public static final long INVALID_USER_ID = Integer.MIN_VALUE;
|
||||||
/**
|
/**
|
||||||
@@ -111,6 +121,13 @@ public final class DatabaseUtils {
|
|||||||
.authority(AUTHORITY)
|
.authority(AUTHORITY)
|
||||||
.appendPath(BATTERY_STATE_TABLE)
|
.appendPath(BATTERY_STATE_TABLE)
|
||||||
.build();
|
.build();
|
||||||
|
/** A content URI to access battery usage slots data. */
|
||||||
|
public static final Uri BATTERY_USAGE_SLOT_URI =
|
||||||
|
new Uri.Builder()
|
||||||
|
.scheme(ContentResolver.SCHEME_CONTENT)
|
||||||
|
.authority(AUTHORITY)
|
||||||
|
.appendPath(BATTERY_USAGE_SLOT_TABLE)
|
||||||
|
.build();
|
||||||
|
|
||||||
// For testing only.
|
// For testing only.
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
@@ -140,7 +157,7 @@ public final class DatabaseUtils {
|
|||||||
.build();
|
.build();
|
||||||
final long latestTimestamp =
|
final long latestTimestamp =
|
||||||
loadAppUsageLatestTimestampFromContentProvider(context, appUsageLatestTimestampUri);
|
loadAppUsageLatestTimestampFromContentProvider(context, appUsageLatestTimestampUri);
|
||||||
final String latestTimestampString = ConvertUtils.utcToLocalTimeForLogging(latestTimestamp);
|
final String latestTimestampString = utcToLocalTimeForLogging(latestTimestamp);
|
||||||
Log.d(TAG, String.format(
|
Log.d(TAG, String.format(
|
||||||
"getAppUsageStartTimestampOfUser() userId=%d latestTimestamp=%s in %d/ms",
|
"getAppUsageStartTimestampOfUser() userId=%d latestTimestamp=%s in %d/ms",
|
||||||
userId, latestTimestampString, (System.currentTimeMillis() - startTime)));
|
userId, latestTimestampString, (System.currentTimeMillis() - startTime)));
|
||||||
@@ -161,8 +178,7 @@ public final class DatabaseUtils {
|
|||||||
// sure the app usage calculation near the boundaries is correct.
|
// sure the app usage calculation near the boundaries is correct.
|
||||||
final long queryTimestamp =
|
final long queryTimestamp =
|
||||||
Math.max(rawStartTimestamp, sixDaysAgoTimestamp) - USAGE_QUERY_BUFFER_HOURS;
|
Math.max(rawStartTimestamp, sixDaysAgoTimestamp) - USAGE_QUERY_BUFFER_HOURS;
|
||||||
Log.d(TAG, "sixDayAgoTimestamp: " + ConvertUtils.utcToLocalTimeForLogging(
|
Log.d(TAG, "sixDaysAgoTimestamp: " + utcToLocalTimeForLogging(sixDaysAgoTimestamp));
|
||||||
sixDaysAgoTimestamp));
|
|
||||||
final String queryUserIdString = userIds.stream()
|
final String queryUserIdString = userIds.stream()
|
||||||
.map(userId -> String.valueOf(userId))
|
.map(userId -> String.valueOf(userId))
|
||||||
.collect(Collectors.joining(","));
|
.collect(Collectors.joining(","));
|
||||||
@@ -189,11 +205,15 @@ public final class DatabaseUtils {
|
|||||||
public static List<BatteryEvent> getBatteryEvents(
|
public static List<BatteryEvent> getBatteryEvents(
|
||||||
Context context,
|
Context context,
|
||||||
final Calendar calendar,
|
final Calendar calendar,
|
||||||
final long rawStartTimestamp) {
|
final long rawStartTimestamp,
|
||||||
|
final List<BatteryEventType> queryBatteryEventTypes) {
|
||||||
final long startTime = System.currentTimeMillis();
|
final long startTime = System.currentTimeMillis();
|
||||||
final long sixDaysAgoTimestamp = getTimestampSixDaysAgo(calendar);
|
final long sixDaysAgoTimestamp = getTimestampSixDaysAgo(calendar);
|
||||||
final long queryTimestamp = Math.max(rawStartTimestamp, sixDaysAgoTimestamp);
|
final long queryTimestamp = Math.max(rawStartTimestamp, sixDaysAgoTimestamp);
|
||||||
Log.d(TAG, "getBatteryEvents for timestamp: " + queryTimestamp);
|
Log.d(TAG, "getBatteryEvents for timestamp: " + queryTimestamp);
|
||||||
|
final String queryBatteryEventTypesString = queryBatteryEventTypes.stream()
|
||||||
|
.map(type -> String.valueOf(type.getNumber()))
|
||||||
|
.collect(Collectors.joining(","));
|
||||||
// Builds the content uri everytime to avoid cache.
|
// Builds the content uri everytime to avoid cache.
|
||||||
final Uri batteryEventUri =
|
final Uri batteryEventUri =
|
||||||
new Uri.Builder()
|
new Uri.Builder()
|
||||||
@@ -202,6 +222,8 @@ public final class DatabaseUtils {
|
|||||||
.appendPath(BATTERY_EVENT_TABLE)
|
.appendPath(BATTERY_EVENT_TABLE)
|
||||||
.appendQueryParameter(
|
.appendQueryParameter(
|
||||||
QUERY_KEY_TIMESTAMP, Long.toString(queryTimestamp))
|
QUERY_KEY_TIMESTAMP, Long.toString(queryTimestamp))
|
||||||
|
.appendQueryParameter(
|
||||||
|
QUERY_BATTERY_EVENT_TYPE, queryBatteryEventTypesString)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
final List<BatteryEvent> batteryEventList =
|
final List<BatteryEvent> batteryEventList =
|
||||||
@@ -211,13 +233,82 @@ public final class DatabaseUtils {
|
|||||||
return batteryEventList;
|
return batteryEventList;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Long: for timestamp and String: for BatteryHistEntry.getKey() */
|
/**
|
||||||
public static Map<Long, Map<String, BatteryHistEntry>> getHistoryMapSinceLastFullCharge(
|
* Returns the battery usage slot data after {@code rawStartTimestamp} in battery event table.
|
||||||
Context context, Calendar calendar) {
|
*/
|
||||||
|
public static List<BatteryUsageSlot> getBatteryUsageSlots(
|
||||||
|
Context context,
|
||||||
|
final Calendar calendar,
|
||||||
|
final long rawStartTimestamp) {
|
||||||
final long startTime = System.currentTimeMillis();
|
final long startTime = System.currentTimeMillis();
|
||||||
final long sixDaysAgoTimestamp = getTimestampSixDaysAgo(calendar);
|
final long sixDaysAgoTimestamp = getTimestampSixDaysAgo(calendar);
|
||||||
Log.d(TAG, "sixDayAgoTimestamp: " + ConvertUtils.utcToLocalTimeForLogging(
|
final long queryTimestamp = Math.max(rawStartTimestamp, sixDaysAgoTimestamp);
|
||||||
sixDaysAgoTimestamp));
|
Log.d(TAG, "getBatteryUsageSlots for timestamp: " + queryTimestamp);
|
||||||
|
// Builds the content uri everytime to avoid cache.
|
||||||
|
final Uri batteryUsageSlotUri =
|
||||||
|
new Uri.Builder()
|
||||||
|
.scheme(ContentResolver.SCHEME_CONTENT)
|
||||||
|
.authority(AUTHORITY)
|
||||||
|
.appendPath(BATTERY_USAGE_SLOT_TABLE)
|
||||||
|
.appendQueryParameter(
|
||||||
|
QUERY_KEY_TIMESTAMP, Long.toString(queryTimestamp))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
final List<BatteryUsageSlot> batteryUsageSlotList =
|
||||||
|
loadBatteryUsageSlotsFromContentProvider(context, batteryUsageSlotUri);
|
||||||
|
Log.d(TAG, String.format("getBatteryUsageSlots size=%d in %d/ms",
|
||||||
|
batteryUsageSlotList.size(), (System.currentTimeMillis() - startTime)));
|
||||||
|
return batteryUsageSlotList;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the last full charge time. */
|
||||||
|
public static long getLastFullChargeTime(Context context) {
|
||||||
|
final long startTime = System.currentTimeMillis();
|
||||||
|
// Builds the content uri everytime to avoid cache.
|
||||||
|
final Uri lastFullChargeTimeUri =
|
||||||
|
new Uri.Builder()
|
||||||
|
.scheme(ContentResolver.SCHEME_CONTENT)
|
||||||
|
.authority(AUTHORITY)
|
||||||
|
.appendPath(LAST_FULL_CHARGE_TIMESTAMP_PATH)
|
||||||
|
.build();
|
||||||
|
final long lastFullChargeTime = loadLastFullChargeTimeFromContentProvider(
|
||||||
|
context, lastFullChargeTimeUri);
|
||||||
|
final String lastFullChargeTimeString = utcToLocalTimeForLogging(lastFullChargeTime);
|
||||||
|
Log.d(TAG, String.format(
|
||||||
|
"getLastFullChargeTime() lastFullChargeTime=%s in %d/ms",
|
||||||
|
lastFullChargeTimeString, (System.currentTimeMillis() - startTime)));
|
||||||
|
return lastFullChargeTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the first battery state timestamp no later than the {@code queryTimestamp}. */
|
||||||
|
@VisibleForTesting
|
||||||
|
static long getBatteryStateLatestTimestampBeforeQueryTimestamp(
|
||||||
|
Context context, final long queryTimestamp) {
|
||||||
|
final long startTime = System.currentTimeMillis();
|
||||||
|
// Builds the content uri everytime to avoid cache.
|
||||||
|
final Uri batteryStateLatestTimestampUri =
|
||||||
|
new Uri.Builder()
|
||||||
|
.scheme(ContentResolver.SCHEME_CONTENT)
|
||||||
|
.authority(AUTHORITY)
|
||||||
|
.appendPath(BATTERY_STATE_LATEST_TIMESTAMP_PATH)
|
||||||
|
.appendQueryParameter(
|
||||||
|
QUERY_KEY_TIMESTAMP, Long.toString(queryTimestamp))
|
||||||
|
.build();
|
||||||
|
final long batteryStateLatestTimestamp = loadBatteryStateLatestTimestampFromContentProvider(
|
||||||
|
context, batteryStateLatestTimestampUri);
|
||||||
|
final String batteryStateLatestTimestampString =
|
||||||
|
utcToLocalTimeForLogging(batteryStateLatestTimestamp);
|
||||||
|
Log.d(TAG, String.format(
|
||||||
|
"getBatteryStateLatestTimestamp() batteryStateLatestTimestamp=%s in %d/ms",
|
||||||
|
batteryStateLatestTimestampString, (System.currentTimeMillis() - startTime)));
|
||||||
|
return batteryStateLatestTimestamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the battery history map after the given timestamp. */
|
||||||
|
@VisibleForTesting
|
||||||
|
static Map<Long, Map<String, BatteryHistEntry>> getHistoryMapSinceQueryTimestamp(
|
||||||
|
Context context, final long queryTimestamp) {
|
||||||
|
final long startTime = System.currentTimeMillis();
|
||||||
// Builds the content uri everytime to avoid cache.
|
// Builds the content uri everytime to avoid cache.
|
||||||
final Uri batteryStateUri =
|
final Uri batteryStateUri =
|
||||||
new Uri.Builder()
|
new Uri.Builder()
|
||||||
@@ -225,20 +316,46 @@ public final class DatabaseUtils {
|
|||||||
.authority(AUTHORITY)
|
.authority(AUTHORITY)
|
||||||
.appendPath(BATTERY_STATE_TABLE)
|
.appendPath(BATTERY_STATE_TABLE)
|
||||||
.appendQueryParameter(
|
.appendQueryParameter(
|
||||||
QUERY_KEY_TIMESTAMP, Long.toString(sixDaysAgoTimestamp))
|
QUERY_KEY_TIMESTAMP, Long.toString(queryTimestamp))
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
final Map<Long, Map<String, BatteryHistEntry>> resultMap =
|
final Map<Long, Map<String, BatteryHistEntry>> resultMap =
|
||||||
loadHistoryMapFromContentProvider(context, batteryStateUri);
|
loadHistoryMapFromContentProvider(context, batteryStateUri);
|
||||||
if (resultMap == null || resultMap.isEmpty()) {
|
if (resultMap == null || resultMap.isEmpty()) {
|
||||||
Log.d(TAG, "getHistoryMapSinceLastFullCharge() returns empty or null");
|
Log.d(TAG, "getBatteryHistoryMap() returns empty or null");
|
||||||
} else {
|
} else {
|
||||||
Log.d(TAG, String.format("getHistoryMapSinceLastFullCharge() size=%d in %d/ms",
|
Log.d(TAG, String.format("getBatteryHistoryMap() size=%d in %d/ms",
|
||||||
resultMap.size(), (System.currentTimeMillis() - startTime)));
|
resultMap.size(), (System.currentTimeMillis() - startTime)));
|
||||||
}
|
}
|
||||||
return resultMap;
|
return resultMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the battery history map since the latest record no later than the given timestamp.
|
||||||
|
* If there is no record before the given timestamp or the given timestamp is before last full
|
||||||
|
* charge time, returns the history map since last full charge time.
|
||||||
|
*/
|
||||||
|
public static Map<Long, Map<String, BatteryHistEntry>>
|
||||||
|
getHistoryMapSinceLatestRecordBeforeQueryTimestamp(Context context, Calendar calendar,
|
||||||
|
final long queryTimestamp, final long lastFullChargeTime) {
|
||||||
|
final long sixDaysAgoTimestamp = getTimestampSixDaysAgo(calendar);
|
||||||
|
Log.d(TAG, "sixDaysAgoTimestamp: " + utcToLocalTimeForLogging(sixDaysAgoTimestamp));
|
||||||
|
final long batteryStateLatestTimestamp =
|
||||||
|
queryTimestamp == 0L ? 0L : getBatteryStateLatestTimestampBeforeQueryTimestamp(
|
||||||
|
context, queryTimestamp);
|
||||||
|
final long maxTimestamp = Math.max(Math.max(
|
||||||
|
sixDaysAgoTimestamp, lastFullChargeTime), batteryStateLatestTimestamp);
|
||||||
|
return getHistoryMapSinceQueryTimestamp(context, maxTimestamp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the history map since last full charge time. */
|
||||||
|
public static Map<Long, Map<String, BatteryHistEntry>> getHistoryMapSinceLastFullCharge(
|
||||||
|
Context context, Calendar calendar) {
|
||||||
|
final long lastFullChargeTime = getLastFullChargeTime(context);
|
||||||
|
return getHistoryMapSinceLatestRecordBeforeQueryTimestamp(
|
||||||
|
context, calendar, 0, lastFullChargeTime);
|
||||||
|
}
|
||||||
|
|
||||||
/** Clears all data in the battery usage database. */
|
/** Clears all data in the battery usage database. */
|
||||||
public static void clearAll(Context context) {
|
public static void clearAll(Context context) {
|
||||||
AsyncTask.execute(() -> {
|
AsyncTask.execute(() -> {
|
||||||
@@ -248,6 +365,7 @@ public final class DatabaseUtils {
|
|||||||
database.appUsageEventDao().clearAll();
|
database.appUsageEventDao().clearAll();
|
||||||
database.batteryEventDao().clearAll();
|
database.batteryEventDao().clearAll();
|
||||||
database.batteryStateDao().clearAll();
|
database.batteryStateDao().clearAll();
|
||||||
|
database.batteryUsageSlotDao().clearAll();
|
||||||
} catch (RuntimeException e) {
|
} catch (RuntimeException e) {
|
||||||
Log.e(TAG, "clearAll() failed", e);
|
Log.e(TAG, "clearAll() failed", e);
|
||||||
}
|
}
|
||||||
@@ -265,6 +383,7 @@ public final class DatabaseUtils {
|
|||||||
database.appUsageEventDao().clearAllBefore(earliestTimestamp);
|
database.appUsageEventDao().clearAllBefore(earliestTimestamp);
|
||||||
database.batteryEventDao().clearAllBefore(earliestTimestamp);
|
database.batteryEventDao().clearAllBefore(earliestTimestamp);
|
||||||
database.batteryStateDao().clearAllBefore(earliestTimestamp);
|
database.batteryStateDao().clearAllBefore(earliestTimestamp);
|
||||||
|
database.batteryUsageSlotDao().clearAllBefore(earliestTimestamp);
|
||||||
} catch (RuntimeException e) {
|
} catch (RuntimeException e) {
|
||||||
Log.e(TAG, "clearAllBefore() failed", e);
|
Log.e(TAG, "clearAllBefore() failed", e);
|
||||||
}
|
}
|
||||||
@@ -293,7 +412,7 @@ public final class DatabaseUtils {
|
|||||||
/*user=*/ context.getSystemService(UserManager.class)
|
/*user=*/ context.getSystemService(UserManager.class)
|
||||||
.getProfileParent(context.getUser()));
|
.getProfileParent(context.getUser()));
|
||||||
} catch (PackageManager.NameNotFoundException e) {
|
} catch (PackageManager.NameNotFoundException e) {
|
||||||
Log.e(TAG, "context.createPackageContextAsUser() fail:" + e);
|
Log.e(TAG, "context.createPackageContextAsUser() fail:", e);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -320,7 +439,7 @@ public final class DatabaseUtils {
|
|||||||
resolver.notifyChange(APP_USAGE_EVENT_URI, /*observer=*/ null);
|
resolver.notifyChange(APP_USAGE_EVENT_URI, /*observer=*/ null);
|
||||||
Log.d(TAG, "insert() app usage events data into database");
|
Log.d(TAG, "insert() app usage events data into database");
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Log.e(TAG, "bulkInsert() app usage data into database error:\n" + e);
|
Log.e(TAG, "bulkInsert() app usage data into database error:", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Log.d(TAG, String.format("sendAppUsageEventData() size=%d in %d/ms",
|
Log.d(TAG, String.format("sendAppUsageEventData() size=%d in %d/ms",
|
||||||
@@ -346,8 +465,65 @@ public final class DatabaseUtils {
|
|||||||
return contentValues;
|
return contentValues;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static List<ContentValues> sendBatteryEventData(
|
||||||
|
final Context context, final List<BatteryEvent> batteryEventList) {
|
||||||
|
final long startTime = System.currentTimeMillis();
|
||||||
|
// Creates the ContentValues list to insert them into provider.
|
||||||
|
final List<ContentValues> valuesList = new ArrayList<>();
|
||||||
|
batteryEventList.stream()
|
||||||
|
.forEach(batteryEvent -> valuesList.add(
|
||||||
|
ConvertUtils.convertBatteryEventToContentValues(batteryEvent)));
|
||||||
|
int size = 0;
|
||||||
|
final ContentResolver resolver = context.getContentResolver();
|
||||||
|
// Inserts all ContentValues into battery provider.
|
||||||
|
if (!valuesList.isEmpty()) {
|
||||||
|
final ContentValues[] valuesArray = new ContentValues[valuesList.size()];
|
||||||
|
valuesList.toArray(valuesArray);
|
||||||
|
try {
|
||||||
|
size = resolver.bulkInsert(BATTERY_EVENT_URI, valuesArray);
|
||||||
|
resolver.notifyChange(BATTERY_EVENT_URI, /*observer=*/ null);
|
||||||
|
Log.d(TAG, "insert() battery event data into database");
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e(TAG, "bulkInsert() battery event data into database error:", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Log.d(TAG, String.format("sendBatteryEventData() size=%d in %d/ms",
|
||||||
|
size, (System.currentTimeMillis() - startTime)));
|
||||||
|
clearMemory();
|
||||||
|
return valuesList;
|
||||||
|
}
|
||||||
|
|
||||||
|
static List<ContentValues> sendBatteryUsageSlotData(
|
||||||
|
final Context context, final List<BatteryUsageSlot> batteryUsageSlotList) {
|
||||||
|
final long startTime = System.currentTimeMillis();
|
||||||
|
// Creates the ContentValues list to insert them into provider.
|
||||||
|
final List<ContentValues> valuesList = new ArrayList<>();
|
||||||
|
batteryUsageSlotList.stream()
|
||||||
|
.forEach(batteryUsageSlot -> valuesList.add(
|
||||||
|
ConvertUtils.convertBatteryUsageSlotToContentValues(batteryUsageSlot)));
|
||||||
|
int size = 0;
|
||||||
|
final ContentResolver resolver = context.getContentResolver();
|
||||||
|
// Inserts all ContentValues into battery provider.
|
||||||
|
if (!valuesList.isEmpty()) {
|
||||||
|
final ContentValues[] valuesArray = new ContentValues[valuesList.size()];
|
||||||
|
valuesList.toArray(valuesArray);
|
||||||
|
try {
|
||||||
|
size = resolver.bulkInsert(BATTERY_USAGE_SLOT_URI, valuesArray);
|
||||||
|
resolver.notifyChange(BATTERY_USAGE_SLOT_URI, /*observer=*/ null);
|
||||||
|
Log.d(TAG, "insert() battery usage slots data into database");
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e(TAG, "bulkInsert() battery usage slots data into database error:", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Log.d(TAG, String.format("sendBatteryUsageSlotData() size=%d in %d/ms",
|
||||||
|
size, (System.currentTimeMillis() - startTime)));
|
||||||
|
clearMemory();
|
||||||
|
return valuesList;
|
||||||
|
}
|
||||||
|
|
||||||
static List<ContentValues> sendBatteryEntryData(
|
static List<ContentValues> sendBatteryEntryData(
|
||||||
final Context context,
|
final Context context,
|
||||||
|
final long snapshotTimestamp,
|
||||||
final List<BatteryEntry> batteryEntryList,
|
final List<BatteryEntry> batteryEntryList,
|
||||||
final BatteryUsageStats batteryUsageStats,
|
final BatteryUsageStats batteryUsageStats,
|
||||||
final boolean isFullChargeStart) {
|
final boolean isFullChargeStart) {
|
||||||
@@ -364,7 +540,6 @@ public final class DatabaseUtils {
|
|||||||
final int batteryHealth = intent.getIntExtra(
|
final int batteryHealth = intent.getIntExtra(
|
||||||
BatteryManager.EXTRA_HEALTH, BatteryManager.BATTERY_HEALTH_UNKNOWN);
|
BatteryManager.EXTRA_HEALTH, BatteryManager.BATTERY_HEALTH_UNKNOWN);
|
||||||
// We should use the same timestamp for each data snapshot.
|
// We should use the same timestamp for each data snapshot.
|
||||||
final long snapshotTimestamp = Clock.systemUTC().millis();
|
|
||||||
final long snapshotBootTimestamp = SystemClock.elapsedRealtime();
|
final long snapshotBootTimestamp = SystemClock.elapsedRealtime();
|
||||||
|
|
||||||
// Creates the ContentValues list to insert them into provider.
|
// Creates the ContentValues list to insert them into provider.
|
||||||
@@ -409,8 +584,7 @@ public final class DatabaseUtils {
|
|||||||
Log.d(TAG, "insert() battery states data into database with isFullChargeStart:"
|
Log.d(TAG, "insert() battery states data into database with isFullChargeStart:"
|
||||||
+ isFullChargeStart);
|
+ isFullChargeStart);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
errorMessage = e.toString();
|
Log.e(TAG, "bulkInsert() data into database error:", e);
|
||||||
Log.e(TAG, "bulkInsert() data into database error:\n" + errorMessage);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Inserts one fake data into battery provider.
|
// Inserts one fake data into battery provider.
|
||||||
@@ -430,8 +604,7 @@ public final class DatabaseUtils {
|
|||||||
+ isFullChargeStart);
|
+ isFullChargeStart);
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
errorMessage = e.toString();
|
Log.e(TAG, "insert() data into database error:", e);
|
||||||
Log.e(TAG, "insert() data into database error:\n" + errorMessage);
|
|
||||||
}
|
}
|
||||||
valuesList.add(contentValues);
|
valuesList.add(contentValues);
|
||||||
}
|
}
|
||||||
@@ -504,8 +677,7 @@ public final class DatabaseUtils {
|
|||||||
static void recordDateTime(Context context, String preferenceKey) {
|
static void recordDateTime(Context context, String preferenceKey) {
|
||||||
final SharedPreferences sharedPreferences = getSharedPreferences(context);
|
final SharedPreferences sharedPreferences = getSharedPreferences(context);
|
||||||
if (sharedPreferences != null) {
|
if (sharedPreferences != null) {
|
||||||
final String currentTime = ConvertUtils.utcToLocalTimeForLogging(
|
final String currentTime = utcToLocalTimeForLogging(System.currentTimeMillis());
|
||||||
System.currentTimeMillis());
|
|
||||||
sharedPreferences.edit().putString(preferenceKey, currentTime).apply();
|
sharedPreferences.edit().putString(preferenceKey, currentTime).apply();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -533,11 +705,6 @@ public final class DatabaseUtils {
|
|||||||
cursor.moveToFirst();
|
cursor.moveToFirst();
|
||||||
// There is only one column returned so use the index 0 directly.
|
// There is only one column returned so use the index 0 directly.
|
||||||
final long latestTimestamp = cursor.getLong(/*columnIndex=*/ 0);
|
final long latestTimestamp = cursor.getLong(/*columnIndex=*/ 0);
|
||||||
try {
|
|
||||||
cursor.close();
|
|
||||||
} catch (Exception e) {
|
|
||||||
Log.e(TAG, "cursor.close() failed", e);
|
|
||||||
}
|
|
||||||
// If there is no data for this user, 0 will be returned from the database.
|
// If there is no data for this user, 0 will be returned from the database.
|
||||||
return latestTimestamp == 0 ? INVALID_USER_ID : latestTimestamp;
|
return latestTimestamp == 0 ? INVALID_USER_ID : latestTimestamp;
|
||||||
}
|
}
|
||||||
@@ -556,14 +723,9 @@ public final class DatabaseUtils {
|
|||||||
if (cursor == null || cursor.getCount() == 0) {
|
if (cursor == null || cursor.getCount() == 0) {
|
||||||
return appUsageEventList;
|
return appUsageEventList;
|
||||||
}
|
}
|
||||||
// Loads and recovers all AppUsageEvent data from cursor.
|
// Loads and converts all AppUsageEvent data from cursor.
|
||||||
while (cursor.moveToNext()) {
|
while (cursor.moveToNext()) {
|
||||||
appUsageEventList.add(ConvertUtils.convertToAppUsageEventFromCursor(cursor));
|
appUsageEventList.add(ConvertUtils.convertToAppUsageEvent(cursor));
|
||||||
}
|
|
||||||
try {
|
|
||||||
cursor.close();
|
|
||||||
} catch (Exception e) {
|
|
||||||
Log.e(TAG, "cursor.close() failed", e);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return appUsageEventList;
|
return appUsageEventList;
|
||||||
@@ -582,19 +744,71 @@ public final class DatabaseUtils {
|
|||||||
if (cursor == null || cursor.getCount() == 0) {
|
if (cursor == null || cursor.getCount() == 0) {
|
||||||
return batteryEventList;
|
return batteryEventList;
|
||||||
}
|
}
|
||||||
// Loads and recovers all AppUsageEvent data from cursor.
|
// Loads and converts all AppUsageEvent data from cursor.
|
||||||
while (cursor.moveToNext()) {
|
while (cursor.moveToNext()) {
|
||||||
batteryEventList.add(ConvertUtils.convertToBatteryEventFromCursor(cursor));
|
batteryEventList.add(ConvertUtils.convertToBatteryEvent(cursor));
|
||||||
}
|
|
||||||
try {
|
|
||||||
cursor.close();
|
|
||||||
} catch (Exception e) {
|
|
||||||
Log.e(TAG, "cursor.close() failed", e);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return batteryEventList;
|
return batteryEventList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static List<BatteryUsageSlot> loadBatteryUsageSlotsFromContentProvider(
|
||||||
|
Context context, Uri batteryUsageSlotUri) {
|
||||||
|
final List<BatteryUsageSlot> batteryUsageSlotList = new ArrayList<>();
|
||||||
|
context = getParentContext(context);
|
||||||
|
if (context == null) {
|
||||||
|
return batteryUsageSlotList;
|
||||||
|
}
|
||||||
|
try (Cursor cursor = sFakeSupplier != null
|
||||||
|
? sFakeSupplier.get()
|
||||||
|
: context.getContentResolver().query(batteryUsageSlotUri, null, null, null)) {
|
||||||
|
if (cursor == null || cursor.getCount() == 0) {
|
||||||
|
return batteryUsageSlotList;
|
||||||
|
}
|
||||||
|
// Loads and converts all AppUsageEvent data from cursor.
|
||||||
|
while (cursor.moveToNext()) {
|
||||||
|
batteryUsageSlotList.add(ConvertUtils.convertToBatteryUsageSlot(cursor));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return batteryUsageSlotList;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static long loadLastFullChargeTimeFromContentProvider(
|
||||||
|
Context context, final Uri lastFullChargeTimeUri) {
|
||||||
|
// We have already make sure the context here is with profile parent's user identity. Don't
|
||||||
|
// need to check whether current user is work profile.
|
||||||
|
try (Cursor cursor = sFakeSupplier != null
|
||||||
|
? sFakeSupplier.get()
|
||||||
|
: context.getContentResolver().query(
|
||||||
|
lastFullChargeTimeUri, null, null, null)) {
|
||||||
|
if (cursor == null || cursor.getCount() == 0) {
|
||||||
|
return 0L;
|
||||||
|
}
|
||||||
|
cursor.moveToFirst();
|
||||||
|
// There is only one column returned so use the index 0 directly.
|
||||||
|
final long lastFullChargeTime = cursor.getLong(/*columnIndex=*/ 0);
|
||||||
|
return lastFullChargeTime;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static long loadBatteryStateLatestTimestampFromContentProvider(
|
||||||
|
Context context, final Uri batteryStateLatestTimestampUri) {
|
||||||
|
// We have already make sure the context here is with profile parent's user identity. Don't
|
||||||
|
// need to check whether current user is work profile.
|
||||||
|
try (Cursor cursor = sFakeSupplier != null
|
||||||
|
? sFakeSupplier.get()
|
||||||
|
: context.getContentResolver().query(
|
||||||
|
batteryStateLatestTimestampUri, null, null, null)) {
|
||||||
|
if (cursor == null || cursor.getCount() == 0) {
|
||||||
|
return 0L;
|
||||||
|
}
|
||||||
|
cursor.moveToFirst();
|
||||||
|
// There is only one column returned so use the index 0 directly.
|
||||||
|
final long batteryStateLatestTimestamp = cursor.getLong(/*columnIndex=*/ 0);
|
||||||
|
return batteryStateLatestTimestamp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static Map<Long, Map<String, BatteryHistEntry>> loadHistoryMapFromContentProvider(
|
private static Map<Long, Map<String, BatteryHistEntry>> loadHistoryMapFromContentProvider(
|
||||||
Context context, Uri batteryStateUri) {
|
Context context, Uri batteryStateUri) {
|
||||||
context = getParentContext(context);
|
context = getParentContext(context);
|
||||||
@@ -607,7 +821,7 @@ public final class DatabaseUtils {
|
|||||||
if (cursor == null || cursor.getCount() == 0) {
|
if (cursor == null || cursor.getCount() == 0) {
|
||||||
return resultMap;
|
return resultMap;
|
||||||
}
|
}
|
||||||
// Loads and recovers all BatteryHistEntry data from cursor.
|
// Loads and converts all BatteryHistEntry data from cursor.
|
||||||
while (cursor.moveToNext()) {
|
while (cursor.moveToNext()) {
|
||||||
final BatteryHistEntry entry = new BatteryHistEntry(cursor);
|
final BatteryHistEntry entry = new BatteryHistEntry(cursor);
|
||||||
final long timestamp = entry.mTimestamp;
|
final long timestamp = entry.mTimestamp;
|
||||||
@@ -620,11 +834,6 @@ public final class DatabaseUtils {
|
|||||||
}
|
}
|
||||||
batteryHistEntryMap.put(key, entry);
|
batteryHistEntryMap.put(key, entry);
|
||||||
}
|
}
|
||||||
try {
|
|
||||||
cursor.close();
|
|
||||||
} catch (Exception e) {
|
|
||||||
Log.e(TAG, "cursor.close() failed", e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return resultMap;
|
return resultMap;
|
||||||
}
|
}
|
||||||
|
@@ -44,7 +44,6 @@ public final class PeriodicJobReceiver extends BroadcastReceiver {
|
|||||||
}
|
}
|
||||||
BatteryUsageLogUtils.writeLog(context, Action.EXECUTE_JOB, "");
|
BatteryUsageLogUtils.writeLog(context, Action.EXECUTE_JOB, "");
|
||||||
BatteryUsageDataLoader.enqueueWork(context, /*isFullChargeStart=*/ false);
|
BatteryUsageDataLoader.enqueueWork(context, /*isFullChargeStart=*/ false);
|
||||||
AppUsageDataLoader.enqueueWork(context);
|
|
||||||
Log.d(TAG, "refresh periodic job from action=" + action);
|
Log.d(TAG, "refresh periodic job from action=" + action);
|
||||||
PeriodicJobManager.getInstance(context).refreshJob(/*fromBoot=*/ false);
|
PeriodicJobManager.getInstance(context).refreshJob(/*fromBoot=*/ false);
|
||||||
DatabaseUtils.clearExpiredDataIfNeeded(context);
|
DatabaseUtils.clearExpiredDataIfNeeded(context);
|
||||||
|
@@ -21,12 +21,13 @@ import android.app.settings.SettingsEnums;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.database.ContentObserver;
|
import android.database.ContentObserver;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
import android.os.AsyncTask;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
|
import android.os.Looper;
|
||||||
import android.provider.SearchIndexableResource;
|
import android.provider.SearchIndexableResource;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.annotation.VisibleForTesting;
|
import androidx.annotation.VisibleForTesting;
|
||||||
import androidx.loader.app.LoaderManager;
|
import androidx.loader.app.LoaderManager;
|
||||||
import androidx.loader.content.Loader;
|
import androidx.loader.content.Loader;
|
||||||
@@ -39,11 +40,13 @@ import com.android.settings.overlay.FeatureFactory;
|
|||||||
import com.android.settings.search.BaseSearchIndexProvider;
|
import com.android.settings.search.BaseSearchIndexProvider;
|
||||||
import com.android.settingslib.core.AbstractPreferenceController;
|
import com.android.settingslib.core.AbstractPreferenceController;
|
||||||
import com.android.settingslib.search.SearchIndexable;
|
import com.android.settingslib.search.SearchIndexable;
|
||||||
|
import com.android.settingslib.utils.AsyncLoaderCompat;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
/** Advanced power usage. */
|
/** Advanced power usage. */
|
||||||
@SearchIndexable(forTarget = SearchIndexable.ALL & ~SearchIndexable.ARC)
|
@SearchIndexable(forTarget = SearchIndexable.ALL & ~SearchIndexable.ARC)
|
||||||
@@ -55,16 +58,17 @@ public class PowerUsageAdvanced extends PowerUsageBase {
|
|||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
BatteryHistoryPreference mHistPref;
|
BatteryHistoryPreference mHistPref;
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
Map<Long, Map<String, BatteryHistEntry>> mBatteryHistoryMap;
|
final BatteryLevelDataLoaderCallbacks mBatteryLevelDataLoaderCallbacks =
|
||||||
@VisibleForTesting
|
new BatteryLevelDataLoaderCallbacks();
|
||||||
final BatteryHistoryLoaderCallbacks mBatteryHistoryLoaderCallbacks =
|
|
||||||
new BatteryHistoryLoaderCallbacks();
|
|
||||||
|
|
||||||
private boolean mIsChartDataLoaded = false;
|
private boolean mIsChartDataLoaded = false;
|
||||||
|
private long mResumeTimestamp;
|
||||||
private BatteryChartPreferenceController mBatteryChartPreferenceController;
|
private BatteryChartPreferenceController mBatteryChartPreferenceController;
|
||||||
|
private Optional<BatteryLevelData> mBatteryLevelData;
|
||||||
|
|
||||||
|
private final Handler mHandler = new Handler(Looper.getMainLooper());
|
||||||
private final ContentObserver mBatteryObserver =
|
private final ContentObserver mBatteryObserver =
|
||||||
new ContentObserver(new Handler()) {
|
new ContentObserver(mHandler) {
|
||||||
@Override
|
@Override
|
||||||
public void onChange(boolean selfChange) {
|
public void onChange(boolean selfChange) {
|
||||||
Log.d(TAG, "onBatteryContentChange: " + selfChange);
|
Log.d(TAG, "onBatteryContentChange: " + selfChange);
|
||||||
@@ -79,6 +83,7 @@ public class PowerUsageAdvanced extends PowerUsageBase {
|
|||||||
super.onCreate(icicle);
|
super.onCreate(icicle);
|
||||||
mHistPref = findPreference(KEY_BATTERY_CHART);
|
mHistPref = findPreference(KEY_BATTERY_CHART);
|
||||||
setBatteryChartPreferenceController();
|
setBatteryChartPreferenceController();
|
||||||
|
AsyncTask.execute(() -> BootBroadcastReceiver.invokeJobRecheck(getContext()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -109,6 +114,7 @@ public class PowerUsageAdvanced extends PowerUsageBase {
|
|||||||
super.onPause();
|
super.onPause();
|
||||||
// Resets the flag to reload usage data in onResume() callback.
|
// Resets the flag to reload usage data in onResume() callback.
|
||||||
mIsChartDataLoaded = false;
|
mIsChartDataLoaded = false;
|
||||||
|
mBatteryLevelData = null;
|
||||||
final Uri uri = DatabaseUtils.BATTERY_CONTENT_URI;
|
final Uri uri = DatabaseUtils.BATTERY_CONTENT_URI;
|
||||||
if (uri != null) {
|
if (uri != null) {
|
||||||
getContext().getContentResolver().unregisterContentObserver(mBatteryObserver);
|
getContext().getContentResolver().unregisterContentObserver(mBatteryObserver);
|
||||||
@@ -118,6 +124,7 @@ public class PowerUsageAdvanced extends PowerUsageBase {
|
|||||||
@Override
|
@Override
|
||||||
public void onResume() {
|
public void onResume() {
|
||||||
super.onResume();
|
super.onResume();
|
||||||
|
mResumeTimestamp = System.currentTimeMillis();
|
||||||
final Uri uri = DatabaseUtils.BATTERY_CONTENT_URI;
|
final Uri uri = DatabaseUtils.BATTERY_CONTENT_URI;
|
||||||
if (uri != null) {
|
if (uri != null) {
|
||||||
getContext().getContentResolver().registerContentObserver(
|
getContext().getContentResolver().registerContentObserver(
|
||||||
@@ -158,21 +165,9 @@ public class PowerUsageAdvanced extends PowerUsageBase {
|
|||||||
return controllers;
|
return controllers;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected boolean isBatteryHistoryNeeded() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void refreshUi(@BatteryUpdateType int refreshType) {
|
protected void refreshUi(@BatteryUpdateType int refreshType) {
|
||||||
final Context context = getContext();
|
// Do nothing
|
||||||
if (context == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
updatePreference(mHistPref);
|
|
||||||
if (mBatteryChartPreferenceController != null && mBatteryHistoryMap != null) {
|
|
||||||
mBatteryChartPreferenceController.setBatteryHistoryMap(mBatteryHistoryMap);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -181,11 +176,32 @@ public class PowerUsageAdvanced extends PowerUsageBase {
|
|||||||
bundle.putInt(KEY_REFRESH_TYPE, refreshType);
|
bundle.putInt(KEY_REFRESH_TYPE, refreshType);
|
||||||
if (!mIsChartDataLoaded) {
|
if (!mIsChartDataLoaded) {
|
||||||
mIsChartDataLoaded = true;
|
mIsChartDataLoaded = true;
|
||||||
restartLoader(LoaderIndex.BATTERY_HISTORY_LOADER, bundle,
|
restartLoader(LoaderIndex.BATTERY_LEVEL_DATA_LOADER, bundle,
|
||||||
mBatteryHistoryLoaderCallbacks);
|
mBatteryLevelDataLoaderCallbacks);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void onBatteryLevelDataUpdate(BatteryLevelData batteryLevelData) {
|
||||||
|
mBatteryLevelData = Optional.ofNullable(batteryLevelData);
|
||||||
|
if (mBatteryChartPreferenceController != null) {
|
||||||
|
mBatteryChartPreferenceController.onBatteryLevelDataUpdate(batteryLevelData);
|
||||||
|
Log.d(TAG, String.format("Battery chart shows in %d millis",
|
||||||
|
System.currentTimeMillis() - mResumeTimestamp));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onBatteryDiffDataMapUpdate(Map<Long, BatteryDiffData> batteryDiffDataMap) {
|
||||||
|
if (mBatteryLevelData != null && mBatteryChartPreferenceController != null) {
|
||||||
|
Map<Integer, Map<Integer, BatteryDiffData>> batteryUsageMap =
|
||||||
|
DataProcessor.generateBatteryUsageMap(
|
||||||
|
getContext(), batteryDiffDataMap, mBatteryLevelData.orElse(null));
|
||||||
|
DataProcessor.loadLabelAndIcon(batteryUsageMap);
|
||||||
|
mBatteryChartPreferenceController.onBatteryUsageMapUpdate(batteryUsageMap);
|
||||||
|
}
|
||||||
|
Log.d(TAG, String.format("Battery usage list shows in %d millis",
|
||||||
|
System.currentTimeMillis() - mResumeTimestamp));
|
||||||
|
}
|
||||||
|
|
||||||
private void setBatteryChartPreferenceController() {
|
private void setBatteryChartPreferenceController() {
|
||||||
if (mHistPref != null && mBatteryChartPreferenceController != null) {
|
if (mHistPref != null && mBatteryChartPreferenceController != null) {
|
||||||
mHistPref.setChartPreferenceController(mBatteryChartPreferenceController);
|
mHistPref.setChartPreferenceController(mBatteryChartPreferenceController);
|
||||||
@@ -216,28 +232,31 @@ public class PowerUsageAdvanced extends PowerUsageBase {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
private class BatteryHistoryLoaderCallbacks
|
private class BatteryLevelDataLoaderCallbacks
|
||||||
implements LoaderManager.LoaderCallbacks<Map<Long, Map<String, BatteryHistEntry>>> {
|
implements LoaderManager.LoaderCallbacks<BatteryLevelData> {
|
||||||
private int mRefreshType;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@NonNull
|
public Loader<BatteryLevelData> onCreateLoader(int id, Bundle bundle) {
|
||||||
public Loader<Map<Long, Map<String, BatteryHistEntry>>> onCreateLoader(
|
return new AsyncLoaderCompat<BatteryLevelData>(getContext().getApplicationContext()) {
|
||||||
int id, Bundle bundle) {
|
@Override
|
||||||
mRefreshType = bundle.getInt(KEY_REFRESH_TYPE);
|
protected void onDiscardResult(BatteryLevelData result) {}
|
||||||
return new BatteryHistoryLoader(getContext());
|
|
||||||
|
@Override
|
||||||
|
public BatteryLevelData loadInBackground() {
|
||||||
|
return DataProcessManager.getBatteryLevelData(
|
||||||
|
getContext(), mHandler, /*isFromPeriodJob=*/ false,
|
||||||
|
map -> PowerUsageAdvanced.this.onBatteryDiffDataMapUpdate(map));
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onLoadFinished(Loader<Map<Long, Map<String, BatteryHistEntry>>> loader,
|
public void onLoadFinished(Loader<BatteryLevelData> loader,
|
||||||
Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap) {
|
BatteryLevelData batteryLevelData) {
|
||||||
mBatteryHistoryMap = batteryHistoryMap;
|
PowerUsageAdvanced.this.onBatteryLevelDataUpdate(batteryLevelData);
|
||||||
PowerUsageAdvanced.this.onLoadFinished(mRefreshType);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onLoaderReset(Loader<Map<Long, Map<String, BatteryHistEntry>>> loader) {
|
public void onLoaderReset(Loader<BatteryLevelData> loader) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -32,7 +32,6 @@ import androidx.loader.content.Loader;
|
|||||||
|
|
||||||
import com.android.settings.dashboard.DashboardFragment;
|
import com.android.settings.dashboard.DashboardFragment;
|
||||||
import com.android.settings.fuelgauge.BatteryBroadcastReceiver;
|
import com.android.settings.fuelgauge.BatteryBroadcastReceiver;
|
||||||
import com.android.settings.fuelgauge.BatteryUtils;
|
|
||||||
|
|
||||||
import java.lang.annotation.Retention;
|
import java.lang.annotation.Retention;
|
||||||
import java.lang.annotation.RetentionPolicy;
|
import java.lang.annotation.RetentionPolicy;
|
||||||
@@ -63,14 +62,14 @@ public abstract class PowerUsageBase extends DashboardFragment {
|
|||||||
LoaderIndex.BATTERY_USAGE_STATS_LOADER,
|
LoaderIndex.BATTERY_USAGE_STATS_LOADER,
|
||||||
LoaderIndex.BATTERY_INFO_LOADER,
|
LoaderIndex.BATTERY_INFO_LOADER,
|
||||||
LoaderIndex.BATTERY_TIP_LOADER,
|
LoaderIndex.BATTERY_TIP_LOADER,
|
||||||
LoaderIndex.BATTERY_HISTORY_LOADER
|
LoaderIndex.BATTERY_LEVEL_DATA_LOADER
|
||||||
|
|
||||||
})
|
})
|
||||||
public @interface LoaderIndex {
|
public @interface LoaderIndex {
|
||||||
int BATTERY_USAGE_STATS_LOADER = 0;
|
int BATTERY_USAGE_STATS_LOADER = 0;
|
||||||
int BATTERY_INFO_LOADER = 1;
|
int BATTERY_INFO_LOADER = 1;
|
||||||
int BATTERY_TIP_LOADER = 2;
|
int BATTERY_TIP_LOADER = 2;
|
||||||
int BATTERY_HISTORY_LOADER = 3;
|
int BATTERY_LEVEL_DATA_LOADER = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -108,7 +107,7 @@ public abstract class PowerUsageBase extends DashboardFragment {
|
|||||||
protected void restartBatteryStatsLoader(int refreshType) {
|
protected void restartBatteryStatsLoader(int refreshType) {
|
||||||
final Bundle bundle = new Bundle();
|
final Bundle bundle = new Bundle();
|
||||||
bundle.putInt(KEY_REFRESH_TYPE, refreshType);
|
bundle.putInt(KEY_REFRESH_TYPE, refreshType);
|
||||||
bundle.putBoolean(KEY_INCLUDE_HISTORY, isBatteryHistoryNeeded());
|
bundle.putBoolean(KEY_INCLUDE_HISTORY, false);
|
||||||
restartLoader(LoaderIndex.BATTERY_USAGE_STATS_LOADER, bundle,
|
restartLoader(LoaderIndex.BATTERY_USAGE_STATS_LOADER, bundle,
|
||||||
mBatteryUsageStatsLoaderCallbacks);
|
mBatteryUsageStatsLoaderCallbacks);
|
||||||
}
|
}
|
||||||
@@ -137,14 +136,6 @@ public abstract class PowerUsageBase extends DashboardFragment {
|
|||||||
|
|
||||||
protected abstract void refreshUi(@BatteryUpdateType int refreshType);
|
protected abstract void refreshUi(@BatteryUpdateType int refreshType);
|
||||||
|
|
||||||
protected abstract boolean isBatteryHistoryNeeded();
|
|
||||||
|
|
||||||
protected void updatePreference(BatteryHistoryPreference historyPref) {
|
|
||||||
final long startTime = System.currentTimeMillis();
|
|
||||||
historyPref.setBatteryUsageStats(mBatteryUsageStats);
|
|
||||||
BatteryUtils.logRuntime(TAG, "updatePreference", startTime);
|
|
||||||
}
|
|
||||||
|
|
||||||
private class BatteryUsageStatsLoaderCallbacks
|
private class BatteryUsageStatsLoaderCallbacks
|
||||||
implements LoaderManager.LoaderCallbacks<BatteryUsageStats> {
|
implements LoaderManager.LoaderCallbacks<BatteryUsageStats> {
|
||||||
private int mRefreshType;
|
private int mRefreshType;
|
||||||
|
@@ -45,7 +45,6 @@ import com.android.settings.fuelgauge.batterytip.tips.BatteryTip;
|
|||||||
import com.android.settings.overlay.FeatureFactory;
|
import com.android.settings.overlay.FeatureFactory;
|
||||||
import com.android.settings.search.BaseSearchIndexProvider;
|
import com.android.settings.search.BaseSearchIndexProvider;
|
||||||
import com.android.settingslib.search.SearchIndexable;
|
import com.android.settingslib.search.SearchIndexable;
|
||||||
import com.android.settingslib.widget.LayoutPreference;
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@@ -69,8 +68,6 @@ public class PowerUsageSummary extends PowerUsageBase implements
|
|||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
BatteryUtils mBatteryUtils;
|
BatteryUtils mBatteryUtils;
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
LayoutPreference mBatteryLayoutPref;
|
|
||||||
@VisibleForTesting
|
|
||||||
BatteryInfo mBatteryInfo;
|
BatteryInfo mBatteryInfo;
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
@@ -208,11 +205,6 @@ public class PowerUsageSummary extends PowerUsageBase implements
|
|||||||
return R.string.help_url_battery;
|
return R.string.help_url_battery;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected boolean isBatteryHistoryNeeded() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void refreshUi(@BatteryUpdateType int refreshType) {
|
protected void refreshUi(@BatteryUpdateType int refreshType) {
|
||||||
final Context context = getContext();
|
final Context context = getContext();
|
||||||
if (context == null) {
|
if (context == null) {
|
||||||
@@ -239,11 +231,6 @@ public class PowerUsageSummary extends PowerUsageBase implements
|
|||||||
restartLoader(LoaderIndex.BATTERY_TIP_LOADER, Bundle.EMPTY, mBatteryTipsCallbacks);
|
restartLoader(LoaderIndex.BATTERY_TIP_LOADER, Bundle.EMPTY, mBatteryTipsCallbacks);
|
||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
|
||||||
void setBatteryLayoutPreference(LayoutPreference layoutPreference) {
|
|
||||||
mBatteryLayoutPref = layoutPreference;
|
|
||||||
}
|
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
void initFeatureProvider() {
|
void initFeatureProvider() {
|
||||||
final Context context = getContext();
|
final Context context = getContext();
|
||||||
|
@@ -36,9 +36,16 @@ public interface BatteryEventDao {
|
|||||||
@Query("SELECT * FROM BatteryEventEntity ORDER BY timestamp DESC")
|
@Query("SELECT * FROM BatteryEventEntity ORDER BY timestamp DESC")
|
||||||
List<BatteryEventEntity> getAll();
|
List<BatteryEventEntity> getAll();
|
||||||
|
|
||||||
|
/** Gets the {@link Cursor} of the last full charge time . */
|
||||||
|
@Query("SELECT MAX(timestamp) FROM BatteryEventEntity"
|
||||||
|
+ " WHERE batteryEventType = 3") // BatteryEventType.FULL_CHARGED = 3
|
||||||
|
Cursor getLastFullChargeTimestamp();
|
||||||
|
|
||||||
/** Gets the {@link Cursor} of all recorded data after a specific timestamp. */
|
/** Gets the {@link Cursor} of all recorded data after a specific timestamp. */
|
||||||
@Query("SELECT * FROM BatteryEventEntity WHERE timestamp > :timestamp ORDER BY timestamp DESC")
|
@Query("SELECT * FROM BatteryEventEntity"
|
||||||
Cursor getAllAfter(long timestamp);
|
+ " WHERE timestamp > :timestamp AND batteryEventType IN (:batteryEventTypes)"
|
||||||
|
+ " ORDER BY timestamp DESC")
|
||||||
|
Cursor getAllAfter(long timestamp, List<Integer> batteryEventTypes);
|
||||||
|
|
||||||
/** Deletes all recorded data before a specific timestamp. */
|
/** Deletes all recorded data before a specific timestamp. */
|
||||||
@Query("DELETE FROM BatteryEventEntity WHERE timestamp <= :timestamp")
|
@Query("DELETE FROM BatteryEventEntity WHERE timestamp <= :timestamp")
|
||||||
|
@@ -37,16 +37,18 @@ public interface BatteryStateDao {
|
|||||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||||
void insertAll(List<BatteryState> states);
|
void insertAll(List<BatteryState> states);
|
||||||
|
|
||||||
|
/** Gets the {@link Cursor} of the latest record timestamp no later than the given timestamp. */
|
||||||
|
@Query("SELECT MAX(timestamp) FROM BatteryState WHERE timestamp <= :timestamp")
|
||||||
|
Cursor getLatestTimestampBefore(long timestamp);
|
||||||
|
|
||||||
|
/** Lists all recorded battery states after a specific timestamp. */
|
||||||
|
@Query("SELECT * FROM BatteryState WHERE timestamp >= :timestamp ORDER BY timestamp ASC")
|
||||||
|
Cursor getBatteryStatesAfter(long timestamp);
|
||||||
|
|
||||||
/** Lists all recorded data after a specific timestamp. */
|
/** Lists all recorded data after a specific timestamp. */
|
||||||
@Query("SELECT * FROM BatteryState WHERE timestamp > :timestamp ORDER BY timestamp DESC")
|
@Query("SELECT * FROM BatteryState WHERE timestamp > :timestamp ORDER BY timestamp DESC")
|
||||||
List<BatteryState> getAllAfter(long timestamp);
|
List<BatteryState> getAllAfter(long timestamp);
|
||||||
|
|
||||||
/** Gets the {@link Cursor} of all recorded data since last full charge within 7 days. */
|
|
||||||
@Query("SELECT * FROM BatteryState WHERE timestamp >= :timestampSixDaysAgo AND timestamp >= "
|
|
||||||
+ "(SELECT IFNULL((SELECT MAX(timestamp) FROM BatteryState "
|
|
||||||
+ "WHERE isFullChargeCycleStart = 1), 0)) ORDER BY timestamp ASC")
|
|
||||||
Cursor getCursorSinceLastFullCharge(long timestampSixDaysAgo);
|
|
||||||
|
|
||||||
/** Get the count of distinct timestamp after a specific timestamp. */
|
/** Get the count of distinct timestamp after a specific timestamp. */
|
||||||
@Query("SELECT COUNT(DISTINCT timestamp) FROM BatteryState WHERE timestamp > :timestamp")
|
@Query("SELECT COUNT(DISTINCT timestamp) FROM BatteryState WHERE timestamp > :timestamp")
|
||||||
int getDistinctTimestampCount(long timestamp);
|
int getDistinctTimestampCount(long timestamp);
|
||||||
|
@@ -25,7 +25,8 @@ import androidx.room.RoomDatabase;
|
|||||||
|
|
||||||
/** A {@link RoomDatabase} for battery usage states history. */
|
/** A {@link RoomDatabase} for battery usage states history. */
|
||||||
@Database(
|
@Database(
|
||||||
entities = {AppUsageEventEntity.class, BatteryEventEntity.class, BatteryState.class},
|
entities = {AppUsageEventEntity.class, BatteryEventEntity.class, BatteryState.class,
|
||||||
|
BatteryUsageSlotEntity.class},
|
||||||
version = 1)
|
version = 1)
|
||||||
public abstract class BatteryStateDatabase extends RoomDatabase {
|
public abstract class BatteryStateDatabase extends RoomDatabase {
|
||||||
private static final String TAG = "BatteryStateDatabase";
|
private static final String TAG = "BatteryStateDatabase";
|
||||||
@@ -38,13 +39,15 @@ public abstract class BatteryStateDatabase extends RoomDatabase {
|
|||||||
public abstract BatteryEventDao batteryEventDao();
|
public abstract BatteryEventDao batteryEventDao();
|
||||||
/** Provides DAO for battery state table. */
|
/** Provides DAO for battery state table. */
|
||||||
public abstract BatteryStateDao batteryStateDao();
|
public abstract BatteryStateDao batteryStateDao();
|
||||||
|
/** Provides DAO for battery usage slot table. */
|
||||||
|
public abstract BatteryUsageSlotDao batteryUsageSlotDao();
|
||||||
|
|
||||||
/** Gets or creates an instance of {@link RoomDatabase}. */
|
/** Gets or creates an instance of {@link RoomDatabase}. */
|
||||||
public static BatteryStateDatabase getInstance(Context context) {
|
public static BatteryStateDatabase getInstance(Context context) {
|
||||||
if (sBatteryStateDatabase == null) {
|
if (sBatteryStateDatabase == null) {
|
||||||
sBatteryStateDatabase =
|
sBatteryStateDatabase =
|
||||||
Room.databaseBuilder(
|
Room.databaseBuilder(
|
||||||
context, BatteryStateDatabase.class, "battery-usage-db-v8")
|
context, BatteryStateDatabase.class, "battery-usage-db-v9")
|
||||||
// Allows accessing data in the main thread for dumping bugreport.
|
// Allows accessing data in the main thread for dumping bugreport.
|
||||||
.allowMainThreadQueries()
|
.allowMainThreadQueries()
|
||||||
.fallbackToDestructiveMigration()
|
.fallbackToDestructiveMigration()
|
||||||
|
@@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2023 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.db;
|
||||||
|
|
||||||
|
import android.database.Cursor;
|
||||||
|
|
||||||
|
import androidx.room.Dao;
|
||||||
|
import androidx.room.Insert;
|
||||||
|
import androidx.room.OnConflictStrategy;
|
||||||
|
import androidx.room.Query;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/** Data access object for accessing {@link BatteryUsageSlotEntity} in the database. */
|
||||||
|
@Dao
|
||||||
|
public interface BatteryUsageSlotDao {
|
||||||
|
/** Inserts a {@link BatteryUsageSlotEntity} data into the database. */
|
||||||
|
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||||
|
void insert(BatteryUsageSlotEntity event);
|
||||||
|
|
||||||
|
/** Gets all recorded data. */
|
||||||
|
@Query("SELECT * FROM BatteryUsageSlotEntity ORDER BY timestamp ASC")
|
||||||
|
List<BatteryUsageSlotEntity> getAll();
|
||||||
|
|
||||||
|
/** Gets the {@link Cursor} of all recorded data after a specific timestamp. */
|
||||||
|
@Query("SELECT * FROM BatteryUsageSlotEntity WHERE timestamp >= :timestamp"
|
||||||
|
+ " ORDER BY timestamp ASC")
|
||||||
|
Cursor getAllAfter(long timestamp);
|
||||||
|
|
||||||
|
/** Deletes all recorded data before a specific timestamp. */
|
||||||
|
@Query("DELETE FROM BatteryUsageSlotEntity WHERE timestamp <= :timestamp")
|
||||||
|
void clearAllBefore(long timestamp);
|
||||||
|
|
||||||
|
/** Clears all recorded data in the database. */
|
||||||
|
@Query("DELETE FROM BatteryUsageSlotEntity")
|
||||||
|
void clearAll();
|
||||||
|
}
|
@@ -0,0 +1,112 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2023 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.db;
|
||||||
|
|
||||||
|
import android.content.ContentValues;
|
||||||
|
|
||||||
|
import androidx.room.Entity;
|
||||||
|
import androidx.room.PrimaryKey;
|
||||||
|
|
||||||
|
import com.android.settings.fuelgauge.batteryusage.ConvertUtils;
|
||||||
|
|
||||||
|
import com.google.errorprone.annotations.CanIgnoreReturnValue;
|
||||||
|
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
|
/** A {@link Entity} class to save battery usage slot into database. */
|
||||||
|
@Entity
|
||||||
|
public class BatteryUsageSlotEntity {
|
||||||
|
/** Keys for accessing {@link ContentValues}. */
|
||||||
|
public static final String KEY_TIMESTAMP = "timestamp";
|
||||||
|
public static final String KEY_BATTERY_USAGE_SLOT = "batteryUsageSlot";
|
||||||
|
|
||||||
|
@PrimaryKey(autoGenerate = true)
|
||||||
|
private long mId;
|
||||||
|
|
||||||
|
public final long timestamp;
|
||||||
|
public final String batteryUsageSlot;
|
||||||
|
|
||||||
|
public BatteryUsageSlotEntity(final long timestamp, final String batteryUsageSlot) {
|
||||||
|
this.timestamp = timestamp;
|
||||||
|
this.batteryUsageSlot = batteryUsageSlot;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Sets the auto-generated content ID. */
|
||||||
|
public void setId(long id) {
|
||||||
|
this.mId = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Gets the auto-generated content ID. */
|
||||||
|
public long getId() {
|
||||||
|
return mId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
final String recordAtDateTime = ConvertUtils.utcToLocalTimeForLogging(timestamp);
|
||||||
|
final StringBuilder builder = new StringBuilder()
|
||||||
|
.append("\nBatteryUsageSlot{")
|
||||||
|
.append(String.format(Locale.US, "\n\ttimestamp=%s|batteryUsageSlot=%s",
|
||||||
|
recordAtDateTime, batteryUsageSlot))
|
||||||
|
.append("\n}");
|
||||||
|
return builder.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Creates new {@link BatteryUsageSlotEntity} from {@link ContentValues}. */
|
||||||
|
public static BatteryUsageSlotEntity create(ContentValues contentValues) {
|
||||||
|
Builder builder = BatteryUsageSlotEntity.newBuilder();
|
||||||
|
if (contentValues.containsKey(KEY_TIMESTAMP)) {
|
||||||
|
builder.setTimestamp(contentValues.getAsLong(KEY_TIMESTAMP));
|
||||||
|
}
|
||||||
|
if (contentValues.containsKey(KEY_BATTERY_USAGE_SLOT)) {
|
||||||
|
builder.setBatteryUsageSlot(contentValues.getAsString(KEY_BATTERY_USAGE_SLOT));
|
||||||
|
}
|
||||||
|
return builder.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Creates a new {@link Builder} instance. */
|
||||||
|
public static Builder newBuilder() {
|
||||||
|
return new Builder();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** A convenience builder class to improve readability. */
|
||||||
|
public static class Builder {
|
||||||
|
private long mTimestamp;
|
||||||
|
private String mBatteryUsageSlot;
|
||||||
|
|
||||||
|
/** Sets the timestamp. */
|
||||||
|
@CanIgnoreReturnValue
|
||||||
|
public Builder setTimestamp(final long timestamp) {
|
||||||
|
mTimestamp = timestamp;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Sets the battery usage slot. */
|
||||||
|
@CanIgnoreReturnValue
|
||||||
|
public Builder setBatteryUsageSlot(final String batteryUsageSlot) {
|
||||||
|
mBatteryUsageSlot = batteryUsageSlot;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Builds the {@link BatteryUsageSlotEntity}. */
|
||||||
|
public BatteryUsageSlotEntity build() {
|
||||||
|
return new BatteryUsageSlotEntity(mTimestamp, mBatteryUsageSlot);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Builder() {}
|
||||||
|
}
|
||||||
|
}
|
@@ -23,6 +23,14 @@ java_library {
|
|||||||
srcs: ["battery_event.proto"],
|
srcs: ["battery_event.proto"],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
java_library {
|
||||||
|
name: "battery-usage-slot-protos-lite",
|
||||||
|
proto: {
|
||||||
|
type: "lite",
|
||||||
|
},
|
||||||
|
srcs: ["battery_usage_slot.proto"],
|
||||||
|
}
|
||||||
|
|
||||||
java_library {
|
java_library {
|
||||||
name: "fuelgauge-usage-state-protos-lite",
|
name: "fuelgauge-usage-state-protos-lite",
|
||||||
proto: {
|
proto: {
|
||||||
|
@@ -8,6 +8,8 @@ enum BatteryEventType {
|
|||||||
UNKNOWN_EVENT = 0;
|
UNKNOWN_EVENT = 0;
|
||||||
POWER_CONNECTED = 1;
|
POWER_CONNECTED = 1;
|
||||||
POWER_DISCONNECTED = 2;
|
POWER_DISCONNECTED = 2;
|
||||||
|
FULL_CHARGED = 3;
|
||||||
|
EVEN_HOUR = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
message BatteryEvent {
|
message BatteryEvent {
|
||||||
|
@@ -0,0 +1,32 @@
|
|||||||
|
syntax = "proto2";
|
||||||
|
|
||||||
|
option java_multiple_files = true;
|
||||||
|
option java_package = "com.android.settings.fuelgauge.batteryusage";
|
||||||
|
option java_outer_classname = "BatteryUsageSlotProto";
|
||||||
|
|
||||||
|
message BatteryUsageSlot {
|
||||||
|
optional int64 start_timestamp = 1;
|
||||||
|
optional int64 end_timestamp = 2;
|
||||||
|
optional int32 start_battery_level = 3;
|
||||||
|
optional int32 end_battery_level = 4;
|
||||||
|
optional int64 screen_on_time = 5;
|
||||||
|
repeated BatteryUsageDiff app_usage = 6;
|
||||||
|
repeated BatteryUsageDiff system_usage = 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
message BatteryUsageDiff {
|
||||||
|
optional int64 uid = 1;
|
||||||
|
optional int64 user_id = 2;
|
||||||
|
optional string package_name = 3;
|
||||||
|
optional string label = 4;
|
||||||
|
optional string key = 5;
|
||||||
|
optional bool is_hidden = 6;
|
||||||
|
optional int32 component_id = 7;
|
||||||
|
optional int32 consumer_type = 8;
|
||||||
|
optional double consume_power = 9;
|
||||||
|
optional double foreground_usage_consume_power = 10;
|
||||||
|
optional double background_usage_consume_power = 11;
|
||||||
|
optional int64 foreground_usage_time = 12;
|
||||||
|
optional int64 background_usage_time = 13;
|
||||||
|
optional int64 screen_on_time = 14;
|
||||||
|
}
|
@@ -1,102 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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 static org.mockito.ArgumentMatchers.any;
|
|
||||||
import static org.mockito.Mockito.doReturn;
|
|
||||||
import static org.mockito.Mockito.spy;
|
|
||||||
import static org.mockito.Mockito.verify;
|
|
||||||
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
|
||||||
|
|
||||||
import android.content.ContentResolver;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.os.UserManager;
|
|
||||||
|
|
||||||
import org.junit.Before;
|
|
||||||
import org.junit.Test;
|
|
||||||
import org.junit.runner.RunWith;
|
|
||||||
import org.mockito.Mock;
|
|
||||||
import org.mockito.MockitoAnnotations;
|
|
||||||
import org.robolectric.RobolectricTestRunner;
|
|
||||||
import org.robolectric.RuntimeEnvironment;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
@RunWith(RobolectricTestRunner.class)
|
|
||||||
public final class AppUsageDataLoaderTest {
|
|
||||||
private Context mContext;
|
|
||||||
@Mock
|
|
||||||
private ContentResolver mMockContentResolver;
|
|
||||||
@Mock
|
|
||||||
private UserManager mUserManager;
|
|
||||||
|
|
||||||
@Before
|
|
||||||
public void setUp() {
|
|
||||||
MockitoAnnotations.initMocks(this);
|
|
||||||
mContext = spy(RuntimeEnvironment.application);
|
|
||||||
doReturn(mContext).when(mContext).getApplicationContext();
|
|
||||||
doReturn(mMockContentResolver).when(mContext).getContentResolver();
|
|
||||||
doReturn(mUserManager).when(mContext).getSystemService(UserManager.class);
|
|
||||||
doReturn(new Intent()).when(mContext).registerReceiver(any(), any());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void loadAppUsageData_withData_insertFakeDataIntoProvider() {
|
|
||||||
final List<AppUsageEvent> AppUsageEventList = new ArrayList<>();
|
|
||||||
final AppUsageEvent appUsageEvent = AppUsageEvent.newBuilder().setUid(0).build();
|
|
||||||
AppUsageEventList.add(appUsageEvent);
|
|
||||||
AppUsageDataLoader.sFakeAppUsageEventsSupplier = () -> new HashMap<>();
|
|
||||||
AppUsageDataLoader.sFakeUsageEventsListSupplier = () -> AppUsageEventList;
|
|
||||||
|
|
||||||
AppUsageDataLoader.loadAppUsageData(mContext);
|
|
||||||
|
|
||||||
verify(mMockContentResolver).bulkInsert(any(), any());
|
|
||||||
verify(mMockContentResolver).notifyChange(any(), any());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void loadAppUsageData_nullAppUsageEvents_notInsertDataIntoProvider() {
|
|
||||||
AppUsageDataLoader.sFakeAppUsageEventsSupplier = () -> null;
|
|
||||||
|
|
||||||
AppUsageDataLoader.loadAppUsageData(mContext);
|
|
||||||
|
|
||||||
verifyNoMoreInteractions(mMockContentResolver);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void loadAppUsageData_nullUsageEventsList_notInsertDataIntoProvider() {
|
|
||||||
AppUsageDataLoader.sFakeAppUsageEventsSupplier = () -> new HashMap<>();
|
|
||||||
AppUsageDataLoader.sFakeUsageEventsListSupplier = () -> null;
|
|
||||||
|
|
||||||
AppUsageDataLoader.loadAppUsageData(mContext);
|
|
||||||
|
|
||||||
verifyNoMoreInteractions(mMockContentResolver);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void loadAppUsageData_emptyUsageEventsList_notInsertDataIntoProvider() {
|
|
||||||
AppUsageDataLoader.sFakeAppUsageEventsSupplier = () -> new HashMap<>();
|
|
||||||
AppUsageDataLoader.sFakeUsageEventsListSupplier = () -> new ArrayList<>();
|
|
||||||
|
|
||||||
AppUsageDataLoader.loadAppUsageData(mContext);
|
|
||||||
|
|
||||||
verifyNoMoreInteractions(mMockContentResolver);
|
|
||||||
}
|
|
||||||
}
|
|
@@ -16,6 +16,8 @@
|
|||||||
|
|
||||||
package com.android.settings.fuelgauge.batteryusage;
|
package com.android.settings.fuelgauge.batteryusage;
|
||||||
|
|
||||||
|
import static com.android.settings.fuelgauge.batteryusage.BatteryChartViewModel.SELECTED_INDEX_ALL;
|
||||||
|
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
import static org.mockito.ArgumentMatchers.anyFloat;
|
import static org.mockito.ArgumentMatchers.anyFloat;
|
||||||
@@ -30,7 +32,6 @@ import static org.mockito.Mockito.reset;
|
|||||||
import static org.mockito.Mockito.spy;
|
import static org.mockito.Mockito.spy;
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
|
|
||||||
import android.content.ContentValues;
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
@@ -39,6 +40,7 @@ import android.os.Bundle;
|
|||||||
import android.os.LocaleList;
|
import android.os.LocaleList;
|
||||||
import android.os.UserManager;
|
import android.os.UserManager;
|
||||||
import android.text.format.DateUtils;
|
import android.text.format.DateUtils;
|
||||||
|
import android.util.ArrayMap;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewPropertyAnimator;
|
import android.view.ViewPropertyAnimator;
|
||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
@@ -54,7 +56,6 @@ import org.mockito.MockitoAnnotations;
|
|||||||
import org.robolectric.RobolectricTestRunner;
|
import org.robolectric.RobolectricTestRunner;
|
||||||
import org.robolectric.RuntimeEnvironment;
|
import org.robolectric.RuntimeEnvironment;
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -112,6 +113,7 @@ public final class BatteryChartPreferenceControllerTest {
|
|||||||
mBatteryChartPreferenceController.mPrefContext = mContext;
|
mBatteryChartPreferenceController.mPrefContext = mContext;
|
||||||
mBatteryChartPreferenceController.mDailyChartView = mDailyChartView;
|
mBatteryChartPreferenceController.mDailyChartView = mDailyChartView;
|
||||||
mBatteryChartPreferenceController.mHourlyChartView = mHourlyChartView;
|
mBatteryChartPreferenceController.mHourlyChartView = mHourlyChartView;
|
||||||
|
BatteryDiffEntry.clearCache();
|
||||||
// Adds fake testing data.
|
// Adds fake testing data.
|
||||||
BatteryDiffEntry.sResourceCache.put(
|
BatteryDiffEntry.sResourceCache.put(
|
||||||
"fakeBatteryDiffEntryKey",
|
"fakeBatteryDiffEntryKey",
|
||||||
@@ -144,7 +146,7 @@ public final class BatteryChartPreferenceControllerTest {
|
|||||||
reset(mHourlyChartView);
|
reset(mHourlyChartView);
|
||||||
setupHourlyChartViewAnimationMock();
|
setupHourlyChartViewAnimationMock();
|
||||||
|
|
||||||
mBatteryChartPreferenceController.setBatteryHistoryMap(createBatteryHistoryMap(6));
|
mBatteryChartPreferenceController.onBatteryLevelDataUpdate(createBatteryLevelData(6));
|
||||||
|
|
||||||
verify(mDailyChartView, atLeastOnce()).setVisibility(View.GONE);
|
verify(mDailyChartView, atLeastOnce()).setVisibility(View.GONE);
|
||||||
// Ignore fast refresh ui from the data processor callback.
|
// Ignore fast refresh ui from the data processor callback.
|
||||||
@@ -176,16 +178,18 @@ public final class BatteryChartPreferenceControllerTest {
|
|||||||
BatteryChartViewModel.AxisLabelPosition.CENTER_OF_TRAPEZOIDS,
|
BatteryChartViewModel.AxisLabelPosition.CENTER_OF_TRAPEZOIDS,
|
||||||
mBatteryChartPreferenceController.mDailyChartLabelTextGenerator);
|
mBatteryChartPreferenceController.mDailyChartLabelTextGenerator);
|
||||||
|
|
||||||
mBatteryChartPreferenceController.setBatteryHistoryMap(createBatteryHistoryMap(60));
|
mBatteryChartPreferenceController.onBatteryLevelDataUpdate(createBatteryLevelData(60));
|
||||||
|
mBatteryChartPreferenceController.onBatteryUsageMapUpdate(getEmptyBatteryUsageMap());
|
||||||
|
|
||||||
verify(mDailyChartView, atLeastOnce()).setVisibility(View.VISIBLE);
|
verify(mDailyChartView, atLeastOnce()).setVisibility(View.VISIBLE);
|
||||||
verify(mViewPropertyAnimator, atLeastOnce()).alpha(0f);
|
verify(mViewPropertyAnimator, atLeastOnce()).alpha(0f);
|
||||||
verify(mDailyChartView).setViewModel(expectedDailyViewModel);
|
verify(mDailyChartView, atLeastOnce()).setViewModel(expectedDailyViewModel);
|
||||||
|
|
||||||
reset(mDailyChartView);
|
reset(mDailyChartView);
|
||||||
reset(mHourlyChartView);
|
reset(mHourlyChartView);
|
||||||
setupHourlyChartViewAnimationMock();
|
setupHourlyChartViewAnimationMock();
|
||||||
doReturn(mLayoutParams).when(mDailyChartView).getLayoutParams();
|
doReturn(mLayoutParams).when(mDailyChartView).getLayoutParams();
|
||||||
|
doReturn(View.GONE).when(mHourlyChartView).getVisibility();
|
||||||
mBatteryChartPreferenceController.mDailyChartIndex = 0;
|
mBatteryChartPreferenceController.mDailyChartIndex = 0;
|
||||||
mBatteryChartPreferenceController.refreshUi();
|
mBatteryChartPreferenceController.refreshUi();
|
||||||
verify(mDailyChartView).setVisibility(View.VISIBLE);
|
verify(mDailyChartView).setVisibility(View.VISIBLE);
|
||||||
@@ -245,8 +249,7 @@ public final class BatteryChartPreferenceControllerTest {
|
|||||||
setupHourlyChartViewAnimationMock();
|
setupHourlyChartViewAnimationMock();
|
||||||
doReturn(mLayoutParams).when(mDailyChartView).getLayoutParams();
|
doReturn(mLayoutParams).when(mDailyChartView).getLayoutParams();
|
||||||
mBatteryChartPreferenceController.mDailyChartIndex = 2;
|
mBatteryChartPreferenceController.mDailyChartIndex = 2;
|
||||||
mBatteryChartPreferenceController.mHourlyChartIndex =
|
mBatteryChartPreferenceController.mHourlyChartIndex = SELECTED_INDEX_ALL;
|
||||||
BatteryChartViewModel.SELECTED_INDEX_ALL;
|
|
||||||
mBatteryChartPreferenceController.refreshUi();
|
mBatteryChartPreferenceController.refreshUi();
|
||||||
verify(mDailyChartView).setVisibility(View.VISIBLE);
|
verify(mDailyChartView).setVisibility(View.VISIBLE);
|
||||||
verify(mViewPropertyAnimator, atLeastOnce()).alpha(1f);
|
verify(mViewPropertyAnimator, atLeastOnce()).alpha(1f);
|
||||||
@@ -272,13 +275,15 @@ public final class BatteryChartPreferenceControllerTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void refreshUi_normalCase_returnTrue() {
|
public void refreshUi_normalCase_returnTrue() {
|
||||||
mBatteryChartPreferenceController.setBatteryHistoryMap(createBatteryHistoryMap(6));
|
mBatteryChartPreferenceController.onBatteryLevelDataUpdate(createBatteryLevelData(6));
|
||||||
|
mBatteryChartPreferenceController.onBatteryUsageMapUpdate(getEmptyBatteryUsageMap());
|
||||||
assertThat(mBatteryChartPreferenceController.refreshUi()).isTrue();
|
assertThat(mBatteryChartPreferenceController.refreshUi()).isTrue();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void refreshUi_batteryIndexedMapIsNull_returnTrue() {
|
public void refreshUi_batteryIndexedMapIsNull_returnTrue() {
|
||||||
mBatteryChartPreferenceController.setBatteryHistoryMap(null);
|
mBatteryChartPreferenceController.onBatteryLevelDataUpdate(null);
|
||||||
|
mBatteryChartPreferenceController.onBatteryUsageMapUpdate(getEmptyBatteryUsageMap());
|
||||||
assertThat(mBatteryChartPreferenceController.refreshUi()).isTrue();
|
assertThat(mBatteryChartPreferenceController.refreshUi()).isTrue();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -296,38 +301,34 @@ public final class BatteryChartPreferenceControllerTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void selectedSlotText_selectAllDaysAllHours_returnNull() {
|
public void selectedSlotText_selectAllDaysAllHours_returnNull() {
|
||||||
mBatteryChartPreferenceController.setBatteryHistoryMap(createBatteryHistoryMap(60));
|
mBatteryChartPreferenceController.onBatteryLevelDataUpdate(createBatteryLevelData(60));
|
||||||
mBatteryChartPreferenceController.mDailyChartIndex =
|
mBatteryChartPreferenceController.mDailyChartIndex = SELECTED_INDEX_ALL;
|
||||||
BatteryChartViewModel.SELECTED_INDEX_ALL;
|
mBatteryChartPreferenceController.mHourlyChartIndex = SELECTED_INDEX_ALL;
|
||||||
mBatteryChartPreferenceController.mHourlyChartIndex =
|
|
||||||
BatteryChartViewModel.SELECTED_INDEX_ALL;
|
|
||||||
|
|
||||||
assertThat(mBatteryChartPreferenceController.getSlotInformation()).isEqualTo(null);
|
assertThat(mBatteryChartPreferenceController.getSlotInformation()).isEqualTo(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void selectedSlotText_onlyOneDayDataSelectAllHours_returnNull() {
|
public void selectedSlotText_onlyOneDayDataSelectAllHours_returnNull() {
|
||||||
mBatteryChartPreferenceController.setBatteryHistoryMap(createBatteryHistoryMap(6));
|
mBatteryChartPreferenceController.onBatteryLevelDataUpdate(createBatteryLevelData(6));
|
||||||
mBatteryChartPreferenceController.mDailyChartIndex = 0;
|
mBatteryChartPreferenceController.mDailyChartIndex = 0;
|
||||||
mBatteryChartPreferenceController.mHourlyChartIndex =
|
mBatteryChartPreferenceController.mHourlyChartIndex = SELECTED_INDEX_ALL;
|
||||||
BatteryChartViewModel.SELECTED_INDEX_ALL;
|
|
||||||
|
|
||||||
assertThat(mBatteryChartPreferenceController.getSlotInformation()).isEqualTo(null);
|
assertThat(mBatteryChartPreferenceController.getSlotInformation()).isEqualTo(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void selectedSlotText_selectADayAllHours_onlyDayText() {
|
public void selectedSlotText_selectADayAllHours_onlyDayText() {
|
||||||
mBatteryChartPreferenceController.setBatteryHistoryMap(createBatteryHistoryMap(60));
|
mBatteryChartPreferenceController.onBatteryLevelDataUpdate(createBatteryLevelData(60));
|
||||||
mBatteryChartPreferenceController.mDailyChartIndex = 1;
|
mBatteryChartPreferenceController.mDailyChartIndex = 1;
|
||||||
mBatteryChartPreferenceController.mHourlyChartIndex =
|
mBatteryChartPreferenceController.mHourlyChartIndex = SELECTED_INDEX_ALL;
|
||||||
BatteryChartViewModel.SELECTED_INDEX_ALL;
|
|
||||||
|
|
||||||
assertThat(mBatteryChartPreferenceController.getSlotInformation()).isEqualTo("Sunday");
|
assertThat(mBatteryChartPreferenceController.getSlotInformation()).isEqualTo("Sunday");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void selectedSlotText_onlyOneDayDataSelectAnHour_onlyHourText() {
|
public void selectedSlotText_onlyOneDayDataSelectAnHour_onlyHourText() {
|
||||||
mBatteryChartPreferenceController.setBatteryHistoryMap(createBatteryHistoryMap(6));
|
mBatteryChartPreferenceController.onBatteryLevelDataUpdate(createBatteryLevelData(6));
|
||||||
mBatteryChartPreferenceController.mDailyChartIndex = 0;
|
mBatteryChartPreferenceController.mDailyChartIndex = 0;
|
||||||
mBatteryChartPreferenceController.mHourlyChartIndex = 2;
|
mBatteryChartPreferenceController.mHourlyChartIndex = 2;
|
||||||
|
|
||||||
@@ -337,7 +338,7 @@ public final class BatteryChartPreferenceControllerTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void selectedSlotText_SelectADayAnHour_dayAndHourText() {
|
public void selectedSlotText_SelectADayAnHour_dayAndHourText() {
|
||||||
mBatteryChartPreferenceController.setBatteryHistoryMap(createBatteryHistoryMap(60));
|
mBatteryChartPreferenceController.onBatteryLevelDataUpdate(createBatteryLevelData(60));
|
||||||
mBatteryChartPreferenceController.mDailyChartIndex = 1;
|
mBatteryChartPreferenceController.mDailyChartIndex = 1;
|
||||||
mBatteryChartPreferenceController.mHourlyChartIndex = 8;
|
mBatteryChartPreferenceController.mHourlyChartIndex = 8;
|
||||||
|
|
||||||
@@ -347,7 +348,7 @@ public final class BatteryChartPreferenceControllerTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void selectedSlotText_selectFirstSlot_withMinuteText() {
|
public void selectedSlotText_selectFirstSlot_withMinuteText() {
|
||||||
mBatteryChartPreferenceController.setBatteryHistoryMap(createBatteryHistoryMap(6));
|
mBatteryChartPreferenceController.onBatteryLevelDataUpdate(createBatteryLevelData(6));
|
||||||
mBatteryChartPreferenceController.mDailyChartIndex = 0;
|
mBatteryChartPreferenceController.mDailyChartIndex = 0;
|
||||||
mBatteryChartPreferenceController.mHourlyChartIndex = 0;
|
mBatteryChartPreferenceController.mHourlyChartIndex = 0;
|
||||||
|
|
||||||
@@ -357,7 +358,7 @@ public final class BatteryChartPreferenceControllerTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void selectedSlotText_selectLastSlot_withNowText() {
|
public void selectedSlotText_selectLastSlot_withNowText() {
|
||||||
mBatteryChartPreferenceController.setBatteryHistoryMap(createBatteryHistoryMap(6));
|
mBatteryChartPreferenceController.onBatteryLevelDataUpdate(createBatteryLevelData(6));
|
||||||
mBatteryChartPreferenceController.mDailyChartIndex = 0;
|
mBatteryChartPreferenceController.mDailyChartIndex = 0;
|
||||||
mBatteryChartPreferenceController.mHourlyChartIndex = 3;
|
mBatteryChartPreferenceController.mHourlyChartIndex = 3;
|
||||||
|
|
||||||
@@ -367,7 +368,7 @@ public final class BatteryChartPreferenceControllerTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void selectedSlotText_selectOnlySlot_withMinuteAndNowText() {
|
public void selectedSlotText_selectOnlySlot_withMinuteAndNowText() {
|
||||||
mBatteryChartPreferenceController.setBatteryHistoryMap(createBatteryHistoryMap(1));
|
mBatteryChartPreferenceController.onBatteryLevelDataUpdate(createBatteryLevelData(1));
|
||||||
mBatteryChartPreferenceController.mDailyChartIndex = 0;
|
mBatteryChartPreferenceController.mDailyChartIndex = 0;
|
||||||
mBatteryChartPreferenceController.mHourlyChartIndex = 0;
|
mBatteryChartPreferenceController.mHourlyChartIndex = 0;
|
||||||
|
|
||||||
@@ -388,7 +389,7 @@ public final class BatteryChartPreferenceControllerTest {
|
|||||||
mBatteryChartPreferenceController.mHourlyChartIndex = -1;
|
mBatteryChartPreferenceController.mHourlyChartIndex = -1;
|
||||||
|
|
||||||
mBatteryChartPreferenceController.onCreate(bundle);
|
mBatteryChartPreferenceController.onCreate(bundle);
|
||||||
mBatteryChartPreferenceController.setBatteryHistoryMap(createBatteryHistoryMap(25));
|
mBatteryChartPreferenceController.onBatteryLevelDataUpdate(createBatteryLevelData(25));
|
||||||
|
|
||||||
assertThat(mBatteryChartPreferenceController.mDailyChartIndex)
|
assertThat(mBatteryChartPreferenceController.mDailyChartIndex)
|
||||||
.isEqualTo(expectedDailyIndex);
|
.isEqualTo(expectedDailyIndex);
|
||||||
@@ -398,9 +399,7 @@ public final class BatteryChartPreferenceControllerTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getTotalHours_getExpectedResult() {
|
public void getTotalHours_getExpectedResult() {
|
||||||
Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap = createBatteryHistoryMap(60);
|
BatteryLevelData batteryLevelData = createBatteryLevelData(60);
|
||||||
BatteryLevelData batteryLevelData =
|
|
||||||
DataProcessManager.getBatteryLevelData(mContext, null, batteryHistoryMap, null);
|
|
||||||
|
|
||||||
final int totalHour = BatteryChartPreferenceController.getTotalHours(batteryLevelData);
|
final int totalHour = BatteryChartPreferenceController.getTotalHours(batteryLevelData);
|
||||||
|
|
||||||
@@ -413,37 +412,26 @@ public final class BatteryChartPreferenceControllerTest {
|
|||||||
return 1619247600000L + index * DateUtils.HOUR_IN_MILLIS;
|
return 1619247600000L + index * DateUtils.HOUR_IN_MILLIS;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Map<Long, Map<String, BatteryHistEntry>> createBatteryHistoryMap(
|
private static BatteryLevelData createBatteryLevelData(int numOfHours) {
|
||||||
int numOfHours) {
|
Map<Long, Integer> batteryLevelMap = new ArrayMap<>();
|
||||||
final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap = new HashMap<>();
|
for (int index = 0; index < numOfHours; index += 2) {
|
||||||
for (int index = 0; index < numOfHours; index++) {
|
final Integer level = 100 - index;
|
||||||
final ContentValues values = new ContentValues();
|
Long timestamp = generateTimestamp(index);
|
||||||
final DeviceBatteryState deviceBatteryState =
|
|
||||||
DeviceBatteryState
|
|
||||||
.newBuilder()
|
|
||||||
.setBatteryLevel(100 - index)
|
|
||||||
.build();
|
|
||||||
final BatteryInformation batteryInformation =
|
|
||||||
BatteryInformation
|
|
||||||
.newBuilder()
|
|
||||||
.setDeviceBatteryState(deviceBatteryState)
|
|
||||||
.setConsumePower(100 - index)
|
|
||||||
.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<String, BatteryHistEntry> entryMap = new HashMap<>();
|
|
||||||
entryMap.put("fake_entry_key" + index, entry);
|
|
||||||
long timestamp = generateTimestamp(index);
|
|
||||||
if (index == 0) {
|
if (index == 0) {
|
||||||
timestamp += DateUtils.MINUTE_IN_MILLIS;
|
timestamp += DateUtils.MINUTE_IN_MILLIS;
|
||||||
|
index--;
|
||||||
}
|
}
|
||||||
batteryHistoryMap.put(timestamp, entryMap);
|
batteryLevelMap.put(timestamp, level);
|
||||||
}
|
}
|
||||||
DataProcessor.sTestCurrentTimeMillis =
|
long current = generateTimestamp(numOfHours - 1) + DateUtils.MINUTE_IN_MILLIS * 2;
|
||||||
generateTimestamp(numOfHours - 1) + DateUtils.MINUTE_IN_MILLIS * 2;
|
batteryLevelMap.put(current, 66);
|
||||||
return batteryHistoryMap;
|
DataProcessor.sTestCurrentTimeMillis = current;
|
||||||
|
return new BatteryLevelData(batteryLevelMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Map<Integer, Map<Integer, BatteryDiffData>> getEmptyBatteryUsageMap() {
|
||||||
|
return Map.of(SELECTED_INDEX_ALL, Map.of(SELECTED_INDEX_ALL, new BatteryDiffData(
|
||||||
|
null, 0, 0, 0, 0, 0, List.of(), List.of(), Set.of(), Set.of(), false)));
|
||||||
}
|
}
|
||||||
|
|
||||||
private BatteryChartPreferenceController createController() {
|
private BatteryChartPreferenceController createController() {
|
||||||
|
@@ -147,6 +147,14 @@ public class BatteryDiffDataTest {
|
|||||||
/*foregroundUsageTimeInMs=*/ 0L, /*backgroundUsageTimeInMs=*/ 0L, isHidden);
|
/*foregroundUsageTimeInMs=*/ 0L, /*backgroundUsageTimeInMs=*/ 0L, isHidden);
|
||||||
return new BatteryDiffEntry(
|
return new BatteryDiffEntry(
|
||||||
context,
|
context,
|
||||||
|
batteryHistEntry.mUid,
|
||||||
|
batteryHistEntry.mUserId,
|
||||||
|
batteryHistEntry.getKey(),
|
||||||
|
batteryHistEntry.mIsHidden,
|
||||||
|
batteryHistEntry.mDrainType,
|
||||||
|
batteryHistEntry.mPackageName,
|
||||||
|
batteryHistEntry.mAppLabel,
|
||||||
|
batteryHistEntry.mConsumerType,
|
||||||
/*foregroundUsageTimeInMs=*/ 0,
|
/*foregroundUsageTimeInMs=*/ 0,
|
||||||
/*backgroundUsageTimeInMs=*/ 0,
|
/*backgroundUsageTimeInMs=*/ 0,
|
||||||
/*screenOnTimeInMs=*/ 0,
|
/*screenOnTimeInMs=*/ 0,
|
||||||
@@ -154,8 +162,7 @@ public class BatteryDiffDataTest {
|
|||||||
/*foregroundUsageConsumePower=*/ 0,
|
/*foregroundUsageConsumePower=*/ 0,
|
||||||
/*foregroundServiceUsageConsumePower=*/ 0,
|
/*foregroundServiceUsageConsumePower=*/ 0,
|
||||||
/*backgroundUsageConsumePower=*/ 0,
|
/*backgroundUsageConsumePower=*/ 0,
|
||||||
/*cachedUsageConsumePower=*/ 0,
|
/*cachedUsageConsumePower=*/ 0);
|
||||||
batteryHistEntry);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static BatteryHistEntry createBatteryHistEntry(
|
private static BatteryHistEntry createBatteryHistEntry(
|
||||||
|
@@ -95,6 +95,14 @@ public final class BatteryDiffEntryTest {
|
|||||||
final BatteryDiffEntry entry =
|
final BatteryDiffEntry entry =
|
||||||
new BatteryDiffEntry(
|
new BatteryDiffEntry(
|
||||||
mContext,
|
mContext,
|
||||||
|
/*uid=*/ 0,
|
||||||
|
/*userId=*/ 0,
|
||||||
|
/*key=*/ "key",
|
||||||
|
/*isHidden=*/ false,
|
||||||
|
/*componentId=*/ -1,
|
||||||
|
/*legacyPackageName=*/ null,
|
||||||
|
/*legacyLabel=*/ null,
|
||||||
|
/*consumerType*/ ConvertUtils.CONSUMER_TYPE_UID_BATTERY,
|
||||||
/*foregroundUsageTimeInMs=*/ 10001L,
|
/*foregroundUsageTimeInMs=*/ 10001L,
|
||||||
/*backgroundUsageTimeInMs=*/ 20002L,
|
/*backgroundUsageTimeInMs=*/ 20002L,
|
||||||
/*screenOnTimeInMs=*/ 30003L,
|
/*screenOnTimeInMs=*/ 30003L,
|
||||||
@@ -102,8 +110,7 @@ public final class BatteryDiffEntryTest {
|
|||||||
/*foregroundUsageConsumePower=*/ 10.0,
|
/*foregroundUsageConsumePower=*/ 10.0,
|
||||||
/*foregroundServiceUsageConsumePower=*/ 10.0,
|
/*foregroundServiceUsageConsumePower=*/ 10.0,
|
||||||
/*backgroundUsageConsumePower=*/ 1.0,
|
/*backgroundUsageConsumePower=*/ 1.0,
|
||||||
/*cachedUsageConsumePower=*/ 1.0,
|
/*cachedUsageConsumePower=*/ 1.0);
|
||||||
/*batteryHistEntry=*/ null);
|
|
||||||
entry.setTotalConsumePower(100.0);
|
entry.setTotalConsumePower(100.0);
|
||||||
|
|
||||||
assertThat(entry.getPercentage()).isEqualTo(22.0);
|
assertThat(entry.getPercentage()).isEqualTo(22.0);
|
||||||
@@ -114,6 +121,14 @@ public final class BatteryDiffEntryTest {
|
|||||||
final BatteryDiffEntry entry =
|
final BatteryDiffEntry entry =
|
||||||
new BatteryDiffEntry(
|
new BatteryDiffEntry(
|
||||||
mContext,
|
mContext,
|
||||||
|
/*uid=*/ 0,
|
||||||
|
/*userId=*/ 0,
|
||||||
|
/*key=*/ "key",
|
||||||
|
/*isHidden=*/ false,
|
||||||
|
/*componentId=*/ -1,
|
||||||
|
/*legacyPackageName=*/ null,
|
||||||
|
/*legacyLabel=*/ null,
|
||||||
|
/*consumerType*/ ConvertUtils.CONSUMER_TYPE_UID_BATTERY,
|
||||||
/*foregroundUsageTimeInMs=*/ 10001L,
|
/*foregroundUsageTimeInMs=*/ 10001L,
|
||||||
/*backgroundUsageTimeInMs=*/ 20002L,
|
/*backgroundUsageTimeInMs=*/ 20002L,
|
||||||
/*screenOnTimeInMs=*/ 30003L,
|
/*screenOnTimeInMs=*/ 30003L,
|
||||||
@@ -121,8 +136,7 @@ public final class BatteryDiffEntryTest {
|
|||||||
/*foregroundUsageConsumePower=*/ 10.0,
|
/*foregroundUsageConsumePower=*/ 10.0,
|
||||||
/*foregroundServiceUsageConsumePower=*/ 10.0,
|
/*foregroundServiceUsageConsumePower=*/ 10.0,
|
||||||
/*backgroundUsageConsumePower=*/ 1.0,
|
/*backgroundUsageConsumePower=*/ 1.0,
|
||||||
/*cachedUsageConsumePower=*/ 1.0,
|
/*cachedUsageConsumePower=*/ 1.0);
|
||||||
/*batteryHistEntry=*/ null);
|
|
||||||
entry.setTotalConsumePower(0);
|
entry.setTotalConsumePower(0);
|
||||||
|
|
||||||
assertThat(entry.getPercentage()).isEqualTo(0);
|
assertThat(entry.getPercentage()).isEqualTo(0);
|
||||||
@@ -133,7 +147,24 @@ public final class BatteryDiffEntryTest {
|
|||||||
final List<BatteryDiffEntry> entryList = new ArrayList<>();
|
final List<BatteryDiffEntry> entryList = new ArrayList<>();
|
||||||
// Generates fake testing data.
|
// Generates fake testing data.
|
||||||
BatteryDiffEntry systemAppsBatteryDiffEntry =
|
BatteryDiffEntry systemAppsBatteryDiffEntry =
|
||||||
new BatteryDiffEntry.SystemAppsBatteryDiffEntry(mContext);
|
new BatteryDiffEntry(
|
||||||
|
mContext,
|
||||||
|
/*uid=*/ 0,
|
||||||
|
/*userId=*/ 0,
|
||||||
|
/*key=*/ BatteryDiffEntry.SYSTEM_APPS_KEY,
|
||||||
|
/*isHidden=*/ false,
|
||||||
|
/*componentId=*/ -1,
|
||||||
|
/*legacyPackageName=*/ null,
|
||||||
|
/*legacyLabel=*/ BatteryDiffEntry.SYSTEM_APPS_KEY,
|
||||||
|
/*consumerType*/ ConvertUtils.CONSUMER_TYPE_UID_BATTERY,
|
||||||
|
/*foregroundUsageTimeInMs=*/ 0,
|
||||||
|
/*backgroundUsageTimeInMs=*/ 0,
|
||||||
|
/*screenOnTimeInMs=*/ 0,
|
||||||
|
/*consumePower=*/ 0,
|
||||||
|
/*foregroundUsageConsumePower=*/ 0,
|
||||||
|
/*foregroundServiceUsageConsumePower=*/ 0,
|
||||||
|
/*backgroundUsageConsumePower=*/ 0,
|
||||||
|
/*cachedUsageConsumePower=*/ 0);
|
||||||
systemAppsBatteryDiffEntry.mConsumePower = 16;
|
systemAppsBatteryDiffEntry.mConsumePower = 16;
|
||||||
systemAppsBatteryDiffEntry.setTotalConsumePower(100);
|
systemAppsBatteryDiffEntry.setTotalConsumePower(100);
|
||||||
entryList.add(systemAppsBatteryDiffEntry);
|
entryList.add(systemAppsBatteryDiffEntry);
|
||||||
@@ -448,17 +479,16 @@ public final class BatteryDiffEntryTest {
|
|||||||
|
|
||||||
private BatteryDiffEntry createBatteryDiffEntry(
|
private BatteryDiffEntry createBatteryDiffEntry(
|
||||||
int consumerType, long uid, boolean isHidden) {
|
int consumerType, long uid, boolean isHidden) {
|
||||||
final ContentValues values = getContentValuesWithType(consumerType);
|
|
||||||
final BatteryInformation batteryInformation =
|
|
||||||
BatteryInformation
|
|
||||||
.newBuilder()
|
|
||||||
.setIsHidden(isHidden)
|
|
||||||
.build();
|
|
||||||
values.put(BatteryHistEntry.KEY_BATTERY_INFORMATION,
|
|
||||||
ConvertUtils.convertBatteryInformationToString(batteryInformation));
|
|
||||||
values.put(BatteryHistEntry.KEY_UID, uid);
|
|
||||||
return new BatteryDiffEntry(
|
return new BatteryDiffEntry(
|
||||||
mContext,
|
mContext,
|
||||||
|
/*uid=*/ uid,
|
||||||
|
/*userId=*/ 0,
|
||||||
|
/*key=*/ "key",
|
||||||
|
/*isHidden=*/ isHidden,
|
||||||
|
/*componentId=*/ -1,
|
||||||
|
/*legacyPackageName=*/ null,
|
||||||
|
/*legacyLabel=*/ null,
|
||||||
|
/*consumerType*/ consumerType,
|
||||||
/*foregroundUsageTimeInMs=*/ 0,
|
/*foregroundUsageTimeInMs=*/ 0,
|
||||||
/*backgroundUsageTimeInMs=*/ 0,
|
/*backgroundUsageTimeInMs=*/ 0,
|
||||||
/*screenOnTimeInMs=*/ 0,
|
/*screenOnTimeInMs=*/ 0,
|
||||||
@@ -466,14 +496,21 @@ public final class BatteryDiffEntryTest {
|
|||||||
/*foregroundUsageConsumePower=*/ 0,
|
/*foregroundUsageConsumePower=*/ 0,
|
||||||
/*foregroundServiceUsageConsumePower=*/ 0,
|
/*foregroundServiceUsageConsumePower=*/ 0,
|
||||||
/*backgroundUsageConsumePower=*/ 0,
|
/*backgroundUsageConsumePower=*/ 0,
|
||||||
/*cachedUsageConsumePower=*/ 0,
|
/*cachedUsageConsumePower=*/ 0);
|
||||||
new BatteryHistEntry(values));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private BatteryDiffEntry createBatteryDiffEntry(
|
private BatteryDiffEntry createBatteryDiffEntry(
|
||||||
double consumePower, BatteryHistEntry batteryHistEntry) {
|
double consumePower, BatteryHistEntry batteryHistEntry) {
|
||||||
final BatteryDiffEntry entry = new BatteryDiffEntry(
|
final BatteryDiffEntry entry = new BatteryDiffEntry(
|
||||||
mContext,
|
mContext,
|
||||||
|
batteryHistEntry.mUid,
|
||||||
|
batteryHistEntry.mUserId,
|
||||||
|
batteryHistEntry.getKey(),
|
||||||
|
batteryHistEntry.mIsHidden,
|
||||||
|
batteryHistEntry.mDrainType,
|
||||||
|
batteryHistEntry.mPackageName,
|
||||||
|
batteryHistEntry.mAppLabel,
|
||||||
|
batteryHistEntry.mConsumerType,
|
||||||
/*foregroundUsageTimeInMs=*/ 0,
|
/*foregroundUsageTimeInMs=*/ 0,
|
||||||
/*backgroundUsageTimeInMs=*/ 0,
|
/*backgroundUsageTimeInMs=*/ 0,
|
||||||
/*screenOnTimeInMs=*/ 0,
|
/*screenOnTimeInMs=*/ 0,
|
||||||
@@ -481,8 +518,7 @@ public final class BatteryDiffEntryTest {
|
|||||||
/*foregroundUsageConsumePower=*/ 0,
|
/*foregroundUsageConsumePower=*/ 0,
|
||||||
/*foregroundServiceUsageConsumePower=*/ 0,
|
/*foregroundServiceUsageConsumePower=*/ 0,
|
||||||
/*backgroundUsageConsumePower=*/ 0,
|
/*backgroundUsageConsumePower=*/ 0,
|
||||||
/*cachedUsageConsumePower=*/ 0,
|
/*cachedUsageConsumePower=*/ 0);
|
||||||
batteryHistEntry);
|
|
||||||
entry.setTotalConsumePower(100.0);
|
entry.setTotalConsumePower(100.0);
|
||||||
return entry;
|
return entry;
|
||||||
}
|
}
|
||||||
|
@@ -15,6 +15,10 @@
|
|||||||
*/
|
*/
|
||||||
package com.android.settings.fuelgauge.batteryusage;
|
package com.android.settings.fuelgauge.batteryusage;
|
||||||
|
|
||||||
|
import static com.android.settings.fuelgauge.batteryusage.ConvertUtils.isSystemConsumer;
|
||||||
|
import static com.android.settings.fuelgauge.batteryusage.ConvertUtils.isUidConsumer;
|
||||||
|
import static com.android.settings.fuelgauge.batteryusage.ConvertUtils.isUserConsumer;
|
||||||
|
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
@@ -147,32 +151,32 @@ public final class BatteryHistEntryTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testIsAppEntry_returnExpectedResult() {
|
public void testIsAppEntry_returnExpectedResult() {
|
||||||
assertThat(createEntry(ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY).isAppEntry())
|
assertThat(isUidConsumer(
|
||||||
.isFalse();
|
createEntry(ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY).mConsumerType)).isFalse();
|
||||||
assertThat(createEntry(ConvertUtils.CONSUMER_TYPE_USER_BATTERY).isAppEntry())
|
assertThat(isUidConsumer(
|
||||||
.isFalse();
|
createEntry(ConvertUtils.CONSUMER_TYPE_USER_BATTERY).mConsumerType)).isFalse();
|
||||||
assertThat(createEntry(ConvertUtils.CONSUMER_TYPE_UID_BATTERY).isAppEntry())
|
assertThat(isUidConsumer(
|
||||||
.isTrue();
|
createEntry(ConvertUtils.CONSUMER_TYPE_UID_BATTERY).mConsumerType)).isTrue();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testIsUserEntry_returnExpectedResult() {
|
public void testIsUserEntry_returnExpectedResult() {
|
||||||
assertThat(createEntry(ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY).isUserEntry())
|
assertThat(isUserConsumer(
|
||||||
.isFalse();
|
createEntry(ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY).mConsumerType)).isFalse();
|
||||||
assertThat(createEntry(ConvertUtils.CONSUMER_TYPE_USER_BATTERY).isUserEntry())
|
assertThat(isUserConsumer(
|
||||||
.isTrue();
|
createEntry(ConvertUtils.CONSUMER_TYPE_USER_BATTERY).mConsumerType)).isTrue();
|
||||||
assertThat(createEntry(ConvertUtils.CONSUMER_TYPE_UID_BATTERY).isUserEntry())
|
assertThat(isUserConsumer(
|
||||||
.isFalse();
|
createEntry(ConvertUtils.CONSUMER_TYPE_UID_BATTERY).mConsumerType)).isFalse();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testIsSystemEntry_returnExpectedResult() {
|
public void testIsSystemEntry_returnExpectedResult() {
|
||||||
assertThat(createEntry(ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY).isSystemEntry())
|
assertThat(isSystemConsumer(
|
||||||
.isTrue();
|
createEntry(ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY).mConsumerType)).isTrue();
|
||||||
assertThat(createEntry(ConvertUtils.CONSUMER_TYPE_USER_BATTERY).isSystemEntry())
|
assertThat(isSystemConsumer(
|
||||||
.isFalse();
|
createEntry(ConvertUtils.CONSUMER_TYPE_USER_BATTERY).mConsumerType)).isFalse();
|
||||||
assertThat(createEntry(ConvertUtils.CONSUMER_TYPE_UID_BATTERY).isSystemEntry())
|
assertThat(isSystemConsumer(
|
||||||
.isFalse();
|
createEntry(ConvertUtils.CONSUMER_TYPE_UID_BATTERY).mConsumerType)).isFalse();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@@ -27,7 +27,6 @@ import android.widget.TextView;
|
|||||||
import androidx.preference.PreferenceViewHolder;
|
import androidx.preference.PreferenceViewHolder;
|
||||||
|
|
||||||
import com.android.settings.R;
|
import com.android.settings.R;
|
||||||
import com.android.settings.fuelgauge.BatteryInfo;
|
|
||||||
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
@@ -42,8 +41,6 @@ public class BatteryHistoryPreferenceTest {
|
|||||||
@Mock
|
@Mock
|
||||||
private PreferenceViewHolder mViewHolder;
|
private PreferenceViewHolder mViewHolder;
|
||||||
@Mock
|
@Mock
|
||||||
private BatteryInfo mBatteryInfo;
|
|
||||||
@Mock
|
|
||||||
private TextView mTextView;
|
private TextView mTextView;
|
||||||
@Mock
|
@Mock
|
||||||
private BatteryChartView mDailyChartView;
|
private BatteryChartView mDailyChartView;
|
||||||
@@ -59,7 +56,6 @@ public class BatteryHistoryPreferenceTest {
|
|||||||
LayoutInflater.from(context).inflate(R.layout.battery_chart_graph, null);
|
LayoutInflater.from(context).inflate(R.layout.battery_chart_graph, null);
|
||||||
|
|
||||||
mBatteryHistoryPreference = new BatteryHistoryPreference(context, null);
|
mBatteryHistoryPreference = new BatteryHistoryPreference(context, null);
|
||||||
mBatteryHistoryPreference.mBatteryInfo = mBatteryInfo;
|
|
||||||
mViewHolder = spy(PreferenceViewHolder.createInstanceForTests(itemView));
|
mViewHolder = spy(PreferenceViewHolder.createInstanceForTests(itemView));
|
||||||
when(mViewHolder.findViewById(R.id.daily_battery_chart)).thenReturn(mDailyChartView);
|
when(mViewHolder.findViewById(R.id.daily_battery_chart)).thenReturn(mDailyChartView);
|
||||||
when(mViewHolder.findViewById(R.id.hourly_battery_chart)).thenReturn(mHourlyChartView);
|
when(mViewHolder.findViewById(R.id.hourly_battery_chart)).thenReturn(mHourlyChartView);
|
||||||
|
@@ -0,0 +1,214 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2023 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 static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.robolectric.RobolectricTestRunner;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.TimeZone;
|
||||||
|
|
||||||
|
@RunWith(RobolectricTestRunner.class)
|
||||||
|
public class BatteryLevelDataTest {
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
TimeZone.setDefault(TimeZone.getTimeZone("GMT+8"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getDailyTimestamps_allDataInOneHour_returnExpectedList() {
|
||||||
|
// Timezone GMT+8
|
||||||
|
final List<Long> timestamps = List.of(
|
||||||
|
1640970006000L, // 2022-01-01 01:00:06
|
||||||
|
1640973608000L // 2022-01-01 01:00:08
|
||||||
|
);
|
||||||
|
|
||||||
|
final List<Long> expectedTimestamps = List.of(
|
||||||
|
1640970006000L, // 2022-01-01 01:00:06
|
||||||
|
1640973608000L // 2022-01-01 01:00:08
|
||||||
|
);
|
||||||
|
assertThat(BatteryLevelData.getDailyTimestamps(timestamps)).isEqualTo(expectedTimestamps);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getDailyTimestamps_OneHourDataPerDay_returnExpectedList() {
|
||||||
|
// Timezone GMT+8
|
||||||
|
final List<Long> timestamps = List.of(
|
||||||
|
1641049200000L, // 2022-01-01 23:00:00
|
||||||
|
1641052800000L, // 2022-01-02 00:00:00
|
||||||
|
1641056400000L // 2022-01-02 01:00:00
|
||||||
|
);
|
||||||
|
|
||||||
|
final List<Long> expectedTimestamps = List.of(
|
||||||
|
1641049200000L, // 2022-01-01 23:00:00
|
||||||
|
1641052800000L, // 2022-01-02 00:00:00
|
||||||
|
1641056400000L // 2022-01-02 01:00:00
|
||||||
|
);
|
||||||
|
assertThat(BatteryLevelData.getDailyTimestamps(timestamps)).isEqualTo(expectedTimestamps);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getDailyTimestamps_OneDayData_returnExpectedList() {
|
||||||
|
// Timezone GMT+8
|
||||||
|
final List<Long> timestamps = List.of(
|
||||||
|
1640966400000L, // 2022-01-01 00:00:00
|
||||||
|
1640970000000L, // 2022-01-01 01:00:00
|
||||||
|
1640973600000L, // 2022-01-01 02:00:00
|
||||||
|
1640977200000L, // 2022-01-01 03:00:00
|
||||||
|
1640980800000L // 2022-01-01 04:00:00
|
||||||
|
);
|
||||||
|
|
||||||
|
final List<Long> expectedTimestamps = List.of(
|
||||||
|
1640966400000L, // 2022-01-01 00:00:00
|
||||||
|
1640980800000L // 2022-01-01 04:00:00
|
||||||
|
);
|
||||||
|
assertThat(BatteryLevelData.getDailyTimestamps(timestamps)).isEqualTo(expectedTimestamps);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getDailyTimestamps_MultipleDaysData_returnExpectedList() {
|
||||||
|
// Timezone GMT+8
|
||||||
|
final List<Long> timestamps = List.of(
|
||||||
|
1641045600000L, // 2022-01-01 22:00:00
|
||||||
|
1641060000000L, // 2022-01-02 02:00:00
|
||||||
|
1641160800000L, // 2022-01-03 06:00:00
|
||||||
|
1641232800000L // 2022-01-04 02:00:00
|
||||||
|
);
|
||||||
|
|
||||||
|
final List<Long> expectedTimestamps = List.of(
|
||||||
|
1641045600000L, // 2022-01-01 22:00:00
|
||||||
|
1641052800000L, // 2022-01-02 00:00:00
|
||||||
|
1641139200000L, // 2022-01-03 00:00:00
|
||||||
|
1641225600000L, // 2022-01-04 00:00:00
|
||||||
|
1641232800000L // 2022-01-04 02:00:00
|
||||||
|
);
|
||||||
|
assertThat(BatteryLevelData.getDailyTimestamps(timestamps)).isEqualTo(expectedTimestamps);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getDailyTimestamps_FirstDayOneHourData_returnExpectedList() {
|
||||||
|
// Timezone GMT+8
|
||||||
|
final List<Long> timestamps = List.of(
|
||||||
|
1641049200000L, // 2022-01-01 23:00:00
|
||||||
|
1641060000000L, // 2022-01-02 02:00:00
|
||||||
|
1641160800000L, // 2022-01-03 06:00:00
|
||||||
|
1641254400000L // 2022-01-04 08:00:00
|
||||||
|
);
|
||||||
|
|
||||||
|
final List<Long> expectedTimestamps = List.of(
|
||||||
|
1641049200000L, // 2022-01-01 23:00:00
|
||||||
|
1641052800000L, // 2022-01-02 00:00:00
|
||||||
|
1641139200000L, // 2022-01-03 00:00:00
|
||||||
|
1641225600000L, // 2022-01-04 00:00:00
|
||||||
|
1641254400000L // 2022-01-04 08:00:00
|
||||||
|
);
|
||||||
|
assertThat(BatteryLevelData.getDailyTimestamps(timestamps)).isEqualTo(expectedTimestamps);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getDailyTimestamps_LastDayNoData_returnExpectedList() {
|
||||||
|
// Timezone GMT+8
|
||||||
|
final List<Long> timestamps = List.of(
|
||||||
|
1640988000000L, // 2022-01-01 06:00:00
|
||||||
|
1641060000000L, // 2022-01-02 02:00:00
|
||||||
|
1641160800000L, // 2022-01-03 06:00:00
|
||||||
|
1641225600000L // 2022-01-04 00:00:00
|
||||||
|
);
|
||||||
|
|
||||||
|
final List<Long> expectedTimestamps = List.of(
|
||||||
|
1640988000000L, // 2022-01-01 06:00:00
|
||||||
|
1641052800000L, // 2022-01-02 00:00:00
|
||||||
|
1641139200000L, // 2022-01-03 00:00:00
|
||||||
|
1641225600000L // 2022-01-04 00:00:00
|
||||||
|
);
|
||||||
|
assertThat(BatteryLevelData.getDailyTimestamps(timestamps)).isEqualTo(expectedTimestamps);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getDailyTimestamps_LastDayOneHourData_returnExpectedList() {
|
||||||
|
// Timezone GMT+8
|
||||||
|
final List<Long> timestamps = List.of(
|
||||||
|
1640988000000L, // 2022-01-01 06:00:00
|
||||||
|
1641060000000L, // 2022-01-02 02:00:00
|
||||||
|
1641160800000L, // 2022-01-03 06:00:00
|
||||||
|
1641229200000L // 2022-01-04 01:00:00
|
||||||
|
);
|
||||||
|
|
||||||
|
final List<Long> expectedTimestamps = List.of(
|
||||||
|
1640988000000L, // 2022-01-01 06:00:00
|
||||||
|
1641052800000L, // 2022-01-02 00:00:00
|
||||||
|
1641139200000L, // 2022-01-03 00:00:00
|
||||||
|
1641225600000L, // 2022-01-04 00:00:00
|
||||||
|
1641229200000L // 2022-01-04 01:00:00
|
||||||
|
);
|
||||||
|
assertThat(BatteryLevelData.getDailyTimestamps(timestamps)).isEqualTo(expectedTimestamps);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void combine_normalFlow_returnExpectedResult() {
|
||||||
|
final BatteryLevelData batteryLevelData =
|
||||||
|
new BatteryLevelData(Map.of(1691596800000L, 90, 1691604000000L, 80));
|
||||||
|
final List<BatteryEvent> batteryLevelRecordEvents = List.of(
|
||||||
|
BatteryEvent.newBuilder().setTimestamp(1691586000166L).setBatteryLevel(100)
|
||||||
|
.setType(BatteryEventType.FULL_CHARGED).build(),
|
||||||
|
BatteryEvent.newBuilder().setTimestamp(1691589600000L).setBatteryLevel(98)
|
||||||
|
.setType(BatteryEventType.EVEN_HOUR).build());
|
||||||
|
|
||||||
|
BatteryLevelData result =
|
||||||
|
BatteryLevelData.combine(batteryLevelData, batteryLevelRecordEvents);
|
||||||
|
|
||||||
|
assertThat(result.getDailyBatteryLevels().getTimestamps())
|
||||||
|
.isEqualTo(List.of(1691586000166L, 1691596800000L, 1691604000000L));
|
||||||
|
assertThat(result.getDailyBatteryLevels().getLevels())
|
||||||
|
.isEqualTo(List.of(100, 90, 80));
|
||||||
|
assertThat(result.getHourlyBatteryLevelsPerDay())
|
||||||
|
.hasSize(2);
|
||||||
|
assertThat(result.getHourlyBatteryLevelsPerDay().get(0).getTimestamps())
|
||||||
|
.isEqualTo(List.of(1691586000166L, 1691589600000L, 1691596800000L));
|
||||||
|
assertThat(result.getHourlyBatteryLevelsPerDay().get(0).getLevels())
|
||||||
|
.isEqualTo(List.of(100, 98, 90));
|
||||||
|
assertThat(result.getHourlyBatteryLevelsPerDay().get(1).getTimestamps())
|
||||||
|
.isEqualTo(List.of(1691596800000L, 1691604000000L));
|
||||||
|
assertThat(result.getHourlyBatteryLevelsPerDay().get(1).getLevels())
|
||||||
|
.isEqualTo(List.of(90, 80));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void combine_existingBatteryLevelDataIsNull_returnExpectedResult() {
|
||||||
|
final List<BatteryEvent> batteryLevelRecordEvents = List.of(
|
||||||
|
BatteryEvent.newBuilder().setTimestamp(1691586000166L).setBatteryLevel(100)
|
||||||
|
.setType(BatteryEventType.FULL_CHARGED).build(),
|
||||||
|
BatteryEvent.newBuilder().setTimestamp(1691589600000L).setBatteryLevel(98)
|
||||||
|
.setType(BatteryEventType.EVEN_HOUR).build());
|
||||||
|
|
||||||
|
BatteryLevelData result =
|
||||||
|
BatteryLevelData.combine(null, batteryLevelRecordEvents);
|
||||||
|
|
||||||
|
assertThat(result.getHourlyBatteryLevelsPerDay())
|
||||||
|
.hasSize(1);
|
||||||
|
assertThat(result.getHourlyBatteryLevelsPerDay().get(0).getTimestamps())
|
||||||
|
.isEqualTo(List.of(1691586000166L, 1691589600000L));
|
||||||
|
assertThat(result.getHourlyBatteryLevelsPerDay().get(0).getLevels())
|
||||||
|
.isEqualTo(List.of(100, 98));
|
||||||
|
}
|
||||||
|
}
|
@@ -96,6 +96,14 @@ public final class BatteryUsageBreakdownControllerTest {
|
|||||||
mBatteryUsageBreakdownController.mAppListPreferenceGroup = mAppListPreferenceGroup;
|
mBatteryUsageBreakdownController.mAppListPreferenceGroup = mAppListPreferenceGroup;
|
||||||
mBatteryDiffEntry = new BatteryDiffEntry(
|
mBatteryDiffEntry = new BatteryDiffEntry(
|
||||||
mContext,
|
mContext,
|
||||||
|
/*uid=*/ 0L,
|
||||||
|
/*userId=*/ 0L,
|
||||||
|
/*key=*/ "key",
|
||||||
|
/*isHidden=*/ false,
|
||||||
|
/*componentId=*/ -1,
|
||||||
|
/*legacyPackageName=*/ null,
|
||||||
|
/*legacyLabel=*/ null,
|
||||||
|
/*consumerType=*/ ConvertUtils.CONSUMER_TYPE_UID_BATTERY,
|
||||||
/*foregroundUsageTimeInMs=*/ 1,
|
/*foregroundUsageTimeInMs=*/ 1,
|
||||||
/*backgroundUsageTimeInMs=*/ 2,
|
/*backgroundUsageTimeInMs=*/ 2,
|
||||||
/*screenOnTimeInMs=*/ 0,
|
/*screenOnTimeInMs=*/ 0,
|
||||||
@@ -103,13 +111,14 @@ public final class BatteryUsageBreakdownControllerTest {
|
|||||||
/*foregroundUsageConsumePower=*/ 0,
|
/*foregroundUsageConsumePower=*/ 0,
|
||||||
/*foregroundServiceUsageConsumePower=*/ 1,
|
/*foregroundServiceUsageConsumePower=*/ 1,
|
||||||
/*backgroundUsageConsumePower=*/ 2,
|
/*backgroundUsageConsumePower=*/ 2,
|
||||||
/*cachedUsageConsumePower=*/ 0,
|
/*cachedUsageConsumePower=*/ 0);
|
||||||
mBatteryHistEntry);
|
|
||||||
mBatteryDiffEntry = spy(mBatteryDiffEntry);
|
mBatteryDiffEntry = spy(mBatteryDiffEntry);
|
||||||
mBatteryUsageBreakdownController.mBatteryDiffData =
|
mBatteryUsageBreakdownController.mBatteryDiffData =
|
||||||
new BatteryDiffData(mContext, /* screenOnTime= */ 0L,
|
new BatteryDiffData(mContext, /* startTimestamp= */ 0L, /* endTimestamp= */ 0L,
|
||||||
Arrays.asList(mBatteryDiffEntry), Arrays.asList(), Set.of(), Set.of(),
|
/* startBatteryLevel= */ 0, /* endBatteryLevel= */ 0,
|
||||||
/* isAccumulated= */ false);
|
/* screenOnTime= */ 0L, Arrays.asList(mBatteryDiffEntry), Arrays.asList(),
|
||||||
|
Set.of(), Set.of(), /* isAccumulated= */ false);
|
||||||
|
BatteryDiffEntry.clearCache();
|
||||||
// Adds fake testing data.
|
// Adds fake testing data.
|
||||||
BatteryDiffEntry.sResourceCache.put(
|
BatteryDiffEntry.sResourceCache.put(
|
||||||
"fakeBatteryDiffEntryKey",
|
"fakeBatteryDiffEntryKey",
|
||||||
@@ -140,7 +149,7 @@ public final class BatteryUsageBreakdownControllerTest {
|
|||||||
doReturn(1).when(mAppListPreferenceGroup).getPreferenceCount();
|
doReturn(1).when(mAppListPreferenceGroup).getPreferenceCount();
|
||||||
doReturn(mDrawable).when(mBatteryDiffEntry).getAppIcon();
|
doReturn(mDrawable).when(mBatteryDiffEntry).getAppIcon();
|
||||||
doReturn(appLabel).when(mBatteryDiffEntry).getAppLabel();
|
doReturn(appLabel).when(mBatteryDiffEntry).getAppLabel();
|
||||||
doReturn(PREF_KEY).when(mBatteryHistEntry).getKey();
|
doReturn(PREF_KEY).when(mBatteryDiffEntry).getKey();
|
||||||
doReturn(null).when(mAppListPreferenceGroup).findPreference(PREF_KEY);
|
doReturn(null).when(mAppListPreferenceGroup).findPreference(PREF_KEY);
|
||||||
doReturn(false).when(mBatteryDiffEntry).validForRestriction();
|
doReturn(false).when(mBatteryDiffEntry).validForRestriction();
|
||||||
|
|
||||||
@@ -168,7 +177,7 @@ public final class BatteryUsageBreakdownControllerTest {
|
|||||||
doReturn(1).when(mAppListPreferenceGroup).getPreferenceCount();
|
doReturn(1).when(mAppListPreferenceGroup).getPreferenceCount();
|
||||||
doReturn(mDrawable).when(mBatteryDiffEntry).getAppIcon();
|
doReturn(mDrawable).when(mBatteryDiffEntry).getAppIcon();
|
||||||
doReturn(appLabel).when(mBatteryDiffEntry).getAppLabel();
|
doReturn(appLabel).when(mBatteryDiffEntry).getAppLabel();
|
||||||
doReturn(PREF_KEY).when(mBatteryHistEntry).getKey();
|
doReturn(PREF_KEY).when(mBatteryDiffEntry).getKey();
|
||||||
doReturn(mPowerGaugePreference).when(mAppListPreferenceGroup).findPreference(PREF_KEY);
|
doReturn(mPowerGaugePreference).when(mAppListPreferenceGroup).findPreference(PREF_KEY);
|
||||||
|
|
||||||
mBatteryUsageBreakdownController.addAllPreferences();
|
mBatteryUsageBreakdownController.addAllPreferences();
|
||||||
@@ -197,7 +206,7 @@ public final class BatteryUsageBreakdownControllerTest {
|
|||||||
public void removeAndCacheAllUnusedPreferences_keepPref_KeepAllPreference() {
|
public void removeAndCacheAllUnusedPreferences_keepPref_KeepAllPreference() {
|
||||||
doReturn(1).when(mAppListPreferenceGroup).getPreferenceCount();
|
doReturn(1).when(mAppListPreferenceGroup).getPreferenceCount();
|
||||||
doReturn(mPowerGaugePreference).when(mAppListPreferenceGroup).getPreference(0);
|
doReturn(mPowerGaugePreference).when(mAppListPreferenceGroup).getPreference(0);
|
||||||
doReturn(PREF_KEY).when(mBatteryHistEntry).getKey();
|
doReturn(PREF_KEY).when(mBatteryDiffEntry).getKey();
|
||||||
doReturn(PREF_KEY).when(mPowerGaugePreference).getKey();
|
doReturn(PREF_KEY).when(mPowerGaugePreference).getKey();
|
||||||
doReturn(mPowerGaugePreference).when(mAppListPreferenceGroup).findPreference(PREF_KEY);
|
doReturn(mPowerGaugePreference).when(mAppListPreferenceGroup).findPreference(PREF_KEY);
|
||||||
// Ensures the testing data is correct.
|
// Ensures the testing data is correct.
|
||||||
@@ -222,7 +231,7 @@ public final class BatteryUsageBreakdownControllerTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void handlePreferenceTreeClick_forAppEntry_returnTrue() {
|
public void handlePreferenceTreeClick_forAppEntry_returnTrue() {
|
||||||
doReturn(false).when(mBatteryHistEntry).isAppEntry();
|
mBatteryDiffEntry.mConsumerType = ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY;
|
||||||
doReturn(mBatteryDiffEntry).when(mPowerGaugePreference).getBatteryDiffEntry();
|
doReturn(mBatteryDiffEntry).when(mPowerGaugePreference).getBatteryDiffEntry();
|
||||||
|
|
||||||
assertThat(mBatteryUsageBreakdownController.handlePreferenceTreeClick(
|
assertThat(mBatteryUsageBreakdownController.handlePreferenceTreeClick(
|
||||||
@@ -238,7 +247,7 @@ public final class BatteryUsageBreakdownControllerTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void handlePreferenceTreeClick_forSystemEntry_returnTrue() {
|
public void handlePreferenceTreeClick_forSystemEntry_returnTrue() {
|
||||||
doReturn(true).when(mBatteryHistEntry).isAppEntry();
|
mBatteryDiffEntry.mConsumerType = ConvertUtils.CONSUMER_TYPE_UID_BATTERY;
|
||||||
doReturn(mBatteryDiffEntry).when(mPowerGaugePreference).getBatteryDiffEntry();
|
doReturn(mBatteryDiffEntry).when(mPowerGaugePreference).getBatteryDiffEntry();
|
||||||
|
|
||||||
assertThat(mBatteryUsageBreakdownController.handlePreferenceTreeClick(
|
assertThat(mBatteryUsageBreakdownController.handlePreferenceTreeClick(
|
||||||
@@ -394,10 +403,23 @@ public final class BatteryUsageBreakdownControllerTest {
|
|||||||
contentValues.put(BatteryHistEntry.KEY_USER_ID, Integer.valueOf(1001));
|
contentValues.put(BatteryHistEntry.KEY_USER_ID, Integer.valueOf(1001));
|
||||||
final BatteryHistEntry batteryHistEntry = new BatteryHistEntry(contentValues);
|
final BatteryHistEntry batteryHistEntry = new BatteryHistEntry(contentValues);
|
||||||
return new BatteryDiffEntry(
|
return new BatteryDiffEntry(
|
||||||
mContext, foregroundUsageTimeInMs, backgroundUsageTimeInMs, screenOnTimeInMs,
|
mContext,
|
||||||
/*consumePower=*/ 0, /*foregroundUsageConsumePower=*/ 0,
|
batteryHistEntry.mUid,
|
||||||
/*foregroundServiceUsageConsumePower=*/ 0, /*backgroundUsageConsumePower=*/ 0,
|
batteryHistEntry.mUserId,
|
||||||
/*cachedUsageConsumePower=*/ 0, batteryHistEntry);
|
batteryHistEntry.getKey(),
|
||||||
|
batteryHistEntry.mIsHidden,
|
||||||
|
batteryHistEntry.mDrainType,
|
||||||
|
batteryHistEntry.mPackageName,
|
||||||
|
batteryHistEntry.mAppLabel,
|
||||||
|
batteryHistEntry.mConsumerType,
|
||||||
|
foregroundUsageTimeInMs,
|
||||||
|
backgroundUsageTimeInMs,
|
||||||
|
screenOnTimeInMs,
|
||||||
|
/*consumePower=*/ 0,
|
||||||
|
/*foregroundUsageConsumePower=*/ 0,
|
||||||
|
/*foregroundServiceUsageConsumePower=*/ 0,
|
||||||
|
/*backgroundUsageConsumePower=*/ 0,
|
||||||
|
/*cachedUsageConsumePower=*/ 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
private BatteryUsageBreakdownController createController() {
|
private BatteryUsageBreakdownController createController() {
|
||||||
|
@@ -20,11 +20,9 @@ import static com.google.common.truth.Truth.assertThat;
|
|||||||
|
|
||||||
import static org.junit.Assert.assertThrows;
|
import static org.junit.Assert.assertThrows;
|
||||||
|
|
||||||
import android.app.Application;
|
|
||||||
import android.content.ContentResolver;
|
import android.content.ContentResolver;
|
||||||
import android.content.ContentValues;
|
import android.content.ContentValues;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
|
||||||
@@ -34,6 +32,7 @@ import com.android.settings.fuelgauge.batteryusage.db.AppUsageEventEntity;
|
|||||||
import com.android.settings.fuelgauge.batteryusage.db.BatteryEventEntity;
|
import com.android.settings.fuelgauge.batteryusage.db.BatteryEventEntity;
|
||||||
import com.android.settings.fuelgauge.batteryusage.db.BatteryState;
|
import com.android.settings.fuelgauge.batteryusage.db.BatteryState;
|
||||||
import com.android.settings.fuelgauge.batteryusage.db.BatteryStateDatabase;
|
import com.android.settings.fuelgauge.batteryusage.db.BatteryStateDatabase;
|
||||||
|
import com.android.settings.fuelgauge.batteryusage.db.BatteryUsageSlotEntity;
|
||||||
import com.android.settings.testutils.BatteryTestUtils;
|
import com.android.settings.testutils.BatteryTestUtils;
|
||||||
import com.android.settings.testutils.FakeClock;
|
import com.android.settings.testutils.FakeClock;
|
||||||
|
|
||||||
@@ -41,12 +40,10 @@ import org.junit.Before;
|
|||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.robolectric.RobolectricTestRunner;
|
import org.robolectric.RobolectricTestRunner;
|
||||||
import org.robolectric.Shadows;
|
|
||||||
|
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
/** Tests for {@link BatteryUsageContentProvider}. */
|
/** Tests for {@link BatteryUsageContentProvider}. */
|
||||||
@@ -126,11 +123,29 @@ public final class BatteryUsageContentProviderTest {
|
|||||||
() -> mProvider.insert(uri, /*contentValues=*/ null));
|
() -> mProvider.insert(uri, /*contentValues=*/ null));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void query_getLastFullChargeTimestamp_returnsExpectedResult() throws Exception {
|
||||||
|
mProvider.onCreate();
|
||||||
|
ContentValues values = new ContentValues();
|
||||||
|
values.put(BatteryEventEntity.KEY_TIMESTAMP, 10001L);
|
||||||
|
values.put(BatteryEventEntity.KEY_BATTERY_EVENT_TYPE,
|
||||||
|
BatteryEventType.FULL_CHARGED.getNumber());
|
||||||
|
values.put(BatteryEventEntity.KEY_BATTERY_LEVEL, 100);
|
||||||
|
mProvider.insert(DatabaseUtils.BATTERY_EVENT_URI, values);
|
||||||
|
|
||||||
|
final Cursor cursor = getCursorOfLastFullChargeTimestamp();
|
||||||
|
|
||||||
|
assertThat(cursor.getCount()).isEqualTo(1);
|
||||||
|
cursor.moveToFirst();
|
||||||
|
final long lastFullChargeTimestamp = cursor.getLong(0);
|
||||||
|
assertThat(lastFullChargeTimestamp).isEqualTo(10001L);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void query_batteryState_returnsExpectedResult() throws Exception {
|
public void query_batteryState_returnsExpectedResult() throws Exception {
|
||||||
mProvider.onCreate();
|
mProvider.onCreate();
|
||||||
final Duration currentTime = Duration.ofHours(52);
|
final Duration currentTime = Duration.ofHours(52);
|
||||||
final long expiredTimeCutoff = currentTime.toMillis() - 3;
|
final long expiredTimeCutoff = currentTime.toMillis() - 8;
|
||||||
|
|
||||||
final Cursor cursor = insertBatteryState(currentTime, Long.toString(expiredTimeCutoff));
|
final Cursor cursor = insertBatteryState(currentTime, Long.toString(expiredTimeCutoff));
|
||||||
|
|
||||||
@@ -150,19 +165,13 @@ public final class BatteryUsageContentProviderTest {
|
|||||||
final String actualPackageName3 = cursor.getString(packageNameIndex);
|
final String actualPackageName3 = cursor.getString(packageNameIndex);
|
||||||
assertThat(actualPackageName3).isEqualTo(PACKAGE_NAME3);
|
assertThat(actualPackageName3).isEqualTo(PACKAGE_NAME3);
|
||||||
cursor.close();
|
cursor.close();
|
||||||
// Verifies the broadcast intent.
|
|
||||||
TimeUnit.SECONDS.sleep(1);
|
|
||||||
final List<Intent> intents = Shadows.shadowOf((Application) mContext).getBroadcastIntents();
|
|
||||||
assertThat(intents).hasSize(1);
|
|
||||||
assertThat(intents.get(0).getAction()).isEqualTo(
|
|
||||||
BootBroadcastReceiver.ACTION_PERIODIC_JOB_RECHECK);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void query_batteryStateTimestamp_returnsExpectedResult() throws Exception {
|
public void query_batteryStateTimestamp_returnsExpectedResult() throws Exception {
|
||||||
mProvider.onCreate();
|
mProvider.onCreate();
|
||||||
final Duration currentTime = Duration.ofHours(52);
|
final Duration currentTime = Duration.ofHours(52);
|
||||||
final long expiredTimeCutoff = currentTime.toMillis() - 1;
|
final long expiredTimeCutoff = currentTime.toMillis() - 2;
|
||||||
|
|
||||||
final Cursor cursor = insertBatteryState(currentTime, Long.toString(expiredTimeCutoff));
|
final Cursor cursor = insertBatteryState(currentTime, Long.toString(expiredTimeCutoff));
|
||||||
|
|
||||||
@@ -178,12 +187,25 @@ public final class BatteryUsageContentProviderTest {
|
|||||||
final String actualPackageName2 = cursor.getString(packageNameIndex);
|
final String actualPackageName2 = cursor.getString(packageNameIndex);
|
||||||
assertThat(actualPackageName2).isEqualTo(PACKAGE_NAME3);
|
assertThat(actualPackageName2).isEqualTo(PACKAGE_NAME3);
|
||||||
cursor.close();
|
cursor.close();
|
||||||
// Verifies the broadcast intent.
|
}
|
||||||
TimeUnit.SECONDS.sleep(1);
|
|
||||||
final List<Intent> intents = Shadows.shadowOf((Application) mContext).getBroadcastIntents();
|
@Test
|
||||||
assertThat(intents).hasSize(1);
|
public void query_getBatteryStateLatestTimestamp_returnsExpectedResult() throws Exception {
|
||||||
assertThat(intents.get(0).getAction()).isEqualTo(
|
mProvider.onCreate();
|
||||||
BootBroadcastReceiver.ACTION_PERIODIC_JOB_RECHECK);
|
final Duration currentTime = Duration.ofHours(52);
|
||||||
|
insertBatteryState(currentTime, Long.toString(currentTime.toMillis()));
|
||||||
|
|
||||||
|
final Cursor cursor1 = getCursorOfBatteryStateLatestTimestamp(currentTime.toMillis() - 5);
|
||||||
|
assertThat(cursor1.getCount()).isEqualTo(1);
|
||||||
|
cursor1.moveToFirst();
|
||||||
|
final long latestTimestamp1 = cursor1.getLong(0);
|
||||||
|
assertThat(latestTimestamp1).isEqualTo(currentTime.toMillis() - 6);
|
||||||
|
|
||||||
|
final Cursor cursor2 = getCursorOfBatteryStateLatestTimestamp(currentTime.toMillis() - 2);
|
||||||
|
assertThat(cursor2.getCount()).isEqualTo(1);
|
||||||
|
cursor2.moveToFirst();
|
||||||
|
final long latestTimestamp2 = cursor2.getLong(0);
|
||||||
|
assertThat(latestTimestamp2).isEqualTo(currentTime.toMillis() - 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -355,7 +377,7 @@ public final class BatteryUsageContentProviderTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void insert_batteryEvent_returnsExpectedResult() {
|
public void insertAndQuery_batteryEvent_returnsExpectedResult() {
|
||||||
mProvider.onCreate();
|
mProvider.onCreate();
|
||||||
ContentValues values = new ContentValues();
|
ContentValues values = new ContentValues();
|
||||||
values.put(BatteryEventEntity.KEY_TIMESTAMP, 10001L);
|
values.put(BatteryEventEntity.KEY_TIMESTAMP, 10001L);
|
||||||
@@ -366,7 +388,7 @@ public final class BatteryUsageContentProviderTest {
|
|||||||
final Uri uri = mProvider.insert(DatabaseUtils.BATTERY_EVENT_URI, values);
|
final Uri uri = mProvider.insert(DatabaseUtils.BATTERY_EVENT_URI, values);
|
||||||
|
|
||||||
assertThat(uri).isEqualTo(DatabaseUtils.BATTERY_EVENT_URI);
|
assertThat(uri).isEqualTo(DatabaseUtils.BATTERY_EVENT_URI);
|
||||||
// Verifies the AppUsageEventEntity content.
|
// Verifies the BatteryEventEntity content.
|
||||||
final List<BatteryEventEntity> entities =
|
final List<BatteryEventEntity> entities =
|
||||||
BatteryStateDatabase.getInstance(mContext).batteryEventDao().getAll();
|
BatteryStateDatabase.getInstance(mContext).batteryEventDao().getAll();
|
||||||
assertThat(entities).hasSize(1);
|
assertThat(entities).hasSize(1);
|
||||||
@@ -374,6 +396,50 @@ public final class BatteryUsageContentProviderTest {
|
|||||||
assertThat(entities.get(0).batteryEventType).isEqualTo(
|
assertThat(entities.get(0).batteryEventType).isEqualTo(
|
||||||
BatteryEventType.POWER_CONNECTED.getNumber());
|
BatteryEventType.POWER_CONNECTED.getNumber());
|
||||||
assertThat(entities.get(0).batteryLevel).isEqualTo(66);
|
assertThat(entities.get(0).batteryLevel).isEqualTo(66);
|
||||||
|
|
||||||
|
final Cursor cursor1 = getCursorOfBatteryEvents(
|
||||||
|
0L, List.of(BatteryEventType.POWER_CONNECTED.getNumber()));
|
||||||
|
assertThat(cursor1.getCount()).isEqualTo(1);
|
||||||
|
cursor1.moveToFirst();
|
||||||
|
assertThat(cursor1.getLong(cursor1.getColumnIndex(BatteryEventEntity.KEY_TIMESTAMP)))
|
||||||
|
.isEqualTo(10001L);
|
||||||
|
assertThat(
|
||||||
|
cursor1.getInt(cursor1.getColumnIndex(BatteryEventEntity.KEY_BATTERY_EVENT_TYPE)))
|
||||||
|
.isEqualTo(BatteryEventType.POWER_CONNECTED.getNumber());
|
||||||
|
assertThat(cursor1.getInt(cursor1.getColumnIndex(BatteryEventEntity.KEY_BATTERY_LEVEL)))
|
||||||
|
.isEqualTo(66);
|
||||||
|
|
||||||
|
final Cursor cursor2 = getCursorOfBatteryEvents(
|
||||||
|
0L, List.of(BatteryEventType.POWER_DISCONNECTED.getNumber()));
|
||||||
|
assertThat(cursor2.getCount()).isEqualTo(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void insertAndQuery_batteryUsageSlot_returnsExpectedResult() {
|
||||||
|
mProvider.onCreate();
|
||||||
|
ContentValues values = new ContentValues();
|
||||||
|
values.put(BatteryUsageSlotEntity.KEY_TIMESTAMP, 10001L);
|
||||||
|
values.put(BatteryUsageSlotEntity.KEY_BATTERY_USAGE_SLOT, "TEST_STRING");
|
||||||
|
|
||||||
|
final Uri uri = mProvider.insert(DatabaseUtils.BATTERY_USAGE_SLOT_URI, values);
|
||||||
|
// Verifies the BatteryUsageSlotEntity content.
|
||||||
|
assertThat(uri).isEqualTo(DatabaseUtils.BATTERY_USAGE_SLOT_URI);
|
||||||
|
final List<BatteryUsageSlotEntity> entities =
|
||||||
|
BatteryStateDatabase.getInstance(mContext).batteryUsageSlotDao().getAll();
|
||||||
|
assertThat(entities).hasSize(1);
|
||||||
|
assertThat(entities.get(0).timestamp).isEqualTo(10001L);
|
||||||
|
assertThat(entities.get(0).batteryUsageSlot).isEqualTo("TEST_STRING");
|
||||||
|
|
||||||
|
final Cursor cursor1 = getCursorOfBatteryUsageSlots(10001L);
|
||||||
|
assertThat(cursor1.getCount()).isEqualTo(1);
|
||||||
|
cursor1.moveToFirst();
|
||||||
|
assertThat(cursor1.getLong(cursor1.getColumnIndex(BatteryUsageSlotEntity.KEY_TIMESTAMP)))
|
||||||
|
.isEqualTo(10001L);
|
||||||
|
assertThat(cursor1.getString(cursor1.getColumnIndex(
|
||||||
|
BatteryUsageSlotEntity.KEY_BATTERY_USAGE_SLOT))).isEqualTo("TEST_STRING");
|
||||||
|
|
||||||
|
final Cursor cursor2 = getCursorOfBatteryUsageSlots(10002L);
|
||||||
|
assertThat(cursor2.getCount()).isEqualTo(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -404,10 +470,10 @@ public final class BatteryUsageContentProviderTest {
|
|||||||
final long currentTimestamp = currentTime.toMillis();
|
final long currentTimestamp = currentTime.toMillis();
|
||||||
// Inserts some valid testing data.
|
// Inserts some valid testing data.
|
||||||
BatteryTestUtils.insertDataToBatteryStateTable(
|
BatteryTestUtils.insertDataToBatteryStateTable(
|
||||||
mContext, currentTimestamp - 2, PACKAGE_NAME1,
|
mContext, currentTimestamp - 6, PACKAGE_NAME1,
|
||||||
/*isFullChargeStart=*/ true);
|
/*isFullChargeStart=*/ true);
|
||||||
BatteryTestUtils.insertDataToBatteryStateTable(
|
BatteryTestUtils.insertDataToBatteryStateTable(
|
||||||
mContext, currentTimestamp - 1, PACKAGE_NAME2);
|
mContext, currentTimestamp - 2, PACKAGE_NAME2);
|
||||||
BatteryTestUtils.insertDataToBatteryStateTable(
|
BatteryTestUtils.insertDataToBatteryStateTable(
|
||||||
mContext, currentTimestamp, PACKAGE_NAME3);
|
mContext, currentTimestamp, PACKAGE_NAME3);
|
||||||
|
|
||||||
@@ -420,17 +486,35 @@ public final class BatteryUsageContentProviderTest {
|
|||||||
DatabaseUtils.QUERY_KEY_TIMESTAMP, queryTimestamp)
|
DatabaseUtils.QUERY_KEY_TIMESTAMP, queryTimestamp)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
final Cursor cursor =
|
final Cursor cursor = query(batteryStateQueryContentUri);
|
||||||
mProvider.query(
|
|
||||||
batteryStateQueryContentUri,
|
|
||||||
/*strings=*/ null,
|
|
||||||
/*s=*/ null,
|
|
||||||
/*strings1=*/ null,
|
|
||||||
/*s1=*/ null);
|
|
||||||
|
|
||||||
return cursor;
|
return cursor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Cursor getCursorOfLastFullChargeTimestamp() {
|
||||||
|
final Uri lastFullChargeTimestampContentUri =
|
||||||
|
new Uri.Builder()
|
||||||
|
.scheme(ContentResolver.SCHEME_CONTENT)
|
||||||
|
.authority(DatabaseUtils.AUTHORITY)
|
||||||
|
.appendPath(DatabaseUtils.LAST_FULL_CHARGE_TIMESTAMP_PATH)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
return query(lastFullChargeTimestampContentUri);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Cursor getCursorOfBatteryStateLatestTimestamp(final long queryTimestamp) {
|
||||||
|
final Uri batteryStateLatestTimestampUri =
|
||||||
|
new Uri.Builder()
|
||||||
|
.scheme(ContentResolver.SCHEME_CONTENT)
|
||||||
|
.authority(DatabaseUtils.AUTHORITY)
|
||||||
|
.appendPath(DatabaseUtils.BATTERY_STATE_LATEST_TIMESTAMP_PATH)
|
||||||
|
.appendQueryParameter(
|
||||||
|
DatabaseUtils.QUERY_KEY_TIMESTAMP, Long.toString(queryTimestamp))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
return query(batteryStateLatestTimestampUri);
|
||||||
|
}
|
||||||
|
|
||||||
private void insertAppUsageEvent() {
|
private void insertAppUsageEvent() {
|
||||||
mProvider.onCreate();
|
mProvider.onCreate();
|
||||||
// Inserts some valid testing data.
|
// Inserts some valid testing data.
|
||||||
@@ -452,12 +536,7 @@ public final class BatteryUsageContentProviderTest {
|
|||||||
DatabaseUtils.QUERY_KEY_USERID, Long.toString(userId))
|
DatabaseUtils.QUERY_KEY_USERID, Long.toString(userId))
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
return mProvider.query(
|
return query(appUsageLatestTimestampQueryContentUri);
|
||||||
appUsageLatestTimestampQueryContentUri,
|
|
||||||
/*strings=*/ null,
|
|
||||||
/*s=*/ null,
|
|
||||||
/*strings1=*/ null,
|
|
||||||
/*s1=*/ null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Cursor getCursorOfAppUsage(final List<Long> userIds, final long queryTimestamp) {
|
private Cursor getCursorOfAppUsage(final List<Long> userIds, final long queryTimestamp) {
|
||||||
@@ -474,7 +553,43 @@ public final class BatteryUsageContentProviderTest {
|
|||||||
.appendQueryParameter(DatabaseUtils.QUERY_KEY_USERID, queryUserIdString)
|
.appendQueryParameter(DatabaseUtils.QUERY_KEY_USERID, queryUserIdString)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
|
return query(appUsageEventUri);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Cursor getCursorOfBatteryEvents(
|
||||||
|
final long queryTimestamp, final List<Integer> batteryEventTypes) {
|
||||||
|
final String batteryEventTypesString = batteryEventTypes.stream()
|
||||||
|
.map(type -> String.valueOf(type))
|
||||||
|
.collect(Collectors.joining(","));
|
||||||
|
final Uri batteryEventUri =
|
||||||
|
new Uri.Builder()
|
||||||
|
.scheme(ContentResolver.SCHEME_CONTENT)
|
||||||
|
.authority(DatabaseUtils.AUTHORITY)
|
||||||
|
.appendPath(DatabaseUtils.BATTERY_EVENT_TABLE)
|
||||||
|
.appendQueryParameter(
|
||||||
|
DatabaseUtils.QUERY_KEY_TIMESTAMP, Long.toString(queryTimestamp))
|
||||||
|
.appendQueryParameter(
|
||||||
|
DatabaseUtils.QUERY_BATTERY_EVENT_TYPE, batteryEventTypesString)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
return query(batteryEventUri);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Cursor getCursorOfBatteryUsageSlots(final long queryTimestamp) {
|
||||||
|
final Uri batteryUsageSlotUri =
|
||||||
|
new Uri.Builder()
|
||||||
|
.scheme(ContentResolver.SCHEME_CONTENT)
|
||||||
|
.authority(DatabaseUtils.AUTHORITY)
|
||||||
|
.appendPath(DatabaseUtils.BATTERY_USAGE_SLOT_TABLE)
|
||||||
|
.appendQueryParameter(
|
||||||
|
DatabaseUtils.QUERY_KEY_TIMESTAMP, Long.toString(queryTimestamp))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
return query(batteryUsageSlotUri);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Cursor query(Uri uri) {
|
||||||
return mProvider.query(
|
return mProvider.query(
|
||||||
appUsageEventUri, /*strings=*/ null, /*s=*/ null, /*strings1=*/ null, /*s1=*/ null);
|
uri, /*strings=*/ null, /*s=*/ null, /*strings1=*/ null, /*s1=*/ null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -22,6 +22,7 @@ import static org.mockito.ArgumentMatchers.any;
|
|||||||
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 static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
import android.content.ContentResolver;
|
import android.content.ContentResolver;
|
||||||
@@ -31,6 +32,7 @@ import android.content.pm.PackageManager;
|
|||||||
import android.os.BatteryStatsManager;
|
import android.os.BatteryStatsManager;
|
||||||
import android.os.BatteryUsageStats;
|
import android.os.BatteryUsageStats;
|
||||||
import android.os.BatteryUsageStatsQuery;
|
import android.os.BatteryUsageStatsQuery;
|
||||||
|
import android.os.UserManager;
|
||||||
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
@@ -43,6 +45,7 @@ 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;
|
||||||
|
|
||||||
@RunWith(RobolectricTestRunner.class)
|
@RunWith(RobolectricTestRunner.class)
|
||||||
@@ -56,6 +59,8 @@ public final class BatteryUsageDataLoaderTest {
|
|||||||
@Mock
|
@Mock
|
||||||
private PackageManager mPackageManager;
|
private PackageManager mPackageManager;
|
||||||
@Mock
|
@Mock
|
||||||
|
private UserManager mUserManager;
|
||||||
|
@Mock
|
||||||
private BatteryUsageStats mBatteryUsageStats;
|
private BatteryUsageStats mBatteryUsageStats;
|
||||||
@Mock
|
@Mock
|
||||||
private BatteryEntry mMockBatteryEntry;
|
private BatteryEntry mMockBatteryEntry;
|
||||||
@@ -70,6 +75,7 @@ public final class BatteryUsageDataLoaderTest {
|
|||||||
doReturn(mBatteryStatsManager).when(mContext).getSystemService(
|
doReturn(mBatteryStatsManager).when(mContext).getSystemService(
|
||||||
Context.BATTERY_STATS_SERVICE);
|
Context.BATTERY_STATS_SERVICE);
|
||||||
doReturn(mPackageManager).when(mContext).getPackageManager();
|
doReturn(mPackageManager).when(mContext).getPackageManager();
|
||||||
|
doReturn(mUserManager).when(mContext).getSystemService(UserManager.class);
|
||||||
doReturn(mMockContentResolver).when(mContext).getContentResolver();
|
doReturn(mMockContentResolver).when(mContext).getContentResolver();
|
||||||
doReturn(new Intent()).when(mContext).registerReceiver(any(), any());
|
doReturn(new Intent()).when(mContext).registerReceiver(any(), any());
|
||||||
}
|
}
|
||||||
@@ -82,7 +88,7 @@ public final class BatteryUsageDataLoaderTest {
|
|||||||
.thenReturn(mBatteryUsageStats);
|
.thenReturn(mBatteryUsageStats);
|
||||||
BatteryUsageDataLoader.sFakeBatteryEntryListSupplier = () -> batteryEntryList;
|
BatteryUsageDataLoader.sFakeBatteryEntryListSupplier = () -> batteryEntryList;
|
||||||
|
|
||||||
BatteryUsageDataLoader.loadUsageData(mContext, /*isFullChargeStart=*/ false);
|
BatteryUsageDataLoader.loadBatteryStatsData(mContext, /*isFullChargeStart=*/ false);
|
||||||
|
|
||||||
final int queryFlags = mStatsQueryCaptor.getValue().getFlags();
|
final int queryFlags = mStatsQueryCaptor.getValue().getFlags();
|
||||||
assertThat(queryFlags
|
assertThat(queryFlags
|
||||||
@@ -97,7 +103,7 @@ public final class BatteryUsageDataLoaderTest {
|
|||||||
.thenReturn(mBatteryUsageStats);
|
.thenReturn(mBatteryUsageStats);
|
||||||
BatteryUsageDataLoader.sFakeBatteryEntryListSupplier = () -> null;
|
BatteryUsageDataLoader.sFakeBatteryEntryListSupplier = () -> null;
|
||||||
|
|
||||||
BatteryUsageDataLoader.loadUsageData(mContext, /*isFullChargeStart=*/ false);
|
BatteryUsageDataLoader.loadBatteryStatsData(mContext, /*isFullChargeStart=*/ false);
|
||||||
|
|
||||||
verify(mMockContentResolver).insert(any(), any());
|
verify(mMockContentResolver).insert(any(), any());
|
||||||
}
|
}
|
||||||
@@ -108,8 +114,51 @@ public final class BatteryUsageDataLoaderTest {
|
|||||||
.thenReturn(mBatteryUsageStats);
|
.thenReturn(mBatteryUsageStats);
|
||||||
BatteryUsageDataLoader.sFakeBatteryEntryListSupplier = () -> new ArrayList<>();
|
BatteryUsageDataLoader.sFakeBatteryEntryListSupplier = () -> new ArrayList<>();
|
||||||
|
|
||||||
BatteryUsageDataLoader.loadUsageData(mContext, /*isFullChargeStart=*/ false);
|
BatteryUsageDataLoader.loadBatteryStatsData(mContext, /*isFullChargeStart=*/ false);
|
||||||
|
|
||||||
verify(mMockContentResolver).insert(any(), any());
|
verify(mMockContentResolver).insert(any(), any());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void loadAppUsageData_withData_insertFakeDataIntoProvider() {
|
||||||
|
final List<AppUsageEvent> AppUsageEventList = new ArrayList<>();
|
||||||
|
final AppUsageEvent appUsageEvent = AppUsageEvent.newBuilder().setUid(0).build();
|
||||||
|
AppUsageEventList.add(appUsageEvent);
|
||||||
|
BatteryUsageDataLoader.sFakeAppUsageEventsSupplier = () -> new HashMap<>();
|
||||||
|
BatteryUsageDataLoader.sFakeUsageEventsListSupplier = () -> AppUsageEventList;
|
||||||
|
|
||||||
|
BatteryUsageDataLoader.loadAppUsageData(mContext);
|
||||||
|
|
||||||
|
verify(mMockContentResolver).bulkInsert(any(), any());
|
||||||
|
verify(mMockContentResolver).notifyChange(any(), any());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void loadAppUsageData_nullAppUsageEvents_notInsertDataIntoProvider() {
|
||||||
|
BatteryUsageDataLoader.sFakeAppUsageEventsSupplier = () -> null;
|
||||||
|
|
||||||
|
BatteryUsageDataLoader.loadAppUsageData(mContext);
|
||||||
|
|
||||||
|
verifyNoMoreInteractions(mMockContentResolver);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void loadAppUsageData_nullUsageEventsList_notInsertDataIntoProvider() {
|
||||||
|
BatteryUsageDataLoader.sFakeAppUsageEventsSupplier = () -> new HashMap<>();
|
||||||
|
BatteryUsageDataLoader.sFakeUsageEventsListSupplier = () -> null;
|
||||||
|
|
||||||
|
BatteryUsageDataLoader.loadAppUsageData(mContext);
|
||||||
|
|
||||||
|
verifyNoMoreInteractions(mMockContentResolver);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void loadAppUsageData_emptyUsageEventsList_notInsertDataIntoProvider() {
|
||||||
|
BatteryUsageDataLoader.sFakeAppUsageEventsSupplier = () -> new HashMap<>();
|
||||||
|
BatteryUsageDataLoader.sFakeUsageEventsListSupplier = () -> new ArrayList<>();
|
||||||
|
|
||||||
|
BatteryUsageDataLoader.loadAppUsageData(mContext);
|
||||||
|
|
||||||
|
verifyNoMoreInteractions(mMockContentResolver);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -39,6 +39,7 @@ import android.os.UserHandle;
|
|||||||
|
|
||||||
import com.android.settings.fuelgauge.batteryusage.db.AppUsageEventEntity;
|
import com.android.settings.fuelgauge.batteryusage.db.AppUsageEventEntity;
|
||||||
import com.android.settings.fuelgauge.batteryusage.db.BatteryEventEntity;
|
import com.android.settings.fuelgauge.batteryusage.db.BatteryEventEntity;
|
||||||
|
import com.android.settings.fuelgauge.batteryusage.db.BatteryUsageSlotEntity;
|
||||||
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
@@ -48,7 +49,10 @@ import org.mockito.MockitoAnnotations;
|
|||||||
import org.robolectric.RobolectricTestRunner;
|
import org.robolectric.RobolectricTestRunner;
|
||||||
import org.robolectric.RuntimeEnvironment;
|
import org.robolectric.RuntimeEnvironment;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.TimeZone;
|
import java.util.TimeZone;
|
||||||
|
|
||||||
@RunWith(RobolectricTestRunner.class)
|
@RunWith(RobolectricTestRunner.class)
|
||||||
@@ -212,6 +216,22 @@ public final class ConvertUtilsTest {
|
|||||||
assertThat(values.getAsInteger(BatteryEventEntity.KEY_BATTERY_LEVEL)).isEqualTo(66);
|
assertThat(values.getAsInteger(BatteryEventEntity.KEY_BATTERY_LEVEL)).isEqualTo(66);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void convertBatteryUsageSlotToContentValues_normalCase_returnsExpectedContentValues() {
|
||||||
|
final BatteryUsageSlot batteryUsageSlot =
|
||||||
|
BatteryUsageSlot.newBuilder()
|
||||||
|
.setStartTimestamp(10001L)
|
||||||
|
.setEndTimestamp(30003L)
|
||||||
|
.setStartBatteryLevel(88)
|
||||||
|
.setEndBatteryLevel(66)
|
||||||
|
.setScreenOnTime(123L)
|
||||||
|
.build();
|
||||||
|
final ContentValues values =
|
||||||
|
ConvertUtils.convertBatteryUsageSlotToContentValues(batteryUsageSlot);
|
||||||
|
assertThat(values.getAsLong(BatteryUsageSlotEntity.KEY_TIMESTAMP)).isEqualTo(10001L);
|
||||||
|
assertThat(BatteryUsageSlotEntity.KEY_BATTERY_USAGE_SLOT).isNotEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void convertToBatteryHistEntry_returnsExpectedResult() {
|
public void convertToBatteryHistEntry_returnsExpectedResult() {
|
||||||
final int expectedType = 3;
|
final int expectedType = 3;
|
||||||
@@ -363,7 +383,7 @@ public final class ConvertUtilsTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void convertToAppUsageEventFromCursor_returnExpectedResult() {
|
public void convertToAppUsageEvent_returnExpectedResult() {
|
||||||
final MatrixCursor cursor = new MatrixCursor(
|
final MatrixCursor cursor = new MatrixCursor(
|
||||||
new String[]{
|
new String[]{
|
||||||
AppUsageEventEntity.KEY_UID,
|
AppUsageEventEntity.KEY_UID,
|
||||||
@@ -384,7 +404,7 @@ public final class ConvertUtilsTest {
|
|||||||
100001L});
|
100001L});
|
||||||
cursor.moveToFirst();
|
cursor.moveToFirst();
|
||||||
|
|
||||||
final AppUsageEvent appUsageEvent = ConvertUtils.convertToAppUsageEventFromCursor(cursor);
|
final AppUsageEvent appUsageEvent = ConvertUtils.convertToAppUsageEvent(cursor);
|
||||||
|
|
||||||
assertThat(appUsageEvent.getUid()).isEqualTo(101L);
|
assertThat(appUsageEvent.getUid()).isEqualTo(101L);
|
||||||
assertThat(appUsageEvent.getUserId()).isEqualTo(1001L);
|
assertThat(appUsageEvent.getUserId()).isEqualTo(1001L);
|
||||||
@@ -396,7 +416,7 @@ public final class ConvertUtilsTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void convertToAppUsageEventFromCursor_emptyInstanceIdAndRootName_returnExpectedResult() {
|
public void convertToAppUsageEvent_emptyInstanceIdAndRootName_returnExpectedResult() {
|
||||||
final MatrixCursor cursor = new MatrixCursor(
|
final MatrixCursor cursor = new MatrixCursor(
|
||||||
new String[]{
|
new String[]{
|
||||||
AppUsageEventEntity.KEY_UID,
|
AppUsageEventEntity.KEY_UID,
|
||||||
@@ -413,7 +433,7 @@ public final class ConvertUtilsTest {
|
|||||||
AppUsageEventType.DEVICE_SHUTDOWN.getNumber()});
|
AppUsageEventType.DEVICE_SHUTDOWN.getNumber()});
|
||||||
cursor.moveToFirst();
|
cursor.moveToFirst();
|
||||||
|
|
||||||
final AppUsageEvent appUsageEvent = ConvertUtils.convertToAppUsageEventFromCursor(cursor);
|
final AppUsageEvent appUsageEvent = ConvertUtils.convertToAppUsageEvent(cursor);
|
||||||
|
|
||||||
assertThat(appUsageEvent.getUid()).isEqualTo(101L);
|
assertThat(appUsageEvent.getUid()).isEqualTo(101L);
|
||||||
assertThat(appUsageEvent.getUserId()).isEqualTo(1001L);
|
assertThat(appUsageEvent.getUserId()).isEqualTo(1001L);
|
||||||
@@ -433,6 +453,42 @@ public final class ConvertUtilsTest {
|
|||||||
assertThat(batteryEvent.getBatteryLevel()).isEqualTo(88);
|
assertThat(batteryEvent.getBatteryLevel()).isEqualTo(88);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void convertToBatteryEventList_normalCase_returnsExpectedResult() {
|
||||||
|
final BatteryLevelData batteryLevelData = new BatteryLevelData(Map.of(
|
||||||
|
1691589600000L, 98, 1691596800000L, 90, 1691596812345L, 80));
|
||||||
|
|
||||||
|
final List<BatteryEvent> batteryEventList =
|
||||||
|
ConvertUtils.convertToBatteryEventList(batteryLevelData);
|
||||||
|
|
||||||
|
assertThat(batteryEventList).hasSize(2);
|
||||||
|
assertThat(batteryEventList.get(0).getTimestamp()).isEqualTo(1691589600000L);
|
||||||
|
assertThat(batteryEventList.get(0).getType()).isEqualTo(BatteryEventType.EVEN_HOUR);
|
||||||
|
assertThat(batteryEventList.get(0).getBatteryLevel()).isEqualTo(98);
|
||||||
|
assertThat(batteryEventList.get(1).getTimestamp()).isEqualTo(1691596800000L);
|
||||||
|
assertThat(batteryEventList.get(1).getType()).isEqualTo(BatteryEventType.EVEN_HOUR);
|
||||||
|
assertThat(batteryEventList.get(1).getBatteryLevel()).isEqualTo(90);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void convertToBatteryUsageSlotList_normalCase_returnsExpectedResult() {
|
||||||
|
BatteryDiffData batteryDiffData1 = new BatteryDiffData(
|
||||||
|
mContext, 11L, 12L, 13, 14, 15, List.of(), List.of(), Set.of(), Set.of(), false);
|
||||||
|
BatteryDiffData batteryDiffData2 = new BatteryDiffData(
|
||||||
|
mContext, 21L, 22L, 23, 24, 25, List.of(), List.of(), Set.of(), Set.of(), false);
|
||||||
|
BatteryDiffData batteryDiffData3 = new BatteryDiffData(
|
||||||
|
mContext, 31L, 32L, 33, 34, 35, List.of(), List.of(), Set.of(), Set.of(), false);
|
||||||
|
final Map<Long, BatteryDiffData> batteryDiffDataMap = Map.of(
|
||||||
|
11L, batteryDiffData1, 21L, batteryDiffData2, 31L, batteryDiffData3);
|
||||||
|
|
||||||
|
final List<BatteryUsageSlot> batteryUsageSlotList =
|
||||||
|
ConvertUtils.convertToBatteryUsageSlotList(batteryDiffDataMap);
|
||||||
|
|
||||||
|
assertThat(batteryUsageSlotList).hasSize(3);
|
||||||
|
assertThat(batteryUsageSlotList.stream().map((s) -> s.getScreenOnTime()).sorted().toList())
|
||||||
|
.isEqualTo(List.of(15L, 25L, 35L));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getLocale_nullContext_returnDefaultLocale() {
|
public void getLocale_nullContext_returnDefaultLocale() {
|
||||||
assertThat(ConvertUtils.getLocale(/*context=*/ null))
|
assertThat(ConvertUtils.getLocale(/*context=*/ null))
|
||||||
|
@@ -30,8 +30,12 @@ import android.app.usage.UsageEvents;
|
|||||||
import android.content.ContentValues;
|
import android.content.ContentValues;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
import android.database.Cursor;
|
||||||
import android.database.MatrixCursor;
|
import android.database.MatrixCursor;
|
||||||
import android.os.BatteryManager;
|
import android.os.BatteryManager;
|
||||||
|
import android.os.BatteryStatsManager;
|
||||||
|
import android.os.BatteryUsageStats;
|
||||||
|
import android.os.BatteryUsageStatsQuery;
|
||||||
import android.os.Parcel;
|
import android.os.Parcel;
|
||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
import android.os.UserManager;
|
import android.os.UserManager;
|
||||||
@@ -39,9 +43,12 @@ import android.text.format.DateUtils;
|
|||||||
|
|
||||||
import com.android.settings.fuelgauge.batteryusage.db.AppUsageEventEntity;
|
import com.android.settings.fuelgauge.batteryusage.db.AppUsageEventEntity;
|
||||||
|
|
||||||
|
import org.junit.After;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.ArgumentCaptor;
|
||||||
|
import org.mockito.Captor;
|
||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
import org.mockito.MockitoAnnotations;
|
import org.mockito.MockitoAnnotations;
|
||||||
import org.robolectric.RobolectricTestRunner;
|
import org.robolectric.RobolectricTestRunner;
|
||||||
@@ -52,6 +59,7 @@ import java.util.Collections;
|
|||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
@RunWith(RobolectricTestRunner.class)
|
@RunWith(RobolectricTestRunner.class)
|
||||||
public final class DataProcessManagerTest {
|
public final class DataProcessManagerTest {
|
||||||
@@ -65,7 +73,13 @@ public final class DataProcessManagerTest {
|
|||||||
@Mock
|
@Mock
|
||||||
private UserManager mUserManager;
|
private UserManager mUserManager;
|
||||||
@Mock
|
@Mock
|
||||||
|
private BatteryStatsManager mBatteryStatsManager;
|
||||||
|
@Mock
|
||||||
|
private BatteryUsageStats mBatteryUsageStats;
|
||||||
|
@Mock
|
||||||
private Intent mIntent;
|
private Intent mIntent;
|
||||||
|
@Captor
|
||||||
|
private ArgumentCaptor<BatteryUsageStatsQuery> mBatteryUsageStatsQueryCaptor;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
@@ -77,22 +91,32 @@ public final class DataProcessManagerTest {
|
|||||||
doReturn(mUserManager)
|
doReturn(mUserManager)
|
||||||
.when(mContext)
|
.when(mContext)
|
||||||
.getSystemService(UserManager.class);
|
.getSystemService(UserManager.class);
|
||||||
|
doReturn(mBatteryStatsManager).when(mContext).getSystemService(
|
||||||
|
Context.BATTERY_STATS_SERVICE);
|
||||||
|
doReturn(mBatteryUsageStats).when(
|
||||||
|
mBatteryStatsManager).getBatteryUsageStats(mBatteryUsageStatsQueryCaptor.capture());
|
||||||
doReturn(mIntent).when(mContext).registerReceiver(any(), any());
|
doReturn(mIntent).when(mContext).registerReceiver(any(), any());
|
||||||
doReturn(100).when(mIntent).getIntExtra(eq(BatteryManager.EXTRA_SCALE), anyInt());
|
doReturn(100).when(mIntent).getIntExtra(eq(BatteryManager.EXTRA_SCALE), anyInt());
|
||||||
doReturn(66).when(mIntent).getIntExtra(eq(BatteryManager.EXTRA_LEVEL), anyInt());
|
doReturn(66).when(mIntent).getIntExtra(eq(BatteryManager.EXTRA_LEVEL), anyInt());
|
||||||
|
|
||||||
mDataProcessManager = new DataProcessManager(
|
mDataProcessManager = new DataProcessManager(
|
||||||
mContext, /*handler=*/ null, /*rawStartTimestamp=*/ 0L,
|
mContext, /*handler=*/ null, /*rawStartTimestamp=*/ 0L,
|
||||||
/*callbackFunction=*/ null, /*hourlyBatteryLevelsPerDay=*/ new ArrayList<>(),
|
/*lastFullChargeTimestamp=*/ 0L, /*callbackFunction=*/ null,
|
||||||
|
/*hourlyBatteryLevelsPerDay=*/ new ArrayList<>(),
|
||||||
/*batteryHistoryMap=*/ new HashMap<>());
|
/*batteryHistoryMap=*/ new HashMap<>());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void cleanUp() {
|
||||||
|
DatabaseUtils.sFakeSupplier = null;
|
||||||
|
DataProcessManager.sFakeBatteryHistoryMap = null;
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void constructor_noLevelData() {
|
public void constructor_noLevelData() {
|
||||||
final DataProcessManager dataProcessManager =
|
final DataProcessManager dataProcessManager =
|
||||||
new DataProcessManager(mContext, /*handler=*/ null, /*callbackFunction=*/ null);
|
new DataProcessManager(mContext, /*handler=*/ null, /*callbackFunction=*/ null);
|
||||||
assertThat(dataProcessManager.getShowScreenOnTime()).isFalse();
|
assertThat(dataProcessManager.getShowScreenOnTime()).isFalse();
|
||||||
assertThat(dataProcessManager.getShowBatteryLevel()).isFalse();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -122,16 +146,18 @@ public final class DataProcessManagerTest {
|
|||||||
final String packageName = "package";
|
final String packageName = "package";
|
||||||
// Adds the day 1 data.
|
// Adds the day 1 data.
|
||||||
final List<Long> timestamps1 = List.of(2L, 3L, 4L);
|
final List<Long> timestamps1 = List.of(2L, 3L, 4L);
|
||||||
final List<Integer> levels1 = List.of(100, 100, 100);
|
final Map<Long, Integer> batteryLevelMap1 =
|
||||||
|
Map.of(timestamps1.get(0), 100, timestamps1.get(1), 100, timestamps1.get(2), 100);
|
||||||
hourlyBatteryLevelsPerDay.add(
|
hourlyBatteryLevelsPerDay.add(
|
||||||
new BatteryLevelData.PeriodBatteryLevelData(timestamps1, levels1));
|
new BatteryLevelData.PeriodBatteryLevelData(batteryLevelMap1, timestamps1));
|
||||||
// Adds the day 2 data.
|
// Adds the day 2 data.
|
||||||
hourlyBatteryLevelsPerDay.add(null);
|
hourlyBatteryLevelsPerDay.add(null);
|
||||||
// Adds the day 3 data.
|
// Adds the day 3 data.
|
||||||
final List<Long> timestamps2 = List.of(5L, 6L);
|
final List<Long> timestamps2 = List.of(5L, 6L);
|
||||||
final List<Integer> levels2 = List.of(100, 100);
|
final Map<Long, Integer> batteryLevelMap2 =
|
||||||
|
Map.of(timestamps2.get(0), 100, timestamps2.get(1), 100);
|
||||||
hourlyBatteryLevelsPerDay.add(
|
hourlyBatteryLevelsPerDay.add(
|
||||||
new BatteryLevelData.PeriodBatteryLevelData(timestamps2, levels2));
|
new BatteryLevelData.PeriodBatteryLevelData(batteryLevelMap2, timestamps2));
|
||||||
// Fake current usage data.
|
// Fake current usage data.
|
||||||
final UsageEvents.Event event1 =
|
final UsageEvents.Event event1 =
|
||||||
getUsageEvent(UsageEvents.Event.ACTIVITY_RESUMED, /*timestamp=*/ 1, packageName);
|
getUsageEvent(UsageEvents.Event.ACTIVITY_RESUMED, /*timestamp=*/ 1, packageName);
|
||||||
@@ -171,10 +197,18 @@ public final class DataProcessManagerTest {
|
|||||||
cursor.addRow(new Object[] {
|
cursor.addRow(new Object[] {
|
||||||
AppUsageEventType.ACTIVITY_STOPPED.getNumber(), /*timestamp=*/ 6, /*userId=*/ 1,
|
AppUsageEventType.ACTIVITY_STOPPED.getNumber(), /*timestamp=*/ 6, /*userId=*/ 1,
|
||||||
/*instanceId=*/ 2, packageName});
|
/*instanceId=*/ 2, packageName});
|
||||||
DatabaseUtils.sFakeSupplier = () -> cursor;
|
DatabaseUtils.sFakeSupplier = new Supplier<>() {
|
||||||
|
private int mTimes = 0;
|
||||||
|
@Override
|
||||||
|
public Cursor get() {
|
||||||
|
mTimes++;
|
||||||
|
return mTimes <= 2 ? null : cursor;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
final DataProcessManager dataProcessManager = new DataProcessManager(
|
final DataProcessManager dataProcessManager = new DataProcessManager(
|
||||||
mContext, /*handler=*/ null, /*rawStartTimestamp=*/ 2L, /*callbackFunction=*/ null,
|
mContext, /*handler=*/ null, /*rawStartTimestamp=*/ 2L,
|
||||||
|
/*lastFullChargeTimestamp=*/ 1L, /*callbackFunction=*/ null,
|
||||||
hourlyBatteryLevelsPerDay, /*batteryHistoryMap=*/ new HashMap<>());
|
hourlyBatteryLevelsPerDay, /*batteryHistoryMap=*/ new HashMap<>());
|
||||||
dataProcessManager.start();
|
dataProcessManager.start();
|
||||||
|
|
||||||
@@ -254,12 +288,13 @@ public final class DataProcessManagerTest {
|
|||||||
assertThat(DataProcessManager.getBatteryLevelData(
|
assertThat(DataProcessManager.getBatteryLevelData(
|
||||||
mContext,
|
mContext,
|
||||||
/*handler=*/ null,
|
/*handler=*/ null,
|
||||||
/*batteryHistoryMap=*/ null,
|
/*isFromPeriodJob=*/ false,
|
||||||
/*asyncResponseDelegate=*/ null))
|
/*asyncResponseDelegate=*/ null)).isNull();
|
||||||
.isNull();
|
|
||||||
assertThat(DataProcessManager.getBatteryLevelData(
|
assertThat(DataProcessManager.getBatteryLevelData(
|
||||||
mContext, /*handler=*/ null, new HashMap<>(), /*asyncResponseDelegate=*/ null))
|
mContext,
|
||||||
.isNull();
|
/*handler=*/ null,
|
||||||
|
/*isFromPeriodJob=*/ true,
|
||||||
|
/*asyncResponseDelegate=*/ null)).isNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -270,18 +305,16 @@ public final class DataProcessManagerTest {
|
|||||||
DateUtils.HOUR_IN_MILLIS * 2 - 200L,
|
DateUtils.HOUR_IN_MILLIS * 2 - 200L,
|
||||||
DateUtils.HOUR_IN_MILLIS * 2 - 100L};
|
DateUtils.HOUR_IN_MILLIS * 2 - 100L};
|
||||||
final int[] levels = {100, 99, 98};
|
final int[] levels = {100, 99, 98};
|
||||||
final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap =
|
DataProcessManager.sFakeBatteryHistoryMap = createHistoryMap(timestamps, levels);
|
||||||
createHistoryMap(timestamps, levels);
|
|
||||||
DataProcessor.sTestCurrentTimeMillis = timestamps[timestamps.length - 1];
|
DataProcessor.sTestCurrentTimeMillis = timestamps[timestamps.length - 1];
|
||||||
|
|
||||||
final BatteryLevelData resultData =
|
final BatteryLevelData resultData =
|
||||||
DataProcessManager.getBatteryLevelData(
|
DataProcessManager.getBatteryLevelData(
|
||||||
mContext,
|
mContext,
|
||||||
/*handler=*/ null,
|
/*handler=*/ null,
|
||||||
batteryHistoryMap,
|
/*isFromPeriodJob=*/ false,
|
||||||
/*asyncResponseDelegate=*/ null);
|
/*asyncResponseDelegate=*/ null);
|
||||||
|
|
||||||
|
|
||||||
final List<Long> expectedDailyTimestamps = List.of(
|
final List<Long> expectedDailyTimestamps = List.of(
|
||||||
DateUtils.HOUR_IN_MILLIS * 2 - 300L,
|
DateUtils.HOUR_IN_MILLIS * 2 - 300L,
|
||||||
DateUtils.HOUR_IN_MILLIS * 2 - 100L);
|
DateUtils.HOUR_IN_MILLIS * 2 - 100L);
|
||||||
@@ -301,15 +334,14 @@ public final class DataProcessManagerTest {
|
|||||||
// Timezone GMT+8: 2022-01-01 00:00:00, 2022-01-01 01:00:00
|
// Timezone GMT+8: 2022-01-01 00:00:00, 2022-01-01 01:00:00
|
||||||
final long[] timestamps = {1640966400000L, 1640970000000L};
|
final long[] timestamps = {1640966400000L, 1640970000000L};
|
||||||
final int[] levels = {100, 99};
|
final int[] levels = {100, 99};
|
||||||
final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap =
|
DataProcessManager.sFakeBatteryHistoryMap = createHistoryMap(timestamps, levels);
|
||||||
createHistoryMap(timestamps, levels);
|
|
||||||
DataProcessor.sTestCurrentTimeMillis = timestamps[timestamps.length - 1];
|
DataProcessor.sTestCurrentTimeMillis = timestamps[timestamps.length - 1];
|
||||||
|
|
||||||
final BatteryLevelData resultData =
|
final BatteryLevelData resultData =
|
||||||
DataProcessManager.getBatteryLevelData(
|
DataProcessManager.getBatteryLevelData(
|
||||||
mContext,
|
mContext,
|
||||||
/*handler=*/ null,
|
/*handler=*/ null,
|
||||||
batteryHistoryMap,
|
/*isFromPeriodJob=*/ false,
|
||||||
/*asyncResponseDelegate=*/ null);
|
/*asyncResponseDelegate=*/ null);
|
||||||
|
|
||||||
final List<Long> expectedDailyTimestamps = List.of(
|
final List<Long> expectedDailyTimestamps = List.of(
|
||||||
|
@@ -16,6 +16,9 @@
|
|||||||
|
|
||||||
package com.android.settings.fuelgauge.batteryusage;
|
package com.android.settings.fuelgauge.batteryusage;
|
||||||
|
|
||||||
|
import static com.android.settings.fuelgauge.batteryusage.ConvertUtils.FAKE_PACKAGE_NAME;
|
||||||
|
import static com.android.settingslib.fuelgauge.BatteryStatus.BATTERY_LEVEL_UNKNOWN;
|
||||||
|
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
import static org.mockito.Mockito.anyInt;
|
import static org.mockito.Mockito.anyInt;
|
||||||
@@ -42,6 +45,7 @@ import android.os.BatteryUsageStats;
|
|||||||
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.util.ArrayMap;
|
||||||
|
|
||||||
import com.android.settings.fuelgauge.PowerUsageFeatureProvider;
|
import com.android.settings.fuelgauge.PowerUsageFeatureProvider;
|
||||||
import com.android.settings.testutils.FakeFeatureFactory;
|
import com.android.settings.testutils.FakeFeatureFactory;
|
||||||
@@ -188,16 +192,18 @@ public final class DataProcessorTest {
|
|||||||
final String packageName = "com.android.settings";
|
final String packageName = "com.android.settings";
|
||||||
// Adds the day 1 data.
|
// Adds the day 1 data.
|
||||||
final List<Long> timestamps1 = List.of(14400000L, 18000000L, 21600000L);
|
final List<Long> timestamps1 = List.of(14400000L, 18000000L, 21600000L);
|
||||||
final List<Integer> levels1 = List.of(100, 100, 100);
|
final Map<Long, Integer> batteryLevelMap1 =
|
||||||
|
Map.of(timestamps1.get(0), 100, timestamps1.get(1), 100, timestamps1.get(2), 100);
|
||||||
hourlyBatteryLevelsPerDay.add(
|
hourlyBatteryLevelsPerDay.add(
|
||||||
new BatteryLevelData.PeriodBatteryLevelData(timestamps1, levels1));
|
new BatteryLevelData.PeriodBatteryLevelData(batteryLevelMap1, timestamps1));
|
||||||
// Adds the day 2 data.
|
// Adds the day 2 data.
|
||||||
hourlyBatteryLevelsPerDay.add(null);
|
hourlyBatteryLevelsPerDay.add(null);
|
||||||
// Adds the day 3 data.
|
// Adds the day 3 data.
|
||||||
final List<Long> timestamps2 = List.of(45200000L, 48800000L);
|
final List<Long> timestamps2 = List.of(45200000L, 48800000L);
|
||||||
final List<Integer> levels2 = List.of(100, 100);
|
final Map<Long, Integer> batteryLevelMap2 =
|
||||||
|
Map.of(timestamps2.get(0), 100, timestamps2.get(1), 100);
|
||||||
hourlyBatteryLevelsPerDay.add(
|
hourlyBatteryLevelsPerDay.add(
|
||||||
new BatteryLevelData.PeriodBatteryLevelData(timestamps2, levels2));
|
new BatteryLevelData.PeriodBatteryLevelData(batteryLevelMap2, timestamps2));
|
||||||
final List<AppUsageEvent> appUsageEventList = new ArrayList<>();
|
final List<AppUsageEvent> appUsageEventList = new ArrayList<>();
|
||||||
// Adds some events before the start timestamp.
|
// Adds some events before the start timestamp.
|
||||||
appUsageEventList.add(buildAppUsageEvent(
|
appUsageEventList.add(buildAppUsageEvent(
|
||||||
@@ -285,7 +291,7 @@ public final class DataProcessorTest {
|
|||||||
final List<BatteryLevelData.PeriodBatteryLevelData> hourlyBatteryLevelsPerDay =
|
final List<BatteryLevelData.PeriodBatteryLevelData> hourlyBatteryLevelsPerDay =
|
||||||
new ArrayList<>();
|
new ArrayList<>();
|
||||||
hourlyBatteryLevelsPerDay.add(
|
hourlyBatteryLevelsPerDay.add(
|
||||||
new BatteryLevelData.PeriodBatteryLevelData(new ArrayList<>(), new ArrayList<>()));
|
new BatteryLevelData.PeriodBatteryLevelData(new ArrayMap<>(), new ArrayList<>()));
|
||||||
assertThat(DataProcessor.generateAppUsagePeriodMap(
|
assertThat(DataProcessor.generateAppUsagePeriodMap(
|
||||||
mContext, hourlyBatteryLevelsPerDay, new ArrayList<>(), new ArrayList<>()))
|
mContext, hourlyBatteryLevelsPerDay, new ArrayList<>(), new ArrayList<>()))
|
||||||
.isNull();
|
.isNull();
|
||||||
@@ -370,19 +376,6 @@ public final class DataProcessorTest {
|
|||||||
DataProcessor.CURRENT_TIME_BATTERY_HISTORY_PLACEHOLDER)).isTrue();
|
DataProcessor.CURRENT_TIME_BATTERY_HISTORY_PLACEHOLDER)).isTrue();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void getLevelDataThroughProcessedHistoryMap_notEnoughData_returnNull() {
|
|
||||||
final long[] timestamps = {100L};
|
|
||||||
final int[] levels = {100};
|
|
||||||
final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap =
|
|
||||||
createHistoryMap(timestamps, levels);
|
|
||||||
DataProcessor.sTestCurrentTimeMillis = timestamps[timestamps.length - 1];
|
|
||||||
|
|
||||||
assertThat(
|
|
||||||
DataProcessor.getLevelDataThroughProcessedHistoryMap(mContext, batteryHistoryMap))
|
|
||||||
.isNull();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getLevelDataThroughProcessedHistoryMap_OneDayData_returnExpectedResult() {
|
public void getLevelDataThroughProcessedHistoryMap_OneDayData_returnExpectedResult() {
|
||||||
// Timezone GMT+8
|
// Timezone GMT+8
|
||||||
@@ -441,7 +434,7 @@ public final class DataProcessorTest {
|
|||||||
);
|
);
|
||||||
final List<Integer> expectedDailyLevels = new ArrayList<>();
|
final List<Integer> expectedDailyLevels = new ArrayList<>();
|
||||||
expectedDailyLevels.add(100);
|
expectedDailyLevels.add(100);
|
||||||
expectedDailyLevels.add(null);
|
expectedDailyLevels.add(BATTERY_LEVEL_UNKNOWN);
|
||||||
expectedDailyLevels.add(82);
|
expectedDailyLevels.add(82);
|
||||||
final List<List<Long>> expectedHourlyTimestamps = List.of(
|
final List<List<Long>> expectedHourlyTimestamps = List.of(
|
||||||
List.of(
|
List.of(
|
||||||
@@ -459,13 +452,13 @@ public final class DataProcessorTest {
|
|||||||
);
|
);
|
||||||
final List<Integer> expectedHourlyLevels1 = new ArrayList<>();
|
final List<Integer> expectedHourlyLevels1 = new ArrayList<>();
|
||||||
expectedHourlyLevels1.add(100);
|
expectedHourlyLevels1.add(100);
|
||||||
expectedHourlyLevels1.add(null);
|
expectedHourlyLevels1.add(BATTERY_LEVEL_UNKNOWN);
|
||||||
expectedHourlyLevels1.add(null);
|
expectedHourlyLevels1.add(BATTERY_LEVEL_UNKNOWN);
|
||||||
final List<Integer> expectedHourlyLevels2 = new ArrayList<>();
|
final List<Integer> expectedHourlyLevels2 = new ArrayList<>();
|
||||||
expectedHourlyLevels2.add(null);
|
expectedHourlyLevels2.add(BATTERY_LEVEL_UNKNOWN);
|
||||||
expectedHourlyLevels2.add(94);
|
expectedHourlyLevels2.add(94);
|
||||||
expectedHourlyLevels2.add(90);
|
expectedHourlyLevels2.add(90);
|
||||||
expectedHourlyLevels2.add(null);
|
expectedHourlyLevels2.add(BATTERY_LEVEL_UNKNOWN);
|
||||||
expectedHourlyLevels2.add(82);
|
expectedHourlyLevels2.add(82);
|
||||||
final List<List<Integer>> expectedHourlyLevels = List.of(
|
final List<List<Integer>> expectedHourlyLevels = List.of(
|
||||||
expectedHourlyLevels1,
|
expectedHourlyLevels1,
|
||||||
@@ -503,8 +496,8 @@ public final class DataProcessorTest {
|
|||||||
);
|
);
|
||||||
final List<Integer> expectedDailyLevels = new ArrayList<>();
|
final List<Integer> expectedDailyLevels = new ArrayList<>();
|
||||||
expectedDailyLevels.add(100);
|
expectedDailyLevels.add(100);
|
||||||
expectedDailyLevels.add(null);
|
expectedDailyLevels.add(BATTERY_LEVEL_UNKNOWN);
|
||||||
expectedDailyLevels.add(null);
|
expectedDailyLevels.add(BATTERY_LEVEL_UNKNOWN);
|
||||||
expectedDailyLevels.add(88);
|
expectedDailyLevels.add(88);
|
||||||
final List<List<Long>> expectedHourlyTimestamps = List.of(
|
final List<List<Long>> expectedHourlyTimestamps = List.of(
|
||||||
List.of(
|
List.of(
|
||||||
@@ -542,32 +535,32 @@ public final class DataProcessorTest {
|
|||||||
);
|
);
|
||||||
final List<Integer> expectedHourlyLevels1 = new ArrayList<>();
|
final List<Integer> expectedHourlyLevels1 = new ArrayList<>();
|
||||||
expectedHourlyLevels1.add(100);
|
expectedHourlyLevels1.add(100);
|
||||||
expectedHourlyLevels1.add(null);
|
expectedHourlyLevels1.add(BATTERY_LEVEL_UNKNOWN);
|
||||||
expectedHourlyLevels1.add(null);
|
expectedHourlyLevels1.add(BATTERY_LEVEL_UNKNOWN);
|
||||||
expectedHourlyLevels1.add(null);
|
expectedHourlyLevels1.add(BATTERY_LEVEL_UNKNOWN);
|
||||||
expectedHourlyLevels1.add(null);
|
expectedHourlyLevels1.add(BATTERY_LEVEL_UNKNOWN);
|
||||||
expectedHourlyLevels1.add(null);
|
expectedHourlyLevels1.add(BATTERY_LEVEL_UNKNOWN);
|
||||||
expectedHourlyLevels1.add(null);
|
expectedHourlyLevels1.add(BATTERY_LEVEL_UNKNOWN);
|
||||||
expectedHourlyLevels1.add(null);
|
expectedHourlyLevels1.add(BATTERY_LEVEL_UNKNOWN);
|
||||||
final List<Integer> expectedHourlyLevels2 = new ArrayList<>();
|
final List<Integer> expectedHourlyLevels2 = new ArrayList<>();
|
||||||
expectedHourlyLevels2.add(null);
|
expectedHourlyLevels2.add(BATTERY_LEVEL_UNKNOWN);
|
||||||
expectedHourlyLevels2.add(null);
|
expectedHourlyLevels2.add(BATTERY_LEVEL_UNKNOWN);
|
||||||
expectedHourlyLevels2.add(null);
|
expectedHourlyLevels2.add(BATTERY_LEVEL_UNKNOWN);
|
||||||
expectedHourlyLevels2.add(null);
|
expectedHourlyLevels2.add(BATTERY_LEVEL_UNKNOWN);
|
||||||
expectedHourlyLevels2.add(null);
|
expectedHourlyLevels2.add(BATTERY_LEVEL_UNKNOWN);
|
||||||
expectedHourlyLevels2.add(null);
|
expectedHourlyLevels2.add(BATTERY_LEVEL_UNKNOWN);
|
||||||
expectedHourlyLevels2.add(null);
|
expectedHourlyLevels2.add(BATTERY_LEVEL_UNKNOWN);
|
||||||
expectedHourlyLevels2.add(null);
|
expectedHourlyLevels2.add(BATTERY_LEVEL_UNKNOWN);
|
||||||
expectedHourlyLevels2.add(null);
|
expectedHourlyLevels2.add(BATTERY_LEVEL_UNKNOWN);
|
||||||
expectedHourlyLevels2.add(null);
|
expectedHourlyLevels2.add(BATTERY_LEVEL_UNKNOWN);
|
||||||
expectedHourlyLevels2.add(null);
|
expectedHourlyLevels2.add(BATTERY_LEVEL_UNKNOWN);
|
||||||
expectedHourlyLevels2.add(null);
|
expectedHourlyLevels2.add(BATTERY_LEVEL_UNKNOWN);
|
||||||
expectedHourlyLevels2.add(null);
|
expectedHourlyLevels2.add(BATTERY_LEVEL_UNKNOWN);
|
||||||
expectedHourlyLevels2.add(null);
|
expectedHourlyLevels2.add(BATTERY_LEVEL_UNKNOWN);
|
||||||
final List<Integer> expectedHourlyLevels3 = new ArrayList<>();
|
final List<Integer> expectedHourlyLevels3 = new ArrayList<>();
|
||||||
expectedHourlyLevels3.add(null);
|
expectedHourlyLevels3.add(BATTERY_LEVEL_UNKNOWN);
|
||||||
expectedHourlyLevels3.add(null);
|
expectedHourlyLevels3.add(BATTERY_LEVEL_UNKNOWN);
|
||||||
expectedHourlyLevels3.add(null);
|
expectedHourlyLevels3.add(BATTERY_LEVEL_UNKNOWN);
|
||||||
expectedHourlyLevels3.add(88);
|
expectedHourlyLevels3.add(88);
|
||||||
final List<List<Integer>> expectedHourlyLevels = List.of(
|
final List<List<Integer>> expectedHourlyLevels = List.of(
|
||||||
expectedHourlyLevels1,
|
expectedHourlyLevels1,
|
||||||
@@ -606,8 +599,8 @@ public final class DataProcessorTest {
|
|||||||
);
|
);
|
||||||
final List<Integer> expectedDailyLevels = new ArrayList<>();
|
final List<Integer> expectedDailyLevels = new ArrayList<>();
|
||||||
expectedDailyLevels.add(100);
|
expectedDailyLevels.add(100);
|
||||||
expectedDailyLevels.add(null);
|
expectedDailyLevels.add(BATTERY_LEVEL_UNKNOWN);
|
||||||
expectedDailyLevels.add(null);
|
expectedDailyLevels.add(BATTERY_LEVEL_UNKNOWN);
|
||||||
expectedDailyLevels.add(88);
|
expectedDailyLevels.add(88);
|
||||||
final List<List<Long>> expectedHourlyTimestamps = List.of(
|
final List<List<Long>> expectedHourlyTimestamps = List.of(
|
||||||
List.of(
|
List.of(
|
||||||
@@ -638,25 +631,25 @@ public final class DataProcessorTest {
|
|||||||
);
|
);
|
||||||
final List<Integer> expectedHourlyLevels1 = new ArrayList<>();
|
final List<Integer> expectedHourlyLevels1 = new ArrayList<>();
|
||||||
expectedHourlyLevels1.add(100);
|
expectedHourlyLevels1.add(100);
|
||||||
expectedHourlyLevels1.add(null);
|
expectedHourlyLevels1.add(BATTERY_LEVEL_UNKNOWN);
|
||||||
final List<Integer> expectedHourlyLevels2 = new ArrayList<>();
|
final List<Integer> expectedHourlyLevels2 = new ArrayList<>();
|
||||||
expectedHourlyLevels2.add(null);
|
expectedHourlyLevels2.add(BATTERY_LEVEL_UNKNOWN);
|
||||||
expectedHourlyLevels2.add(null);
|
expectedHourlyLevels2.add(BATTERY_LEVEL_UNKNOWN);
|
||||||
expectedHourlyLevels2.add(null);
|
expectedHourlyLevels2.add(BATTERY_LEVEL_UNKNOWN);
|
||||||
expectedHourlyLevels2.add(null);
|
expectedHourlyLevels2.add(BATTERY_LEVEL_UNKNOWN);
|
||||||
expectedHourlyLevels2.add(null);
|
expectedHourlyLevels2.add(BATTERY_LEVEL_UNKNOWN);
|
||||||
expectedHourlyLevels2.add(null);
|
expectedHourlyLevels2.add(BATTERY_LEVEL_UNKNOWN);
|
||||||
expectedHourlyLevels2.add(null);
|
expectedHourlyLevels2.add(BATTERY_LEVEL_UNKNOWN);
|
||||||
expectedHourlyLevels2.add(null);
|
expectedHourlyLevels2.add(BATTERY_LEVEL_UNKNOWN);
|
||||||
expectedHourlyLevels2.add(null);
|
expectedHourlyLevels2.add(BATTERY_LEVEL_UNKNOWN);
|
||||||
expectedHourlyLevels2.add(null);
|
expectedHourlyLevels2.add(BATTERY_LEVEL_UNKNOWN);
|
||||||
expectedHourlyLevels2.add(null);
|
expectedHourlyLevels2.add(BATTERY_LEVEL_UNKNOWN);
|
||||||
expectedHourlyLevels2.add(null);
|
expectedHourlyLevels2.add(BATTERY_LEVEL_UNKNOWN);
|
||||||
expectedHourlyLevels2.add(null);
|
expectedHourlyLevels2.add(BATTERY_LEVEL_UNKNOWN);
|
||||||
final List<Integer> expectedHourlyLevels3 = new ArrayList<>();
|
final List<Integer> expectedHourlyLevels3 = new ArrayList<>();
|
||||||
expectedHourlyLevels3.add(null);
|
expectedHourlyLevels3.add(BATTERY_LEVEL_UNKNOWN);
|
||||||
expectedHourlyLevels3.add(null);
|
expectedHourlyLevels3.add(BATTERY_LEVEL_UNKNOWN);
|
||||||
expectedHourlyLevels3.add(null);
|
expectedHourlyLevels3.add(BATTERY_LEVEL_UNKNOWN);
|
||||||
expectedHourlyLevels3.add(88);
|
expectedHourlyLevels3.add(88);
|
||||||
final List<List<Integer>> expectedHourlyLevels = List.of(
|
final List<List<Integer>> expectedHourlyLevels = List.of(
|
||||||
expectedHourlyLevels1,
|
expectedHourlyLevels1,
|
||||||
@@ -734,141 +727,6 @@ public final class DataProcessorTest {
|
|||||||
verifyExpectedTimestampSlots(startTimestamp, endTimestamp, expectedTimestamps);
|
verifyExpectedTimestampSlots(startTimestamp, endTimestamp, expectedTimestamps);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void getDailyTimestamps_notEnoughData_returnEmptyList() {
|
|
||||||
assertThat(DataProcessor.getDailyTimestamps(new ArrayList<>())).isEmpty();
|
|
||||||
assertThat(DataProcessor.getDailyTimestamps(List.of(100L))).isEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void getDailyTimestamps_allDataInOneHour_returnExpectedList() {
|
|
||||||
// Timezone GMT+8
|
|
||||||
final List<Long> timestamps = List.of(
|
|
||||||
1640970006000L, // 2022-01-01 01:00:06
|
|
||||||
1640973608000L // 2022-01-01 01:00:08
|
|
||||||
);
|
|
||||||
|
|
||||||
final List<Long> expectedTimestamps = List.of(
|
|
||||||
1640970006000L, // 2022-01-01 01:00:06
|
|
||||||
1640973608000L // 2022-01-01 01:00:08
|
|
||||||
);
|
|
||||||
assertThat(DataProcessor.getDailyTimestamps(timestamps)).isEqualTo(expectedTimestamps);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void getDailyTimestamps_OneHourDataPerDay_returnExpectedList() {
|
|
||||||
// Timezone GMT+8
|
|
||||||
final List<Long> timestamps = List.of(
|
|
||||||
1641049200000L, // 2022-01-01 23:00:00
|
|
||||||
1641052800000L, // 2022-01-02 00:00:00
|
|
||||||
1641056400000L // 2022-01-02 01:00:00
|
|
||||||
);
|
|
||||||
|
|
||||||
final List<Long> expectedTimestamps = List.of(
|
|
||||||
1641049200000L, // 2022-01-01 23:00:00
|
|
||||||
1641052800000L, // 2022-01-02 00:00:00
|
|
||||||
1641056400000L // 2022-01-02 01:00:00
|
|
||||||
);
|
|
||||||
assertThat(DataProcessor.getDailyTimestamps(timestamps)).isEqualTo(expectedTimestamps);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void getDailyTimestamps_OneDayData_returnExpectedList() {
|
|
||||||
// Timezone GMT+8
|
|
||||||
final List<Long> timestamps = List.of(
|
|
||||||
1640966400000L, // 2022-01-01 00:00:00
|
|
||||||
1640970000000L, // 2022-01-01 01:00:00
|
|
||||||
1640973600000L, // 2022-01-01 02:00:00
|
|
||||||
1640977200000L, // 2022-01-01 03:00:00
|
|
||||||
1640980800000L // 2022-01-01 04:00:00
|
|
||||||
);
|
|
||||||
|
|
||||||
final List<Long> expectedTimestamps = List.of(
|
|
||||||
1640966400000L, // 2022-01-01 00:00:00
|
|
||||||
1640980800000L // 2022-01-01 04:00:00
|
|
||||||
);
|
|
||||||
assertThat(DataProcessor.getDailyTimestamps(timestamps)).isEqualTo(expectedTimestamps);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void getDailyTimestamps_MultipleDaysData_returnExpectedList() {
|
|
||||||
// Timezone GMT+8
|
|
||||||
final List<Long> timestamps = List.of(
|
|
||||||
1641045600000L, // 2022-01-01 22:00:00
|
|
||||||
1641060000000L, // 2022-01-02 02:00:00
|
|
||||||
1641160800000L, // 2022-01-03 06:00:00
|
|
||||||
1641232800000L // 2022-01-04 02:00:00
|
|
||||||
);
|
|
||||||
|
|
||||||
final List<Long> expectedTimestamps = List.of(
|
|
||||||
1641045600000L, // 2022-01-01 22:00:00
|
|
||||||
1641052800000L, // 2022-01-02 00:00:00
|
|
||||||
1641139200000L, // 2022-01-03 00:00:00
|
|
||||||
1641225600000L, // 2022-01-04 00:00:00
|
|
||||||
1641232800000L // 2022-01-04 02:00:00
|
|
||||||
);
|
|
||||||
assertThat(DataProcessor.getDailyTimestamps(timestamps)).isEqualTo(expectedTimestamps);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void getDailyTimestamps_FirstDayOneHourData_returnExpectedList() {
|
|
||||||
// Timezone GMT+8
|
|
||||||
final List<Long> timestamps = List.of(
|
|
||||||
1641049200000L, // 2022-01-01 23:00:00
|
|
||||||
1641060000000L, // 2022-01-02 02:00:00
|
|
||||||
1641160800000L, // 2022-01-03 06:00:00
|
|
||||||
1641254400000L // 2022-01-04 08:00:00
|
|
||||||
);
|
|
||||||
|
|
||||||
final List<Long> expectedTimestamps = List.of(
|
|
||||||
1641049200000L, // 2022-01-01 23:00:00
|
|
||||||
1641052800000L, // 2022-01-02 00:00:00
|
|
||||||
1641139200000L, // 2022-01-03 00:00:00
|
|
||||||
1641225600000L, // 2022-01-04 00:00:00
|
|
||||||
1641254400000L // 2022-01-04 08:00:00
|
|
||||||
);
|
|
||||||
assertThat(DataProcessor.getDailyTimestamps(timestamps)).isEqualTo(expectedTimestamps);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void getDailyTimestamps_LastDayNoData_returnExpectedList() {
|
|
||||||
// Timezone GMT+8
|
|
||||||
final List<Long> timestamps = List.of(
|
|
||||||
1640988000000L, // 2022-01-01 06:00:00
|
|
||||||
1641060000000L, // 2022-01-02 02:00:00
|
|
||||||
1641160800000L, // 2022-01-03 06:00:00
|
|
||||||
1641225600000L // 2022-01-04 00:00:00
|
|
||||||
);
|
|
||||||
|
|
||||||
final List<Long> expectedTimestamps = List.of(
|
|
||||||
1640988000000L, // 2022-01-01 06:00:00
|
|
||||||
1641052800000L, // 2022-01-02 00:00:00
|
|
||||||
1641139200000L, // 2022-01-03 00:00:00
|
|
||||||
1641225600000L // 2022-01-04 00:00:00
|
|
||||||
);
|
|
||||||
assertThat(DataProcessor.getDailyTimestamps(timestamps)).isEqualTo(expectedTimestamps);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void getDailyTimestamps_LastDayOneHourData_returnExpectedList() {
|
|
||||||
// Timezone GMT+8
|
|
||||||
final List<Long> timestamps = List.of(
|
|
||||||
1640988000000L, // 2022-01-01 06:00:00
|
|
||||||
1641060000000L, // 2022-01-02 02:00:00
|
|
||||||
1641160800000L, // 2022-01-03 06:00:00
|
|
||||||
1641229200000L // 2022-01-04 01:00:00
|
|
||||||
);
|
|
||||||
|
|
||||||
final List<Long> expectedTimestamps = List.of(
|
|
||||||
1640988000000L, // 2022-01-01 06:00:00
|
|
||||||
1641052800000L, // 2022-01-02 00:00:00
|
|
||||||
1641139200000L, // 2022-01-03 00:00:00
|
|
||||||
1641225600000L, // 2022-01-04 00:00:00
|
|
||||||
1641229200000L // 2022-01-04 01:00:00
|
|
||||||
);
|
|
||||||
assertThat(DataProcessor.getDailyTimestamps(timestamps)).isEqualTo(expectedTimestamps);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void isFromFullCharge_emptyData_returnFalse() {
|
public void isFromFullCharge_emptyData_returnFalse() {
|
||||||
assertThat(DataProcessor.isFromFullCharge(null)).isFalse();
|
assertThat(DataProcessor.isFromFullCharge(null)).isFalse();
|
||||||
@@ -916,20 +774,53 @@ public final class DataProcessorTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getBatteryUsageMap_emptyHistoryMap_returnNull() {
|
public void getBatteryDiffDataMap_emptyHistoryMap_returnEmpty() {
|
||||||
final List<BatteryLevelData.PeriodBatteryLevelData> hourlyBatteryLevelsPerDay =
|
final List<BatteryLevelData.PeriodBatteryLevelData> hourlyBatteryLevelsPerDay =
|
||||||
new ArrayList<>();
|
new ArrayList<>();
|
||||||
|
|
||||||
hourlyBatteryLevelsPerDay.add(
|
hourlyBatteryLevelsPerDay.add(
|
||||||
new BatteryLevelData.PeriodBatteryLevelData(new ArrayList<>(), new ArrayList<>()));
|
new BatteryLevelData.PeriodBatteryLevelData(new ArrayMap<>(), new ArrayList<>()));
|
||||||
|
|
||||||
assertThat(DataProcessor.getBatteryUsageMap(
|
assertThat(DataProcessor.getBatteryDiffDataMap(mContext, hourlyBatteryLevelsPerDay,
|
||||||
mContext, hourlyBatteryLevelsPerDay, new HashMap<>(), /*appUsagePeriodMap=*/ null))
|
new HashMap<>(), /*appUsagePeriodMap=*/ null, Set.of(), Set.of())).isEmpty();
|
||||||
.isNull();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getBatteryUsageMap_returnsExpectedResult() {
|
public void getBatteryDiffDataMap_normalFlow_returnExpectedResult() {
|
||||||
|
final int userId = mContext.getUserId();
|
||||||
|
final long[] batteryHistoryKeys = new long[]{
|
||||||
|
1641045600000L, // 2022-01-01 22:00:00
|
||||||
|
1641049200000L, // 2022-01-01 23:00:00
|
||||||
|
1641052800000L, // 2022-01-02 00:00:00
|
||||||
|
};
|
||||||
|
final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap = Map.of(
|
||||||
|
batteryHistoryKeys[0], Map.of(FAKE_PACKAGE_NAME, createBatteryHistEntry(
|
||||||
|
FAKE_PACKAGE_NAME, "fake_label", /*consumePower=*/ 0, 0, 0,
|
||||||
|
0, 0, 0L, userId, ConvertUtils.CONSUMER_TYPE_UID_BATTERY, 0L, 0L, false)),
|
||||||
|
batteryHistoryKeys[1], Map.of(FAKE_PACKAGE_NAME, createBatteryHistEntry(
|
||||||
|
FAKE_PACKAGE_NAME, "fake_label", /*consumePower=*/ 5, 0, 0,
|
||||||
|
0, 0, 0L, userId, ConvertUtils.CONSUMER_TYPE_UID_BATTERY, 0L, 0L, false)),
|
||||||
|
batteryHistoryKeys[2], Map.of(FAKE_PACKAGE_NAME, createBatteryHistEntry(
|
||||||
|
FAKE_PACKAGE_NAME, "fake_label", /*consumePower=*/ 16, 0, 0,
|
||||||
|
0, 0, 0L, userId, ConvertUtils.CONSUMER_TYPE_UID_BATTERY, 0L, 0L, false)));
|
||||||
|
final BatteryLevelData batteryLevelData = generateBatteryLevelData(batteryHistoryKeys);
|
||||||
|
final Map<Integer, Map<Integer, Map<Long, Map<String, List<AppUsagePeriod>>>>>
|
||||||
|
appUsagePeriodMap = Map.of(0, Map.of(0, Map.of(Long.valueOf(userId), Map.of(
|
||||||
|
FAKE_PACKAGE_NAME, List.of(buildAppUsagePeriod(0, 6))))));
|
||||||
|
|
||||||
|
Map<Long, BatteryDiffData> batteryDiffDataMap = DataProcessor.getBatteryDiffDataMap(
|
||||||
|
mContext, batteryLevelData.getHourlyBatteryLevelsPerDay(), batteryHistoryMap,
|
||||||
|
appUsagePeriodMap, Set.of(), Set.of());
|
||||||
|
|
||||||
|
assertThat(batteryDiffDataMap).hasSize(1);
|
||||||
|
assertThat(batteryDiffDataMap).containsKey(batteryHistoryKeys[0]);
|
||||||
|
BatteryDiffData batteryDiffData = batteryDiffDataMap.get(batteryHistoryKeys[0]);
|
||||||
|
assertThat(batteryDiffData.getStartTimestamp()).isEqualTo(batteryHistoryKeys[0]);
|
||||||
|
assertThat(batteryDiffData.getEndTimestamp()).isEqualTo(batteryHistoryKeys[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void generateBatteryUsageMap_returnsExpectedResult() {
|
||||||
final long[] batteryHistoryKeys = new long[]{
|
final long[] batteryHistoryKeys = new long[]{
|
||||||
1641045600000L, // 2022-01-01 22:00:00
|
1641045600000L, // 2022-01-01 22:00:00
|
||||||
1641049200000L, // 2022-01-01 23:00:00
|
1641049200000L, // 2022-01-01 23:00:00
|
||||||
@@ -940,7 +831,7 @@ public final class DataProcessorTest {
|
|||||||
final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap = new HashMap<>();
|
final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap = new HashMap<>();
|
||||||
final int currentUserId = mContext.getUserId();
|
final int currentUserId = mContext.getUserId();
|
||||||
final BatteryHistEntry fakeEntry = createBatteryHistEntry(
|
final BatteryHistEntry fakeEntry = createBatteryHistEntry(
|
||||||
ConvertUtils.FAKE_PACKAGE_NAME, "fake_label", /*consumePower=*/ 0,
|
FAKE_PACKAGE_NAME, "fake_label", /*consumePower=*/ 0,
|
||||||
/*foregroundUsageConsumePower=*/ 0, /*foregroundServiceUsageConsumePower=*/ 0,
|
/*foregroundUsageConsumePower=*/ 0, /*foregroundServiceUsageConsumePower=*/ 0,
|
||||||
/*backgroundUsageConsumePower=*/ 0, /*cachedUsageConsumePower=*/ 0,
|
/*backgroundUsageConsumePower=*/ 0, /*cachedUsageConsumePower=*/ 0,
|
||||||
/*uid=*/ 0L, currentUserId, ConvertUtils.CONSUMER_TYPE_UID_BATTERY,
|
/*uid=*/ 0L, currentUserId, ConvertUtils.CONSUMER_TYPE_UID_BATTERY,
|
||||||
@@ -1030,19 +921,7 @@ public final class DataProcessorTest {
|
|||||||
entryMap.put(entry.getKey(), entry);
|
entryMap.put(entry.getKey(), entry);
|
||||||
entryMap.put(fakeEntry.getKey(), fakeEntry);
|
entryMap.put(fakeEntry.getKey(), fakeEntry);
|
||||||
batteryHistoryMap.put(batteryHistoryKeys[4], entryMap);
|
batteryHistoryMap.put(batteryHistoryKeys[4], entryMap);
|
||||||
final List<BatteryLevelData.PeriodBatteryLevelData> hourlyBatteryLevelsPerDay =
|
final BatteryLevelData batteryLevelData = generateBatteryLevelData(batteryHistoryKeys);
|
||||||
new ArrayList<>();
|
|
||||||
// Adds the day 1 data.
|
|
||||||
List<Long> timestamps =
|
|
||||||
List.of(batteryHistoryKeys[0], batteryHistoryKeys[2]);
|
|
||||||
final List<Integer> levels = List.of(100, 100);
|
|
||||||
hourlyBatteryLevelsPerDay.add(
|
|
||||||
new BatteryLevelData.PeriodBatteryLevelData(timestamps, levels));
|
|
||||||
// Adds the day 2 data.
|
|
||||||
timestamps = List.of(batteryHistoryKeys[2], batteryHistoryKeys[4]);
|
|
||||||
hourlyBatteryLevelsPerDay.add(
|
|
||||||
new BatteryLevelData.PeriodBatteryLevelData(timestamps, levels));
|
|
||||||
|
|
||||||
// Adds app usage data to test screen on time.
|
// Adds app usage data to test screen on time.
|
||||||
final Map<Integer, Map<Integer, Map<Long, Map<String, List<AppUsagePeriod>>>>>
|
final Map<Integer, Map<Integer, Map<Long, Map<String, List<AppUsagePeriod>>>>>
|
||||||
appUsagePeriodMap = new HashMap<>();
|
appUsagePeriodMap = new HashMap<>();
|
||||||
@@ -1066,8 +945,12 @@ public final class DataProcessorTest {
|
|||||||
appUsagePeriodMap.get(1).put(0, appUsageMap);
|
appUsagePeriodMap.get(1).put(0, appUsageMap);
|
||||||
|
|
||||||
final Map<Integer, Map<Integer, BatteryDiffData>> resultMap =
|
final Map<Integer, Map<Integer, BatteryDiffData>> resultMap =
|
||||||
DataProcessor.getBatteryUsageMap(
|
DataProcessor.generateBatteryUsageMap(
|
||||||
mContext, hourlyBatteryLevelsPerDay, batteryHistoryMap, appUsagePeriodMap);
|
mContext,
|
||||||
|
DataProcessor.getBatteryDiffDataMap(mContext,
|
||||||
|
batteryLevelData.getHourlyBatteryLevelsPerDay(), batteryHistoryMap,
|
||||||
|
appUsagePeriodMap, Set.of(), Set.of()),
|
||||||
|
batteryLevelData);
|
||||||
|
|
||||||
BatteryDiffData resultDiffData =
|
BatteryDiffData resultDiffData =
|
||||||
resultMap
|
resultMap
|
||||||
@@ -1128,7 +1011,7 @@ public final class DataProcessorTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getBatteryUsageMap_multipleUsers_returnsExpectedResult() {
|
public void generateBatteryUsageMap_multipleUsers_returnsExpectedResult() {
|
||||||
final long[] batteryHistoryKeys = new long[]{
|
final long[] batteryHistoryKeys = new long[]{
|
||||||
1641052800000L, // 2022-01-02 00:00:00
|
1641052800000L, // 2022-01-02 00:00:00
|
||||||
1641056400000L, // 2022-01-02 01:00:00
|
1641056400000L, // 2022-01-02 01:00:00
|
||||||
@@ -1217,17 +1100,15 @@ public final class DataProcessorTest {
|
|||||||
/*backgroundUsageTimeInMs=*/ 30L, /*isHidden=*/ false);
|
/*backgroundUsageTimeInMs=*/ 30L, /*isHidden=*/ false);
|
||||||
entryMap.put(entry.getKey(), entry);
|
entryMap.put(entry.getKey(), entry);
|
||||||
batteryHistoryMap.put(batteryHistoryKeys[2], entryMap);
|
batteryHistoryMap.put(batteryHistoryKeys[2], entryMap);
|
||||||
final List<BatteryLevelData.PeriodBatteryLevelData> hourlyBatteryLevelsPerDay =
|
final BatteryLevelData batteryLevelData = generateBatteryLevelData(batteryHistoryKeys);
|
||||||
new ArrayList<>();
|
|
||||||
List<Long> timestamps = List.of(batteryHistoryKeys[0], batteryHistoryKeys[2]);
|
|
||||||
final List<Integer> levels = List.of(100, 100);
|
|
||||||
hourlyBatteryLevelsPerDay.add(
|
|
||||||
new BatteryLevelData.PeriodBatteryLevelData(timestamps, levels));
|
|
||||||
|
|
||||||
final Map<Integer, Map<Integer, BatteryDiffData>> resultMap =
|
final Map<Integer, Map<Integer, BatteryDiffData>> resultMap =
|
||||||
DataProcessor.getBatteryUsageMap(
|
DataProcessor.generateBatteryUsageMap(
|
||||||
mContext, hourlyBatteryLevelsPerDay, batteryHistoryMap,
|
mContext,
|
||||||
/*appUsagePeriodMap=*/ null);
|
DataProcessor.getBatteryDiffDataMap(mContext,
|
||||||
|
batteryLevelData.getHourlyBatteryLevelsPerDay(), batteryHistoryMap,
|
||||||
|
/*appUsagePeriodMap=*/ null, Set.of(), Set.of()),
|
||||||
|
batteryLevelData);
|
||||||
|
|
||||||
final BatteryDiffData resultDiffData =
|
final BatteryDiffData resultDiffData =
|
||||||
resultMap
|
resultMap
|
||||||
@@ -1247,7 +1128,7 @@ public final class DataProcessorTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getBatteryUsageMap_usageTimeExceed_returnsExpectedResult() {
|
public void generateBatteryUsageMap_usageTimeExceed_returnsExpectedResult() {
|
||||||
final long[] batteryHistoryKeys = new long[]{
|
final long[] batteryHistoryKeys = new long[]{
|
||||||
1641052800000L, // 2022-01-02 00:00:00
|
1641052800000L, // 2022-01-02 00:00:00
|
||||||
1641056400000L, // 2022-01-02 01:00:00
|
1641056400000L, // 2022-01-02 01:00:00
|
||||||
@@ -1288,12 +1169,7 @@ public final class DataProcessorTest {
|
|||||||
/*backgroundUsageTimeInMs=*/ 7200000L, /*isHidden=*/ false);
|
/*backgroundUsageTimeInMs=*/ 7200000L, /*isHidden=*/ false);
|
||||||
entryMap.put(entry.getKey(), entry);
|
entryMap.put(entry.getKey(), entry);
|
||||||
batteryHistoryMap.put(batteryHistoryKeys[2], entryMap);
|
batteryHistoryMap.put(batteryHistoryKeys[2], entryMap);
|
||||||
final List<BatteryLevelData.PeriodBatteryLevelData> hourlyBatteryLevelsPerDay =
|
final BatteryLevelData batteryLevelData = generateBatteryLevelData(batteryHistoryKeys);
|
||||||
new ArrayList<>();
|
|
||||||
List<Long> timestamps = List.of(batteryHistoryKeys[0], batteryHistoryKeys[2]);
|
|
||||||
final List<Integer> levels = List.of(100, 100);
|
|
||||||
hourlyBatteryLevelsPerDay.add(
|
|
||||||
new BatteryLevelData.PeriodBatteryLevelData(timestamps, levels));
|
|
||||||
|
|
||||||
// Adds app usage data to test screen on time.
|
// Adds app usage data to test screen on time.
|
||||||
final Map<Integer, Map<Integer, Map<Long, Map<String, List<AppUsagePeriod>>>>>
|
final Map<Integer, Map<Integer, Map<Long, Map<String, List<AppUsagePeriod>>>>>
|
||||||
@@ -1307,8 +1183,12 @@ public final class DataProcessorTest {
|
|||||||
appUsagePeriodMap.get(0).put(0, appUsageMap);
|
appUsagePeriodMap.get(0).put(0, appUsageMap);
|
||||||
|
|
||||||
final Map<Integer, Map<Integer, BatteryDiffData>> resultMap =
|
final Map<Integer, Map<Integer, BatteryDiffData>> resultMap =
|
||||||
DataProcessor.getBatteryUsageMap(
|
DataProcessor.generateBatteryUsageMap(
|
||||||
mContext, hourlyBatteryLevelsPerDay, batteryHistoryMap, appUsagePeriodMap);
|
mContext,
|
||||||
|
DataProcessor.getBatteryDiffDataMap(mContext,
|
||||||
|
batteryLevelData.getHourlyBatteryLevelsPerDay(), batteryHistoryMap,
|
||||||
|
appUsagePeriodMap, Set.of(), Set.of()),
|
||||||
|
batteryLevelData);
|
||||||
|
|
||||||
final BatteryDiffData resultDiffData =
|
final BatteryDiffData resultDiffData =
|
||||||
resultMap
|
resultMap
|
||||||
@@ -1338,7 +1218,7 @@ public final class DataProcessorTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getBatteryUsageMap_hideApplicationEntries_returnsExpectedResult() {
|
public void generateBatteryUsageMap_hideApplicationEntries_returnsExpectedResult() {
|
||||||
final long[] batteryHistoryKeys = new long[]{
|
final long[] batteryHistoryKeys = new long[]{
|
||||||
1641052800000L, // 2022-01-02 00:00:00
|
1641052800000L, // 2022-01-02 00:00:00
|
||||||
1641056400000L, // 2022-01-02 01:00:00
|
1641056400000L, // 2022-01-02 01:00:00
|
||||||
@@ -1403,19 +1283,17 @@ public final class DataProcessorTest {
|
|||||||
/*backgroundUsageTimeInMs=*/ 20L, /*isHidden=*/ false);
|
/*backgroundUsageTimeInMs=*/ 20L, /*isHidden=*/ false);
|
||||||
entryMap.put(entry.getKey(), entry);
|
entryMap.put(entry.getKey(), entry);
|
||||||
batteryHistoryMap.put(batteryHistoryKeys[2], entryMap);
|
batteryHistoryMap.put(batteryHistoryKeys[2], entryMap);
|
||||||
final List<BatteryLevelData.PeriodBatteryLevelData> hourlyBatteryLevelsPerDay =
|
final BatteryLevelData batteryLevelData = generateBatteryLevelData(batteryHistoryKeys);
|
||||||
new ArrayList<>();
|
|
||||||
List<Long> timestamps = List.of(batteryHistoryKeys[0], batteryHistoryKeys[2]);
|
|
||||||
final List<Integer> levels = List.of(100, 100);
|
|
||||||
hourlyBatteryLevelsPerDay.add(
|
|
||||||
new BatteryLevelData.PeriodBatteryLevelData(timestamps, levels));
|
|
||||||
when(mPowerUsageFeatureProvider.getHideApplicationSet())
|
when(mPowerUsageFeatureProvider.getHideApplicationSet())
|
||||||
.thenReturn(Set.of("package1"));
|
.thenReturn(Set.of("package1"));
|
||||||
|
|
||||||
final Map<Integer, Map<Integer, BatteryDiffData>> resultMap =
|
final Map<Integer, Map<Integer, BatteryDiffData>> resultMap =
|
||||||
DataProcessor.getBatteryUsageMap(
|
DataProcessor.generateBatteryUsageMap(
|
||||||
mContext, hourlyBatteryLevelsPerDay, batteryHistoryMap,
|
mContext,
|
||||||
/*appUsagePeriodMap=*/ null);
|
DataProcessor.getBatteryDiffDataMap(mContext,
|
||||||
|
batteryLevelData.getHourlyBatteryLevelsPerDay(), batteryHistoryMap,
|
||||||
|
/*appUsagePeriodMap=*/ null, Set.of(), Set.of()),
|
||||||
|
batteryLevelData);
|
||||||
|
|
||||||
final BatteryDiffData resultDiffData =
|
final BatteryDiffData resultDiffData =
|
||||||
resultMap
|
resultMap
|
||||||
@@ -1431,7 +1309,7 @@ public final class DataProcessorTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getBatteryUsageMap_hideBackgroundUsageTime_returnsExpectedResult() {
|
public void generateBatteryUsageMap_hideBackgroundUsageTime_returnsExpectedResult() {
|
||||||
final long[] batteryHistoryKeys = new long[]{
|
final long[] batteryHistoryKeys = new long[]{
|
||||||
1641052800000L, // 2022-01-02 00:00:00
|
1641052800000L, // 2022-01-02 00:00:00
|
||||||
1641056400000L, // 2022-01-02 01:00:00
|
1641056400000L, // 2022-01-02 01:00:00
|
||||||
@@ -1496,19 +1374,17 @@ public final class DataProcessorTest {
|
|||||||
/*backgroundUsageTimeInMs=*/ 20L, /*isHidden=*/ false);
|
/*backgroundUsageTimeInMs=*/ 20L, /*isHidden=*/ false);
|
||||||
entryMap.put(entry.getKey(), entry);
|
entryMap.put(entry.getKey(), entry);
|
||||||
batteryHistoryMap.put(batteryHistoryKeys[2], entryMap);
|
batteryHistoryMap.put(batteryHistoryKeys[2], entryMap);
|
||||||
final List<BatteryLevelData.PeriodBatteryLevelData> hourlyBatteryLevelsPerDay =
|
final BatteryLevelData batteryLevelData = generateBatteryLevelData(batteryHistoryKeys);
|
||||||
new ArrayList<>();
|
|
||||||
List<Long> timestamps = List.of(batteryHistoryKeys[0], batteryHistoryKeys[2]);
|
|
||||||
final List<Integer> levels = List.of(100, 100);
|
|
||||||
hourlyBatteryLevelsPerDay.add(
|
|
||||||
new BatteryLevelData.PeriodBatteryLevelData(timestamps, levels));
|
|
||||||
when(mPowerUsageFeatureProvider.getHideBackgroundUsageTimeSet())
|
when(mPowerUsageFeatureProvider.getHideBackgroundUsageTimeSet())
|
||||||
.thenReturn(new HashSet(Arrays.asList((CharSequence) "package2")));
|
.thenReturn(new HashSet(Arrays.asList((CharSequence) "package2")));
|
||||||
|
|
||||||
final Map<Integer, Map<Integer, BatteryDiffData>> resultMap =
|
final Map<Integer, Map<Integer, BatteryDiffData>> resultMap =
|
||||||
DataProcessor.getBatteryUsageMap(
|
DataProcessor.generateBatteryUsageMap(
|
||||||
mContext, hourlyBatteryLevelsPerDay, batteryHistoryMap,
|
mContext,
|
||||||
/*appUsagePeriodMap=*/ null);
|
DataProcessor.getBatteryDiffDataMap(mContext,
|
||||||
|
batteryLevelData.getHourlyBatteryLevelsPerDay(), batteryHistoryMap,
|
||||||
|
/*appUsagePeriodMap=*/ null, Set.of(), Set.of()),
|
||||||
|
batteryLevelData);
|
||||||
|
|
||||||
final BatteryDiffData resultDiffData =
|
final BatteryDiffData resultDiffData =
|
||||||
resultMap
|
resultMap
|
||||||
@@ -1523,7 +1399,10 @@ public final class DataProcessorTest {
|
|||||||
@Test
|
@Test
|
||||||
public void generateBatteryDiffData_emptyBatteryEntryList_returnNull() {
|
public void generateBatteryDiffData_emptyBatteryEntryList_returnNull() {
|
||||||
assertThat(DataProcessor.generateBatteryDiffData(mContext,
|
assertThat(DataProcessor.generateBatteryDiffData(mContext,
|
||||||
DataProcessor.convertToBatteryHistEntry(null, mBatteryUsageStats))).isNull();
|
System.currentTimeMillis(),
|
||||||
|
DataProcessor.convertToBatteryHistEntry(null, mBatteryUsageStats),
|
||||||
|
/* systemAppsPackageNames= */ Set.of(),
|
||||||
|
/* systemAppsUids= */ Set.of())).isNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -1574,7 +1453,10 @@ public final class DataProcessorTest {
|
|||||||
.when(mMockBatteryEntry4).getPowerComponentId();
|
.when(mMockBatteryEntry4).getPowerComponentId();
|
||||||
|
|
||||||
final BatteryDiffData batteryDiffData = DataProcessor.generateBatteryDiffData(mContext,
|
final BatteryDiffData batteryDiffData = DataProcessor.generateBatteryDiffData(mContext,
|
||||||
DataProcessor.convertToBatteryHistEntry(batteryEntryList, mBatteryUsageStats));
|
System.currentTimeMillis(),
|
||||||
|
DataProcessor.convertToBatteryHistEntry(batteryEntryList, mBatteryUsageStats),
|
||||||
|
/* systemAppsPackageNames= */ Set.of(),
|
||||||
|
/* systemAppsUids= */ Set.of());
|
||||||
|
|
||||||
assertBatteryDiffEntry(
|
assertBatteryDiffEntry(
|
||||||
batteryDiffData.getAppDiffEntryList().get(0), 0, /*uid=*/ 2L,
|
batteryDiffData.getAppDiffEntryList().get(0), 0, /*uid=*/ 2L,
|
||||||
@@ -2041,9 +1923,9 @@ public final class DataProcessorTest {
|
|||||||
final double backgroundUsageConsumePower, final double cachedUsageConsumePower,
|
final double backgroundUsageConsumePower, final double cachedUsageConsumePower,
|
||||||
final long foregroundUsageTimeInMs, final long backgroundUsageTimeInMs,
|
final long foregroundUsageTimeInMs, final long backgroundUsageTimeInMs,
|
||||||
final long screenOnTimeInMs) {
|
final long screenOnTimeInMs) {
|
||||||
assertThat(entry.mBatteryHistEntry.mUserId).isEqualTo(userId);
|
assertThat(entry.mUserId).isEqualTo(userId);
|
||||||
assertThat(entry.mBatteryHistEntry.mUid).isEqualTo(uid);
|
assertThat(entry.mUid).isEqualTo(uid);
|
||||||
assertThat(entry.mBatteryHistEntry.mConsumerType).isEqualTo(consumerType);
|
assertThat(entry.mConsumerType).isEqualTo(consumerType);
|
||||||
assertThat(entry.getPercentage()).isEqualTo(consumePercentage);
|
assertThat(entry.getPercentage()).isEqualTo(consumePercentage);
|
||||||
assertThat(entry.mForegroundUsageConsumePower).isEqualTo(foregroundUsageConsumePower);
|
assertThat(entry.mForegroundUsageConsumePower).isEqualTo(foregroundUsageConsumePower);
|
||||||
assertThat(entry.mForegroundServiceUsageConsumePower)
|
assertThat(entry.mForegroundServiceUsageConsumePower)
|
||||||
@@ -2054,4 +1936,12 @@ public final class DataProcessorTest {
|
|||||||
assertThat(entry.mBackgroundUsageTimeInMs).isEqualTo(backgroundUsageTimeInMs);
|
assertThat(entry.mBackgroundUsageTimeInMs).isEqualTo(backgroundUsageTimeInMs);
|
||||||
assertThat(entry.mScreenOnTimeInMs).isEqualTo(screenOnTimeInMs);
|
assertThat(entry.mScreenOnTimeInMs).isEqualTo(screenOnTimeInMs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private BatteryLevelData generateBatteryLevelData(long[] timestamps) {
|
||||||
|
Map<Long, Integer> batteryLevelMap = new ArrayMap<>();
|
||||||
|
for (long timestamp : timestamps) {
|
||||||
|
batteryLevelMap.put(timestamp, 100);
|
||||||
|
}
|
||||||
|
return new BatteryLevelData(batteryLevelMap);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -173,8 +173,8 @@ public final class DatabaseUtilsTest {
|
|||||||
doReturn(null).when(mContext).registerReceiver(any(), any());
|
doReturn(null).when(mContext).registerReceiver(any(), any());
|
||||||
assertThat(
|
assertThat(
|
||||||
DatabaseUtils.sendBatteryEntryData(
|
DatabaseUtils.sendBatteryEntryData(
|
||||||
mContext, /*batteryEntryList=*/ null, mBatteryUsageStats,
|
mContext, System.currentTimeMillis(), /*batteryEntryList=*/ null,
|
||||||
/*isFullChargeStart=*/ false))
|
mBatteryUsageStats, /*isFullChargeStart=*/ false))
|
||||||
.isNull();
|
.isNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -193,7 +193,10 @@ public final class DatabaseUtilsTest {
|
|||||||
|
|
||||||
final List<ContentValues> valuesList =
|
final List<ContentValues> valuesList =
|
||||||
DatabaseUtils.sendBatteryEntryData(
|
DatabaseUtils.sendBatteryEntryData(
|
||||||
mContext, batteryEntryList, mBatteryUsageStats,
|
mContext,
|
||||||
|
System.currentTimeMillis(),
|
||||||
|
batteryEntryList,
|
||||||
|
mBatteryUsageStats,
|
||||||
/*isFullChargeStart=*/ false);
|
/*isFullChargeStart=*/ false);
|
||||||
|
|
||||||
assertThat(valuesList).hasSize(2);
|
assertThat(valuesList).hasSize(2);
|
||||||
@@ -216,6 +219,7 @@ public final class DatabaseUtilsTest {
|
|||||||
final List<ContentValues> valuesList =
|
final List<ContentValues> valuesList =
|
||||||
DatabaseUtils.sendBatteryEntryData(
|
DatabaseUtils.sendBatteryEntryData(
|
||||||
mContext,
|
mContext,
|
||||||
|
System.currentTimeMillis(),
|
||||||
new ArrayList<>(),
|
new ArrayList<>(),
|
||||||
mBatteryUsageStats,
|
mBatteryUsageStats,
|
||||||
/*isFullChargeStart=*/ false);
|
/*isFullChargeStart=*/ false);
|
||||||
@@ -235,6 +239,7 @@ public final class DatabaseUtilsTest {
|
|||||||
final List<ContentValues> valuesList =
|
final List<ContentValues> valuesList =
|
||||||
DatabaseUtils.sendBatteryEntryData(
|
DatabaseUtils.sendBatteryEntryData(
|
||||||
mContext,
|
mContext,
|
||||||
|
System.currentTimeMillis(),
|
||||||
/*batteryEntryList=*/ null,
|
/*batteryEntryList=*/ null,
|
||||||
mBatteryUsageStats,
|
mBatteryUsageStats,
|
||||||
/*isFullChargeStart=*/ false);
|
/*isFullChargeStart=*/ false);
|
||||||
@@ -254,6 +259,7 @@ public final class DatabaseUtilsTest {
|
|||||||
final List<ContentValues> valuesList =
|
final List<ContentValues> valuesList =
|
||||||
DatabaseUtils.sendBatteryEntryData(
|
DatabaseUtils.sendBatteryEntryData(
|
||||||
mContext,
|
mContext,
|
||||||
|
System.currentTimeMillis(),
|
||||||
/*batteryEntryList=*/ null,
|
/*batteryEntryList=*/ null,
|
||||||
/*batteryUsageStats=*/ null,
|
/*batteryUsageStats=*/ null,
|
||||||
/*isFullChargeStart=*/ false);
|
/*isFullChargeStart=*/ false);
|
||||||
@@ -359,7 +365,7 @@ public final class DatabaseUtilsTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getHistoryMapSinceLastFullCharge_emptyCursorContent_returnEmptyMap() {
|
public void getHistoryMap_emptyCursorContent_returnEmptyMap() {
|
||||||
final MatrixCursor cursor = new MatrixCursor(
|
final MatrixCursor cursor = new MatrixCursor(
|
||||||
new String[] {
|
new String[] {
|
||||||
BatteryHistEntry.KEY_UID,
|
BatteryHistEntry.KEY_UID,
|
||||||
@@ -367,36 +373,33 @@ public final class DatabaseUtilsTest {
|
|||||||
BatteryHistEntry.KEY_TIMESTAMP});
|
BatteryHistEntry.KEY_TIMESTAMP});
|
||||||
DatabaseUtils.sFakeSupplier = () -> cursor;
|
DatabaseUtils.sFakeSupplier = () -> cursor;
|
||||||
|
|
||||||
assertThat(DatabaseUtils.getHistoryMapSinceLastFullCharge(
|
assertThat(DatabaseUtils.getHistoryMapSinceQueryTimestamp(mContext, 0)).isEmpty();
|
||||||
mContext, /*calendar=*/ null)).isEmpty();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getHistoryMapSinceLastFullCharge_nullCursor_returnEmptyMap() {
|
public void getHistoryMap_nullCursor_returnEmptyMap() {
|
||||||
DatabaseUtils.sFakeSupplier = () -> null;
|
DatabaseUtils.sFakeSupplier = () -> null;
|
||||||
assertThat(DatabaseUtils.getHistoryMapSinceLastFullCharge(
|
assertThat(DatabaseUtils.getHistoryMapSinceQueryTimestamp(mContext, 0)).isEmpty();
|
||||||
mContext, /*calendar=*/ null)).isEmpty();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getHistoryMapSinceLastFullCharge_returnExpectedMap() {
|
public void getHistoryMap_returnExpectedMap() {
|
||||||
final Long timestamp1 = Long.valueOf(1001L);
|
final Long timestamp1 = Long.valueOf(1001L);
|
||||||
final Long timestamp2 = Long.valueOf(1002L);
|
final Long timestamp2 = Long.valueOf(1002L);
|
||||||
final MatrixCursor cursor = getMatrixCursor();
|
final MatrixCursor cursor = getMatrixCursor();
|
||||||
// Adds fake data into the cursor.
|
// Adds fake data into the cursor.
|
||||||
cursor.addRow(new Object[] {
|
cursor.addRow(new Object[] {
|
||||||
"app name1", timestamp1, 1, ConvertUtils.CONSUMER_TYPE_UID_BATTERY});
|
"app name1", timestamp1, 1, ConvertUtils.CONSUMER_TYPE_UID_BATTERY, true});
|
||||||
cursor.addRow(new Object[] {
|
cursor.addRow(new Object[] {
|
||||||
"app name2", timestamp2, 2, ConvertUtils.CONSUMER_TYPE_UID_BATTERY});
|
"app name2", timestamp2, 2, ConvertUtils.CONSUMER_TYPE_UID_BATTERY, false});
|
||||||
cursor.addRow(new Object[] {
|
cursor.addRow(new Object[] {
|
||||||
"app name3", timestamp2, 3, ConvertUtils.CONSUMER_TYPE_UID_BATTERY});
|
"app name3", timestamp2, 3, ConvertUtils.CONSUMER_TYPE_UID_BATTERY, false});
|
||||||
cursor.addRow(new Object[] {
|
cursor.addRow(new Object[] {
|
||||||
"app name4", timestamp2, 4, ConvertUtils.CONSUMER_TYPE_UID_BATTERY});
|
"app name4", timestamp2, 4, ConvertUtils.CONSUMER_TYPE_UID_BATTERY, false});
|
||||||
DatabaseUtils.sFakeSupplier = () -> cursor;
|
DatabaseUtils.sFakeSupplier = () -> cursor;
|
||||||
|
|
||||||
final Map<Long, Map<String, BatteryHistEntry>> batteryHistMap =
|
final Map<Long, Map<String, BatteryHistEntry>> batteryHistMap =
|
||||||
DatabaseUtils.getHistoryMapSinceLastFullCharge(
|
DatabaseUtils.getHistoryMapSinceQueryTimestamp(mContext, timestamp1);
|
||||||
mContext, /*calendar=*/ null);
|
|
||||||
|
|
||||||
assertThat(batteryHistMap).hasSize(2);
|
assertThat(batteryHistMap).hasSize(2);
|
||||||
// Verifies the BatteryHistEntry data for timestamp1.
|
// Verifies the BatteryHistEntry data for timestamp1.
|
||||||
@@ -412,7 +415,7 @@ public final class DatabaseUtilsTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getHistoryMapSinceLastFullCharge_withWorkProfile_returnExpectedMap()
|
public void getHistoryMap_withWorkProfile_returnExpectedMap()
|
||||||
throws PackageManager.NameNotFoundException {
|
throws PackageManager.NameNotFoundException {
|
||||||
doReturn("com.fake.package").when(mContext).getPackageName();
|
doReturn("com.fake.package").when(mContext).getPackageName();
|
||||||
doReturn(mMockContext).when(mContext).createPackageContextAsUser(
|
doReturn(mMockContext).when(mContext).createPackageContextAsUser(
|
||||||
@@ -425,8 +428,7 @@ public final class DatabaseUtilsTest {
|
|||||||
DatabaseUtils.sFakeSupplier = () -> getMatrixCursor();
|
DatabaseUtils.sFakeSupplier = () -> getMatrixCursor();
|
||||||
|
|
||||||
final Map<Long, Map<String, BatteryHistEntry>> batteryHistMap =
|
final Map<Long, Map<String, BatteryHistEntry>> batteryHistMap =
|
||||||
DatabaseUtils.getHistoryMapSinceLastFullCharge(
|
DatabaseUtils.getHistoryMapSinceQueryTimestamp(mContext, 0);
|
||||||
mContext, /*calendar=*/ null);
|
|
||||||
|
|
||||||
assertThat(batteryHistMap).isEmpty();
|
assertThat(batteryHistMap).isEmpty();
|
||||||
}
|
}
|
||||||
@@ -571,6 +573,7 @@ public final class DatabaseUtilsTest {
|
|||||||
BatteryHistEntry.KEY_PACKAGE_NAME,
|
BatteryHistEntry.KEY_PACKAGE_NAME,
|
||||||
BatteryHistEntry.KEY_TIMESTAMP,
|
BatteryHistEntry.KEY_TIMESTAMP,
|
||||||
BatteryHistEntry.KEY_UID,
|
BatteryHistEntry.KEY_UID,
|
||||||
BatteryHistEntry.KEY_CONSUMER_TYPE});
|
BatteryHistEntry.KEY_CONSUMER_TYPE,
|
||||||
|
BatteryHistEntry.KEY_IS_FULL_CHARGE_CYCLE_START});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -134,11 +134,6 @@ public class PowerUsageBaseTest {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected boolean isBatteryHistoryNeeded() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void refreshUi(int refreshType) {
|
protected void refreshUi(int refreshType) {
|
||||||
// Do nothing
|
// Do nothing
|
||||||
|
@@ -16,6 +16,10 @@
|
|||||||
|
|
||||||
package com.android.settings.fuelgauge.batteryusage.db;
|
package com.android.settings.fuelgauge.batteryusage.db;
|
||||||
|
|
||||||
|
import static com.android.settings.fuelgauge.batteryusage.db.BatteryEventEntity.KEY_BATTERY_EVENT_TYPE;
|
||||||
|
import static com.android.settings.fuelgauge.batteryusage.db.BatteryEventEntity.KEY_BATTERY_LEVEL;
|
||||||
|
import static com.android.settings.fuelgauge.batteryusage.db.BatteryEventEntity.KEY_TIMESTAMP;
|
||||||
|
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
@@ -31,9 +35,14 @@ import org.junit.Test;
|
|||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.robolectric.RobolectricTestRunner;
|
import org.robolectric.RobolectricTestRunner;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/** Tests for {@link BatteryEventDao}. */
|
/** Tests for {@link BatteryEventDao}. */
|
||||||
@RunWith(RobolectricTestRunner.class)
|
@RunWith(RobolectricTestRunner.class)
|
||||||
public final class BatteryEventDaoTest {
|
public final class BatteryEventDaoTest {
|
||||||
|
private static final long TIMESTAMP1 = System.currentTimeMillis();
|
||||||
|
private static final long TIMESTAMP2 = TIMESTAMP1 + 2;
|
||||||
|
|
||||||
private Context mContext;
|
private Context mContext;
|
||||||
private BatteryStateDatabase mDatabase;
|
private BatteryStateDatabase mDatabase;
|
||||||
private BatteryEventDao mBatteryEventDao;
|
private BatteryEventDao mBatteryEventDao;
|
||||||
@@ -51,8 +60,44 @@ public final class BatteryEventDaoTest {
|
|||||||
BatteryStateDatabase.setBatteryStateDatabase(/*database=*/ null);
|
BatteryStateDatabase.setBatteryStateDatabase(/*database=*/ null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getAllAfter_returnExpectedResult() {
|
public void getLastFullChargeTimestamp_normalFlow_expectedBehavior() throws Exception {
|
||||||
|
mBatteryEventDao.insert(BatteryEventEntity.newBuilder()
|
||||||
|
.setTimestamp(TIMESTAMP1)
|
||||||
|
.setBatteryEventType(3)
|
||||||
|
.setBatteryLevel(100)
|
||||||
|
.build());
|
||||||
|
mBatteryEventDao.insert(BatteryEventEntity.newBuilder()
|
||||||
|
.setTimestamp(TIMESTAMP2)
|
||||||
|
.setBatteryEventType(4)
|
||||||
|
.setBatteryLevel(96)
|
||||||
|
.build());
|
||||||
|
|
||||||
|
final Cursor cursor = mBatteryEventDao.getLastFullChargeTimestamp();
|
||||||
|
assertThat(cursor.getCount()).isEqualTo(1);
|
||||||
|
cursor.moveToFirst();
|
||||||
|
assertThat(cursor.getLong(0)).isEqualTo(TIMESTAMP1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getLastFullChargeTimestamp_noLastFullChargeTime_returns0() throws Exception {
|
||||||
|
mBatteryEventDao.clearAll();
|
||||||
|
mBatteryEventDao.insert(BatteryEventEntity.newBuilder()
|
||||||
|
.setTimestamp(TIMESTAMP2)
|
||||||
|
.setBatteryEventType(4)
|
||||||
|
.setBatteryLevel(96)
|
||||||
|
.build());
|
||||||
|
|
||||||
|
final Cursor cursor = mBatteryEventDao.getLastFullChargeTimestamp();
|
||||||
|
|
||||||
|
assertThat(cursor.getCount()).isEqualTo(1);
|
||||||
|
cursor.moveToFirst();
|
||||||
|
assertThat(cursor.getLong(0)).isEqualTo(0L);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getAllAfter_normalFlow_returnExpectedResult() {
|
||||||
mBatteryEventDao.insert(BatteryEventEntity.newBuilder()
|
mBatteryEventDao.insert(BatteryEventEntity.newBuilder()
|
||||||
.setTimestamp(100L)
|
.setTimestamp(100L)
|
||||||
.setBatteryEventType(1)
|
.setBatteryEventType(1)
|
||||||
@@ -64,17 +109,44 @@ public final class BatteryEventDaoTest {
|
|||||||
.setBatteryLevel(88)
|
.setBatteryLevel(88)
|
||||||
.build());
|
.build());
|
||||||
|
|
||||||
final Cursor cursor = mBatteryEventDao.getAllAfter(160L);
|
final Cursor cursor = mBatteryEventDao.getAllAfter(160L, List.of(1, 2));
|
||||||
assertThat(cursor.getCount()).isEqualTo(1);
|
assertThat(cursor.getCount()).isEqualTo(1);
|
||||||
cursor.moveToFirst();
|
cursor.moveToFirst();
|
||||||
assertThat(cursor.getLong(cursor.getColumnIndex(BatteryEventEntity.KEY_TIMESTAMP)))
|
assertThat(cursor.getLong(cursor.getColumnIndex(KEY_TIMESTAMP)))
|
||||||
.isEqualTo(200L);
|
.isEqualTo(200L);
|
||||||
assertThat(cursor.getInt(cursor.getColumnIndex(BatteryEventEntity.KEY_BATTERY_EVENT_TYPE)))
|
assertThat(cursor.getInt(cursor.getColumnIndex(KEY_BATTERY_EVENT_TYPE)))
|
||||||
.isEqualTo(2);
|
.isEqualTo(2);
|
||||||
assertThat(cursor.getInt(cursor.getColumnIndex(BatteryEventEntity.KEY_BATTERY_LEVEL)))
|
assertThat(cursor.getInt(cursor.getColumnIndex(KEY_BATTERY_LEVEL)))
|
||||||
.isEqualTo(88);
|
.isEqualTo(88);
|
||||||
|
|
||||||
mBatteryEventDao.clearAll();
|
mBatteryEventDao.clearAll();
|
||||||
assertThat(mBatteryEventDao.getAll()).isEmpty();
|
assertThat(mBatteryEventDao.getAll()).isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getAllAfter_filterBatteryTypes_returnExpectedResult() {
|
||||||
|
mBatteryEventDao.insert(BatteryEventEntity.newBuilder()
|
||||||
|
.setTimestamp(100L)
|
||||||
|
.setBatteryEventType(1)
|
||||||
|
.setBatteryLevel(66)
|
||||||
|
.build());
|
||||||
|
mBatteryEventDao.insert(BatteryEventEntity.newBuilder()
|
||||||
|
.setTimestamp(200L)
|
||||||
|
.setBatteryEventType(2)
|
||||||
|
.setBatteryLevel(88)
|
||||||
|
.build());
|
||||||
|
|
||||||
|
final Cursor cursor = mBatteryEventDao.getAllAfter(0L, List.of(1));
|
||||||
|
assertThat(cursor.getCount()).isEqualTo(1);
|
||||||
|
cursor.moveToFirst();
|
||||||
|
assertThat(cursor.getLong(cursor.getColumnIndex(KEY_TIMESTAMP)))
|
||||||
|
.isEqualTo(100L);
|
||||||
|
assertThat(cursor.getInt(cursor.getColumnIndex(KEY_BATTERY_EVENT_TYPE)))
|
||||||
|
.isEqualTo(1);
|
||||||
|
assertThat(cursor.getInt(cursor.getColumnIndex(KEY_BATTERY_LEVEL)))
|
||||||
|
.isEqualTo(66);
|
||||||
|
|
||||||
|
mBatteryEventDao.clearAll();
|
||||||
|
assertThat(mBatteryEventDao.getAll()).isEmpty();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -37,9 +37,10 @@ import java.util.List;
|
|||||||
@RunWith(RobolectricTestRunner.class)
|
@RunWith(RobolectricTestRunner.class)
|
||||||
public final class BatteryStateDaoTest {
|
public final class BatteryStateDaoTest {
|
||||||
private static final int CURSOR_COLUMN_SIZE = 9;
|
private static final int CURSOR_COLUMN_SIZE = 9;
|
||||||
private static final long TIMESTAMP1 = System.currentTimeMillis();
|
private static final long CURRENT = System.currentTimeMillis();
|
||||||
private static final long TIMESTAMP2 = System.currentTimeMillis() + 2;
|
private static final long TIMESTAMP1 = CURRENT;
|
||||||
private static final long TIMESTAMP3 = System.currentTimeMillis() + 4;
|
private static final long TIMESTAMP2 = CURRENT + 2;
|
||||||
|
private static final long TIMESTAMP3 = CURRENT + 4;
|
||||||
private static final String PACKAGE_NAME1 = "com.android.apps.settings";
|
private static final String PACKAGE_NAME1 = "com.android.apps.settings";
|
||||||
private static final String PACKAGE_NAME2 = "com.android.apps.calendar";
|
private static final String PACKAGE_NAME2 = "com.android.apps.calendar";
|
||||||
private static final String PACKAGE_NAME3 = "com.android.apps.gmail";
|
private static final String PACKAGE_NAME3 = "com.android.apps.gmail";
|
||||||
@@ -67,7 +68,7 @@ public final class BatteryStateDaoTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void batteryStateDao_insertAll() throws Exception {
|
public void insertAll_normalFlow_expectedBehavior() throws Exception {
|
||||||
final List<BatteryState> states = mBatteryStateDao.getAllAfter(TIMESTAMP1);
|
final List<BatteryState> states = mBatteryStateDao.getAllAfter(TIMESTAMP1);
|
||||||
assertThat(states).hasSize(2);
|
assertThat(states).hasSize(2);
|
||||||
// Verifies the queried battery states.
|
// Verifies the queried battery states.
|
||||||
@@ -76,8 +77,26 @@ public final class BatteryStateDaoTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void batteryStateDao_getCursorSinceLastFullCharge() throws Exception {
|
public void getLatestTimestamp_normalFlow_expectedBehavior() throws Exception {
|
||||||
final Cursor cursor1 = mBatteryStateDao.getCursorSinceLastFullCharge(TIMESTAMP1);
|
final Cursor cursor1 = mBatteryStateDao.getLatestTimestampBefore(TIMESTAMP1 - 1);
|
||||||
|
assertThat(cursor1.getCount()).isEqualTo(1);
|
||||||
|
cursor1.moveToFirst();
|
||||||
|
assertThat(cursor1.getLong(0)).isEqualTo(0L);
|
||||||
|
|
||||||
|
final Cursor cursor2 = mBatteryStateDao.getLatestTimestampBefore(TIMESTAMP2);
|
||||||
|
assertThat(cursor2.getCount()).isEqualTo(1);
|
||||||
|
cursor2.moveToFirst();
|
||||||
|
assertThat(cursor2.getLong(0)).isEqualTo(TIMESTAMP2);
|
||||||
|
|
||||||
|
final Cursor cursor3 = mBatteryStateDao.getLatestTimestampBefore(TIMESTAMP3 + 1);
|
||||||
|
assertThat(cursor3.getCount()).isEqualTo(1);
|
||||||
|
cursor3.moveToFirst();
|
||||||
|
assertThat(cursor3.getLong(0)).isEqualTo(TIMESTAMP3);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getBatteryStatesAfter_normalFlow_expectedBehavior() throws Exception {
|
||||||
|
final Cursor cursor1 = mBatteryStateDao.getBatteryStatesAfter(TIMESTAMP1);
|
||||||
assertThat(cursor1.getCount()).isEqualTo(3);
|
assertThat(cursor1.getCount()).isEqualTo(3);
|
||||||
assertThat(cursor1.getColumnCount()).isEqualTo(CURSOR_COLUMN_SIZE);
|
assertThat(cursor1.getColumnCount()).isEqualTo(CURSOR_COLUMN_SIZE);
|
||||||
// Verifies the queried first battery state.
|
// Verifies the queried first battery state.
|
||||||
@@ -90,7 +109,7 @@ public final class BatteryStateDaoTest {
|
|||||||
cursor1.moveToNext();
|
cursor1.moveToNext();
|
||||||
assertThat(cursor1.getString(3 /*packageName*/)).isEqualTo(PACKAGE_NAME3);
|
assertThat(cursor1.getString(3 /*packageName*/)).isEqualTo(PACKAGE_NAME3);
|
||||||
|
|
||||||
final Cursor cursor2 = mBatteryStateDao.getCursorSinceLastFullCharge(TIMESTAMP3);
|
final Cursor cursor2 = mBatteryStateDao.getBatteryStatesAfter(TIMESTAMP3);
|
||||||
assertThat(cursor2.getCount()).isEqualTo(1);
|
assertThat(cursor2.getCount()).isEqualTo(1);
|
||||||
assertThat(cursor2.getColumnCount()).isEqualTo(CURSOR_COLUMN_SIZE);
|
assertThat(cursor2.getColumnCount()).isEqualTo(CURSOR_COLUMN_SIZE);
|
||||||
// Verifies the queried first battery state.
|
// Verifies the queried first battery state.
|
||||||
@@ -99,25 +118,7 @@ public final class BatteryStateDaoTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void batteryStateDao_getCursorSinceLastFullCharge_noFullChargeData_returnSevenDaysData()
|
public void clearAllBefore_normalFlow_expectedBehavior() throws Exception {
|
||||||
throws Exception {
|
|
||||||
mBatteryStateDao.clearAll();
|
|
||||||
BatteryTestUtils.insertDataToBatteryStateTable(mContext, TIMESTAMP3, PACKAGE_NAME3);
|
|
||||||
BatteryTestUtils.insertDataToBatteryStateTable(mContext, TIMESTAMP2, PACKAGE_NAME2);
|
|
||||||
BatteryTestUtils.insertDataToBatteryStateTable(mContext, TIMESTAMP1, PACKAGE_NAME1);
|
|
||||||
final Cursor cursor = mBatteryStateDao.getCursorSinceLastFullCharge(TIMESTAMP2);
|
|
||||||
assertThat(cursor.getCount()).isEqualTo(2);
|
|
||||||
assertThat(cursor.getColumnCount()).isEqualTo(CURSOR_COLUMN_SIZE);
|
|
||||||
// Verifies the queried first battery state.
|
|
||||||
cursor.moveToFirst();
|
|
||||||
assertThat(cursor.getString(3 /*packageName*/)).isEqualTo(PACKAGE_NAME2);
|
|
||||||
// Verifies the queried third battery state.
|
|
||||||
cursor.moveToNext();
|
|
||||||
assertThat(cursor.getString(3 /*packageName*/)).isEqualTo(PACKAGE_NAME3);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void batteryStateDao_clearAllBefore() throws Exception {
|
|
||||||
mBatteryStateDao.clearAllBefore(TIMESTAMP2);
|
mBatteryStateDao.clearAllBefore(TIMESTAMP2);
|
||||||
|
|
||||||
final List<BatteryState> states = mBatteryStateDao.getAllAfter(0);
|
final List<BatteryState> states = mBatteryStateDao.getAllAfter(0);
|
||||||
@@ -127,20 +128,20 @@ public final class BatteryStateDaoTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void batteryStateDao_clearAll() throws Exception {
|
public void clearAll_normalFlow_expectedBehavior() throws Exception {
|
||||||
assertThat(mBatteryStateDao.getAllAfter(0)).hasSize(3);
|
assertThat(mBatteryStateDao.getAllAfter(0)).hasSize(3);
|
||||||
mBatteryStateDao.clearAll();
|
mBatteryStateDao.clearAll();
|
||||||
assertThat(mBatteryStateDao.getAllAfter(0)).isEmpty();
|
assertThat(mBatteryStateDao.getAllAfter(0)).isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getInstance_createNewInstance() throws Exception {
|
public void getInstance_createNewInstance_returnsExpectedResult() throws Exception {
|
||||||
BatteryStateDatabase.setBatteryStateDatabase(/*database=*/ null);
|
BatteryStateDatabase.setBatteryStateDatabase(/*database=*/ null);
|
||||||
assertThat(BatteryStateDatabase.getInstance(mContext)).isNotNull();
|
assertThat(BatteryStateDatabase.getInstance(mContext)).isNotNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getDistinctTimestampCount_returnsExpectedResult() {
|
public void getDistinctTimestampCount_normalFlow_returnsExpectedResult() {
|
||||||
assertThat(mBatteryStateDao.getDistinctTimestampCount(/*timestamp=*/ 0))
|
assertThat(mBatteryStateDao.getDistinctTimestampCount(/*timestamp=*/ 0))
|
||||||
.isEqualTo(3);
|
.isEqualTo(3);
|
||||||
assertThat(mBatteryStateDao.getDistinctTimestampCount(TIMESTAMP1))
|
assertThat(mBatteryStateDao.getDistinctTimestampCount(TIMESTAMP1))
|
||||||
@@ -148,7 +149,7 @@ public final class BatteryStateDaoTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getDistinctTimestamps_returnsExpectedResult() {
|
public void getDistinctTimestamps_normalFlow_returnsExpectedResult() {
|
||||||
final List<Long> timestamps =
|
final List<Long> timestamps =
|
||||||
mBatteryStateDao.getDistinctTimestamps(/*timestamp=*/ 0);
|
mBatteryStateDao.getDistinctTimestamps(/*timestamp=*/ 0);
|
||||||
|
|
||||||
|
@@ -0,0 +1,110 @@
|
|||||||
|
/*
|
||||||
|
* 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.db;
|
||||||
|
|
||||||
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.database.Cursor;
|
||||||
|
|
||||||
|
import androidx.test.core.app.ApplicationProvider;
|
||||||
|
|
||||||
|
import com.android.settings.testutils.BatteryTestUtils;
|
||||||
|
|
||||||
|
import org.junit.After;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.robolectric.RobolectricTestRunner;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/** Tests for {@link BatteryUsageSlotDao}. */
|
||||||
|
@RunWith(RobolectricTestRunner.class)
|
||||||
|
public final class BatteryUsageSlotDaoTest {
|
||||||
|
private static final int CURSOR_COLUMN_SIZE = 3;
|
||||||
|
private static final long CURRENT = System.currentTimeMillis();
|
||||||
|
private static final long TIMESTAMP1 = CURRENT;
|
||||||
|
private static final long TIMESTAMP2 = CURRENT + 2;
|
||||||
|
private static final String BATTERY_USAGE_SLOT_STRING1 = "BATTERY_USAGE_SLOT_STRING1";
|
||||||
|
private static final String BATTERY_USAGE_SLOT_STRING2 = "BATTERY_USAGE_SLOT_STRING2";
|
||||||
|
|
||||||
|
private Context mContext;
|
||||||
|
private BatteryStateDatabase mDatabase;
|
||||||
|
private BatteryUsageSlotDao mBatteryUsageSlotDao;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
mContext = ApplicationProvider.getApplicationContext();
|
||||||
|
mDatabase = BatteryTestUtils.setUpBatteryStateDatabase(mContext);
|
||||||
|
mBatteryUsageSlotDao = mDatabase.batteryUsageSlotDao();
|
||||||
|
mBatteryUsageSlotDao.insert(
|
||||||
|
new BatteryUsageSlotEntity(TIMESTAMP1, BATTERY_USAGE_SLOT_STRING1));
|
||||||
|
mBatteryUsageSlotDao.insert(
|
||||||
|
new BatteryUsageSlotEntity(TIMESTAMP2, BATTERY_USAGE_SLOT_STRING2));
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void closeDb() {
|
||||||
|
mDatabase.close();
|
||||||
|
BatteryStateDatabase.setBatteryStateDatabase(/*database=*/ null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getAll_normalFlow_expectedBehavior() throws Exception {
|
||||||
|
final List<BatteryUsageSlotEntity> entities = mBatteryUsageSlotDao.getAll();
|
||||||
|
assertThat(entities).hasSize(2);
|
||||||
|
assertThat(entities.get(0).timestamp).isEqualTo(TIMESTAMP1);
|
||||||
|
assertThat(entities.get(0).batteryUsageSlot).isEqualTo(BATTERY_USAGE_SLOT_STRING1);
|
||||||
|
assertThat(entities.get(1).timestamp).isEqualTo(TIMESTAMP2);
|
||||||
|
assertThat(entities.get(1).batteryUsageSlot).isEqualTo(BATTERY_USAGE_SLOT_STRING2);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getAllAfter_normalFlow_expectedBehavior() throws Exception {
|
||||||
|
final Cursor cursor1 = mBatteryUsageSlotDao.getAllAfter(TIMESTAMP1);
|
||||||
|
assertThat(cursor1.getCount()).isEqualTo(2);
|
||||||
|
assertThat(cursor1.getColumnCount()).isEqualTo(CURSOR_COLUMN_SIZE);
|
||||||
|
cursor1.moveToFirst();
|
||||||
|
assertThat(cursor1.getLong(1 /*timestamp*/)).isEqualTo(TIMESTAMP1);
|
||||||
|
cursor1.moveToNext();
|
||||||
|
assertThat(cursor1.getLong(1 /*timestamp*/)).isEqualTo(TIMESTAMP2);
|
||||||
|
|
||||||
|
final Cursor cursor2 = mBatteryUsageSlotDao.getAllAfter(TIMESTAMP1 + 1);
|
||||||
|
assertThat(cursor2.getCount()).isEqualTo(1);
|
||||||
|
assertThat(cursor2.getColumnCount()).isEqualTo(CURSOR_COLUMN_SIZE);
|
||||||
|
cursor2.moveToFirst();
|
||||||
|
assertThat(cursor2.getLong(1 /*timestamp*/)).isEqualTo(TIMESTAMP2);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void clearAllBefore_normalFlow_expectedBehavior() throws Exception {
|
||||||
|
mBatteryUsageSlotDao.clearAllBefore(TIMESTAMP1);
|
||||||
|
|
||||||
|
final List<BatteryUsageSlotEntity> entities = mBatteryUsageSlotDao.getAll();
|
||||||
|
assertThat(entities).hasSize(1);
|
||||||
|
assertThat(entities.get(0).timestamp).isEqualTo(TIMESTAMP2);
|
||||||
|
assertThat(entities.get(0).batteryUsageSlot).isEqualTo(BATTERY_USAGE_SLOT_STRING2);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void clearAll_normalFlow_expectedBehavior() throws Exception {
|
||||||
|
mBatteryUsageSlotDao.clearAll();
|
||||||
|
|
||||||
|
assertThat(mBatteryUsageSlotDao.getAll()).isEmpty();
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,44 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2023 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.db;
|
||||||
|
|
||||||
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.robolectric.RobolectricTestRunner;
|
||||||
|
|
||||||
|
/** Tests for {@link BatteryUsageSlotEntity}. */
|
||||||
|
@RunWith(RobolectricTestRunner.class)
|
||||||
|
public final class BatteryUsageSlotEntityTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testBuilder_returnsExpectedResult() {
|
||||||
|
final long timestamp = 10001L;
|
||||||
|
final String batteryUsageSlotString = "batteryUsageSlotString";
|
||||||
|
|
||||||
|
BatteryUsageSlotEntity entity = BatteryUsageSlotEntity
|
||||||
|
.newBuilder()
|
||||||
|
.setTimestamp(timestamp)
|
||||||
|
.setBatteryUsageSlot(batteryUsageSlotString)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
// Verifies the app relative information.
|
||||||
|
assertThat(entity.timestamp).isEqualTo(timestamp);
|
||||||
|
assertThat(entity.batteryUsageSlot).isEqualTo(batteryUsageSlotString);
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user