Files
packages_apps_Settings/src/com/android/settings/fuelgauge/batteryusage/ConvertUtils.java
mxyyiyi 59e5dc720a Add whether app optimization mode mutable in BatteryUsageDiff proto.
Bug: 350657779
Test: atest ConvertUtilsTest
Flag: EXEMPT bug fix
Change-Id: I80a5e6513e1bee88f85caeed7661b10204df8a51
2024-08-02 10:41:24 +08:00

691 lines
31 KiB
Java

/*
* 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.annotation.IntDef;
import android.app.usage.IUsageStatsManager;
import android.app.usage.UsageEvents.Event;
import android.app.usage.UsageStatsManager;
import android.content.ContentValues;
import android.content.Context;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.os.BatteryUsageStats;
import android.os.Build;
import android.os.LocaleList;
import android.os.UserHandle;
import android.text.TextUtils;
import android.text.format.DateFormat;
import android.util.Base64;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import androidx.core.util.Pair;
import com.android.settings.fuelgauge.BatteryUtils;
import com.android.settings.fuelgauge.batteryusage.db.AppUsageEventEntity;
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.RetentionPolicy;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.TimeZone;
/** A utility class to convert data into another types. */
public final class ConvertUtils {
private static final String TAG = "ConvertUtils";
/** A fake package name to represent no BatteryEntry data. */
public static final String FAKE_PACKAGE_NAME = "fake_package";
@IntDef(
prefix = {"CONSUMER_TYPE"},
value = {
CONSUMER_TYPE_UNKNOWN,
CONSUMER_TYPE_UID_BATTERY,
CONSUMER_TYPE_USER_BATTERY,
CONSUMER_TYPE_SYSTEM_BATTERY,
})
@Retention(RetentionPolicy.SOURCE)
public @interface ConsumerType {}
public static final int CONSUMER_TYPE_UNKNOWN = 0;
public static final int CONSUMER_TYPE_UID_BATTERY = 1;
public static final int CONSUMER_TYPE_USER_BATTERY = 2;
public static final int CONSUMER_TYPE_SYSTEM_BATTERY = 3;
public static final int DEFAULT_USAGE_SOURCE = UsageStatsManager.USAGE_SOURCE_CURRENT_ACTIVITY;
public static final int EMPTY_USAGE_SOURCE = -1;
@VisibleForTesting static int sUsageSource = EMPTY_USAGE_SOURCE;
private ConvertUtils() {}
/** 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(
final BatteryEntry entry,
final BatteryUsageStats batteryUsageStats,
final int batteryLevel,
final int batteryStatus,
final int batteryHealth,
final long bootTimestamp,
final long timestamp,
final boolean isFullChargeStart) {
final ContentValues values = new ContentValues();
if (entry != null && batteryUsageStats != null) {
values.put(BatteryHistEntry.KEY_UID, Long.valueOf(entry.getUid()));
values.put(
BatteryHistEntry.KEY_USER_ID,
Long.valueOf(UserHandle.getUserId(entry.getUid())));
final String packageName = entry.getDefaultPackageName();
values.put(BatteryHistEntry.KEY_PACKAGE_NAME, packageName != null ? packageName : "");
values.put(
BatteryHistEntry.KEY_CONSUMER_TYPE, Integer.valueOf(entry.getConsumerType()));
} else {
values.put(BatteryHistEntry.KEY_PACKAGE_NAME, FAKE_PACKAGE_NAME);
}
values.put(BatteryHistEntry.KEY_TIMESTAMP, Long.valueOf(timestamp));
values.put(
BatteryHistEntry.KEY_IS_FULL_CHARGE_CYCLE_START,
Boolean.valueOf(isFullChargeStart));
final BatteryInformation batteryInformation =
constructBatteryInformation(
entry,
batteryUsageStats,
batteryLevel,
batteryStatus,
batteryHealth,
bootTimestamp);
values.put(
BatteryHistEntry.KEY_BATTERY_INFORMATION,
convertBatteryInformationToString(batteryInformation));
// Save the BatteryInformation unencoded string into database for debugging.
if (Build.TYPE.equals("userdebug")) {
values.put(
BatteryHistEntry.KEY_BATTERY_INFORMATION_DEBUG, batteryInformation.toString());
}
return values;
}
/** Converts {@link AppUsageEvent} to {@link ContentValues} */
public static ContentValues convertAppUsageEventToContentValues(final AppUsageEvent event) {
final ContentValues values = new ContentValues();
values.put(AppUsageEventEntity.KEY_UID, event.getUid());
values.put(AppUsageEventEntity.KEY_USER_ID, event.getUserId());
values.put(AppUsageEventEntity.KEY_TIMESTAMP, event.getTimestamp());
values.put(AppUsageEventEntity.KEY_APP_USAGE_EVENT_TYPE, event.getType().getNumber());
values.put(AppUsageEventEntity.KEY_PACKAGE_NAME, event.getPackageName());
values.put(AppUsageEventEntity.KEY_INSTANCE_ID, event.getInstanceId());
values.put(AppUsageEventEntity.KEY_TASK_ROOT_PACKAGE_NAME, event.getTaskRootPackageName());
return values;
}
/** Converts {@link BatteryEvent} to {@link ContentValues} */
public static ContentValues convertBatteryEventToContentValues(final BatteryEvent event) {
final ContentValues values = new ContentValues();
values.put(BatteryEventEntity.KEY_TIMESTAMP, event.getTimestamp());
values.put(BatteryEventEntity.KEY_BATTERY_EVENT_TYPE, event.getType().getNumber());
values.put(BatteryEventEntity.KEY_BATTERY_LEVEL, event.getBatteryLevel());
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. */
public static String convertBatteryInformationToString(
final BatteryInformation batteryInformation) {
return Base64.encodeToString(batteryInformation.toByteArray(), Base64.DEFAULT);
}
/** Gets the {@link BatteryInformation} instance from {@link ContentValues}. */
public static BatteryInformation getBatteryInformation(
final ContentValues values, final String key) {
final BatteryInformation defaultInstance = BatteryInformation.getDefaultInstance();
if (values != null && values.containsKey(key)) {
return BatteryUtils.parseProtoFromString(values.getAsString(key), defaultInstance);
}
return defaultInstance;
}
/** Gets the {@link BatteryInformation} instance from {@link Cursor}. */
public static BatteryInformation getBatteryInformation(final Cursor cursor, final String key) {
final BatteryInformation defaultInstance = BatteryInformation.getDefaultInstance();
final int columnIndex = cursor.getColumnIndex(key);
if (columnIndex >= 0) {
return BatteryUtils.parseProtoFromString(
cursor.getString(columnIndex), defaultInstance);
}
return defaultInstance;
}
/** Gets the encoded string from {@link BatteryReattribute} instance. */
@NonNull
public static String encodeBatteryReattribute(
@NonNull BatteryReattribute batteryReattribute) {
return Base64.encodeToString(batteryReattribute.toByteArray(), Base64.DEFAULT);
}
/** Gets the decoded {@link BatteryReattribute} instance from string. */
@NonNull
public static BatteryReattribute decodeBatteryReattribute(@NonNull String content) {
return BatteryUtils.parseProtoFromString(
content, BatteryReattribute.getDefaultInstance());
}
/** Converts to {@link BatteryHistEntry} */
public static BatteryHistEntry convertToBatteryHistEntry(
BatteryEntry entry, BatteryUsageStats batteryUsageStats) {
return new BatteryHistEntry(
convertBatteryEntryToContentValues(
entry,
batteryUsageStats,
/* batteryLevel= */ 0,
/* batteryStatus= */ 0,
/* batteryHealth= */ 0,
/* bootTimestamp= */ 0,
/* timestamp= */ 0,
/* isFullChargeStart= */ false));
}
/** Converts from {@link Event} to {@link AppUsageEvent} */
@Nullable
public static AppUsageEvent convertToAppUsageEvent(
Context context,
IUsageStatsManager usageStatsManager,
final Event event,
final long userId) {
final String packageName = event.getPackageName();
if (packageName == null) {
// See b/190609174: Event package names should never be null, but sometimes they are.
// Note that system events like device shutting down should still come with the android
// package name.
Log.w(
TAG,
String.format(
"Ignoring a usage event with null package name (timestamp=%d, type=%d)",
event.getTimeStamp(), event.getEventType()));
return null;
}
final AppUsageEvent.Builder appUsageEventBuilder = AppUsageEvent.newBuilder();
appUsageEventBuilder
.setTimestamp(event.getTimeStamp())
.setType(getAppUsageEventType(event.getEventType()))
.setPackageName(packageName)
.setUserId(userId);
final String taskRootPackageName = getTaskRootPackageName(event);
if (taskRootPackageName != null) {
appUsageEventBuilder.setTaskRootPackageName(taskRootPackageName);
}
final String effectivePackageName =
getEffectivePackageName(
context, usageStatsManager, packageName, taskRootPackageName);
try {
final long uid =
context.getPackageManager()
.getPackageUidAsUser(effectivePackageName, (int) userId);
appUsageEventBuilder.setUid(uid);
} catch (PackageManager.NameNotFoundException e) {
Log.w(
TAG,
String.format(
"Fail to get uid for package %s of user %d)",
event.getPackageName(), userId));
return null;
}
try {
appUsageEventBuilder.setInstanceId(event.getInstanceId());
} catch (NoClassDefFoundError | NoSuchMethodError e) {
Log.w(TAG, "UsageEvent instance ID API error");
}
return appUsageEventBuilder.build();
}
/** Converts from {@link Cursor} to {@link AppUsageEvent} */
public static AppUsageEvent convertToAppUsageEvent(final Cursor cursor) {
final AppUsageEvent.Builder eventBuilder = AppUsageEvent.newBuilder();
eventBuilder.setTimestamp(getLongFromCursor(cursor, AppUsageEventEntity.KEY_TIMESTAMP));
eventBuilder.setType(
AppUsageEventType.forNumber(
getIntegerFromCursor(
cursor, AppUsageEventEntity.KEY_APP_USAGE_EVENT_TYPE)));
eventBuilder.setPackageName(
getStringFromCursor(cursor, AppUsageEventEntity.KEY_PACKAGE_NAME));
eventBuilder.setInstanceId(
getIntegerFromCursor(cursor, AppUsageEventEntity.KEY_INSTANCE_ID));
eventBuilder.setTaskRootPackageName(
getStringFromCursor(cursor, AppUsageEventEntity.KEY_TASK_ROOT_PACKAGE_NAME));
eventBuilder.setUserId(getLongFromCursor(cursor, AppUsageEventEntity.KEY_USER_ID));
eventBuilder.setUid(getLongFromCursor(cursor, AppUsageEventEntity.KEY_UID));
return eventBuilder.build();
}
/** Converts from {@link BatteryEventType} to {@link BatteryEvent} */
public static BatteryEvent convertToBatteryEvent(
long timestamp, BatteryEventType type, int batteryLevel) {
final BatteryEvent.Builder eventBuilder = BatteryEvent.newBuilder();
eventBuilder.setTimestamp(timestamp);
eventBuilder.setType(type);
eventBuilder.setBatteryLevel(batteryLevel);
return eventBuilder.build();
}
/** Converts from {@link Cursor} to {@link BatteryEvent} */
public static BatteryEvent convertToBatteryEvent(final Cursor cursor) {
final BatteryEvent.Builder eventBuilder = BatteryEvent.newBuilder();
eventBuilder.setTimestamp(getLongFromCursor(cursor, BatteryEventEntity.KEY_TIMESTAMP));
eventBuilder.setType(
BatteryEventType.forNumber(
getIntegerFromCursor(cursor, BatteryEventEntity.KEY_BATTERY_EVENT_TYPE)));
eventBuilder.setBatteryLevel(
getIntegerFromCursor(cursor, BatteryEventEntity.KEY_BATTERY_LEVEL));
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();
final int dailyDataSize = levelDataList.size();
for (int dailyIndex = 0; dailyIndex < dailyDataSize; dailyIndex++) {
final BatteryLevelData.PeriodBatteryLevelData oneDayData =
levelDataList.get(dailyIndex);
final int hourDataSize = oneDayData.getLevels().size();
for (int hourIndex = 0; hourIndex < hourDataSize; hourIndex++) {
// For timestamp data on adjacent days, the last data (24:00) of the previous day is
// equal to the first data (00:00) of the next day, so skip sending EVEN_HOUR event.
if (dailyIndex < dailyDataSize - 1 && hourIndex == hourDataSize - 1) {
continue;
}
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 Context context,
final Map<Long, BatteryDiffData> batteryDiffDataMap,
final boolean isAppOptimizationModeLogged) {
List<BatteryUsageSlot> batteryUsageSlotList = new ArrayList<>();
final BatteryOptimizationModeCache optimizationModeCache =
isAppOptimizationModeLogged ? new BatteryOptimizationModeCache(context) : null;
for (BatteryDiffData batteryDiffData : batteryDiffDataMap.values()) {
batteryUsageSlotList.add(
convertToBatteryUsageSlot(batteryDiffData, optimizationModeCache));
}
return batteryUsageSlotList;
}
/**
* Converts UTC timestamp to local time string for logging only, so use the US locale for better
* readability in debugging.
*/
public static String utcToLocalTimeForLogging(long timestamp) {
final Locale locale = Locale.US;
final String pattern = DateFormat.getBestDateTimePattern(locale, "MMM dd,yyyy HH:mm:ss");
return DateFormat.format(pattern, timestamp).toString();
}
/** Converts UTC timestamp to local time hour data. */
public static String utcToLocalTimeHour(
final Context context,
final long timestamp,
final boolean is24HourFormat,
final boolean showMinute) {
final Locale locale = getLocale(context);
// e.g. for 12-hour format: 9 PM
// e.g. for 24-hour format: 09:00
final String skeleton = is24HourFormat ? "HHm" : (showMinute ? "hma" : "ha");
final String pattern = DateFormat.getBestDateTimePattern(locale, skeleton);
return DateFormat.format(pattern, timestamp).toString();
}
/** Converts UTC timestamp to local time day of week data. */
public static String utcToLocalTimeDayOfWeek(
final Context context, final long timestamp, final boolean isAbbreviation) {
final Locale locale = getLocale(context);
final String pattern =
DateFormat.getBestDateTimePattern(locale, isAbbreviation ? "E" : "EEEE");
return DateFormat.format(pattern, timestamp).toString();
}
@VisibleForTesting
static Locale getLocale(Context context) {
if (context == null) {
return Locale.getDefault();
}
final LocaleList locales = context.getResources().getConfiguration().getLocales();
return locales != null && !locales.isEmpty() ? locales.get(0) : Locale.getDefault();
}
/**
* Returns the package name the app usage should be attributed to.
*
* <ul>
* <li>If {@link UsageStatsManager#getUsageSource()} returns {@link
* UsageStatsManager#USAGE_SOURCE_CURRENT_ACTIVITY}, this method will return packageName.
* <li>If {@link UsageStatsManager#getUsageSource()} returns {@link
* UsageStatsManager#USAGE_SOURCE_TASK_ROOT_ACTIVITY}, this method will return
* taskRootPackageName if it exists, or packageName otherwise.
* </ul>
*/
@VisibleForTesting
static String getEffectivePackageName(
Context context,
IUsageStatsManager usageStatsManager,
final String packageName,
final String taskRootPackageName) {
final int usageSource = getUsageSource(context, usageStatsManager);
switch (usageSource) {
case UsageStatsManager.USAGE_SOURCE_TASK_ROOT_ACTIVITY:
return !TextUtils.isEmpty(taskRootPackageName) ? taskRootPackageName : packageName;
case UsageStatsManager.USAGE_SOURCE_CURRENT_ACTIVITY:
return packageName;
default:
Log.e(TAG, "Unexpected usage source: " + usageSource);
return packageName;
}
}
/**
* Returns the package name of the task root when this event was reported when {@code event} is
* one of:
*
* <ul>
* <li>{@link Event#ACTIVITY_RESUMED}
* <li>{@link Event#ACTIVITY_STOPPED}
* </ul>
*/
@Nullable
private static String getTaskRootPackageName(Event event) {
int eventType = event.getEventType();
if (eventType != Event.ACTIVITY_RESUMED && eventType != Event.ACTIVITY_STOPPED) {
// Task root is only relevant for ACTIVITY_* events.
return null;
}
try {
String taskRootPackageName = event.getTaskRootPackageName();
if (taskRootPackageName == null) {
Log.w(
TAG,
String.format(
"Null task root in event with timestamp %d, type=%d, package %s",
event.getTimeStamp(),
event.getEventType(),
event.getPackageName()));
}
return taskRootPackageName;
} catch (NoSuchMethodError e) {
Log.w(TAG, "Failed to call Event#getTaskRootPackageName()");
return null;
}
}
private static int getUsageSource(Context context, IUsageStatsManager usageStatsManager) {
if (sUsageSource == EMPTY_USAGE_SOURCE) {
sUsageSource = DatabaseUtils.getUsageSource(context, usageStatsManager);
}
return sUsageSource;
}
private static AppUsageEventType getAppUsageEventType(final int eventType) {
switch (eventType) {
case Event.ACTIVITY_RESUMED:
return AppUsageEventType.ACTIVITY_RESUMED;
case Event.ACTIVITY_STOPPED:
return AppUsageEventType.ACTIVITY_STOPPED;
case Event.DEVICE_SHUTDOWN:
return AppUsageEventType.DEVICE_SHUTDOWN;
default:
return AppUsageEventType.UNKNOWN;
}
}
@VisibleForTesting
static BatteryUsageDiff convertToBatteryUsageDiff(
final BatteryDiffEntry batteryDiffEntry,
final @Nullable BatteryOptimizationModeCache optimizationModeCache) {
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)
.setForegroundServiceUsageConsumePower(
batteryDiffEntry.mForegroundServiceUsageConsumePower)
.setCachedUsageConsumePower(batteryDiffEntry.mCachedUsageConsumePower)
.setForegroundUsageTime(batteryDiffEntry.mForegroundUsageTimeInMs)
.setForegroundServiceUsageTime(
batteryDiffEntry.mForegroundServiceUsageTimeInMs)
.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);
}
// Log the battery optimization mode of AppEntry while converting to batteryUsageSlot.
if (optimizationModeCache != null && !batteryDiffEntry.isSystemEntry()) {
final Pair<BatteryOptimizationMode, Boolean> batteryOptimizationModeInfo =
optimizationModeCache.getBatteryOptimizeModeInfo(
(int) batteryDiffEntry.mUid, batteryDiffEntry.getPackageName());
builder.setAppOptimizationMode(batteryOptimizationModeInfo.first)
.setIsAppOptimizationModeMutable(batteryOptimizationModeInfo.second);
}
return builder.build();
}
private static BatteryUsageSlot convertToBatteryUsageSlot(
final BatteryDiffData batteryDiffData,
final @Nullable BatteryOptimizationModeCache optimizationModeCache) {
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, optimizationModeCache));
}
for (BatteryDiffEntry batteryDiffEntry : batteryDiffData.getSystemDiffEntryList()) {
builder.addSystemUsage(
convertToBatteryUsageDiff(batteryDiffEntry, /* optimizationModeCache= */ null));
}
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.getForegroundServiceUsageTime(),
batteryUsageDiff.getBackgroundUsageTime(),
batteryUsageDiff.getScreenOnTime(),
batteryUsageDiff.getConsumePower(),
batteryUsageDiff.getForegroundUsageConsumePower(),
batteryUsageDiff.getForegroundServiceUsageConsumePower(),
batteryUsageDiff.getBackgroundUsageConsumePower(),
batteryUsageDiff.getCachedUsageConsumePower());
}
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(
final BatteryEntry entry,
final BatteryUsageStats batteryUsageStats,
final int batteryLevel,
final int batteryStatus,
final int batteryHealth,
final long bootTimestamp) {
final DeviceBatteryState deviceBatteryState =
DeviceBatteryState.newBuilder()
.setBatteryLevel(batteryLevel)
.setBatteryStatus(batteryStatus)
.setBatteryHealth(batteryHealth)
.build();
final BatteryInformation.Builder batteryInformationBuilder =
BatteryInformation.newBuilder()
.setDeviceBatteryState(deviceBatteryState)
.setBootTimestamp(bootTimestamp)
.setZoneId(TimeZone.getDefault().getID());
if (entry != null && batteryUsageStats != null) {
batteryInformationBuilder
.setIsHidden(entry.isHidden())
.setAppLabel(entry.getLabel() != null ? entry.getLabel() : "")
.setTotalPower(batteryUsageStats.getConsumedPower())
.setConsumePower(entry.getConsumedPower())
.setForegroundUsageConsumePower(entry.getConsumedPowerInForeground())
.setForegroundServiceUsageConsumePower(
entry.getConsumedPowerInForegroundService())
.setBackgroundUsageConsumePower(entry.getConsumedPowerInBackground())
.setCachedUsageConsumePower(entry.getConsumedPowerInCached())
.setPercentOfTotal(entry.mPercent)
.setDrainType(entry.getPowerComponentId())
.setForegroundUsageTimeInMs(entry.getTimeInForegroundMs())
.setForegroundServiceUsageTimeInMs(entry.getTimeInForegroundServiceMs())
.setBackgroundUsageTimeInMs(entry.getTimeInBackgroundMs());
}
return batteryInformationBuilder.build();
}
private static int getIntegerFromCursor(final Cursor cursor, final String key) {
final int columnIndex = cursor.getColumnIndex(key);
if (columnIndex >= 0) {
return cursor.getInt(columnIndex);
}
return 0;
}
private static long getLongFromCursor(final Cursor cursor, final String key) {
final int columnIndex = cursor.getColumnIndex(key);
if (columnIndex >= 0) {
return cursor.getLong(columnIndex);
}
return 0L;
}
private static String getStringFromCursor(final Cursor cursor, final String key) {
final int columnIndex = cursor.getColumnIndex(key);
if (columnIndex >= 0) {
return cursor.getString(columnIndex);
}
return "";
}
}