Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 10d3e1e0 authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Enable i18n for battery tips card and fix b/297036263." into udc-qpr-dev-plus-aosp

parents 69ea8a2a ab00ac09
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -1415,12 +1415,12 @@
        <item>Reduce screen timeout to extend battery life</item>
    </string-array>

    <string-array name="power_anomaly_main_btn_strings">
    <string-array name="power_anomaly_main_btn_strings" translatable="false">
        <item>@string/battery_tips_card_action_button</item>
        <item>@string/battery_tips_card_action_button</item>
    </string-array>

    <string-array name="power_anomaly_dismiss_btn_strings">
    <string-array name="power_anomaly_dismiss_btn_strings" translatable="false">
        <item>@string/battery_tips_card_dismiss_button</item>
        <item>@string/battery_tips_card_dismiss_button</item>
    </string-array>
+5 −5
Original line number Diff line number Diff line
@@ -9657,14 +9657,14 @@
    <!-- Preference summary for battery usage list page[CHAR_LIMIT=50]-->
    <string name="app_battery_usage_summary">Set battery usage for apps</string>
    <!-- Label of action button in battery tips card [CHAR LIMIT=NONE] -->
    <string name="battery_tips_card_action_button" translatable="false">View Settings</string>
    <!-- Label of action button in battery tips card [CHAR LIMIT=50] -->
    <string name="battery_tips_card_action_button">View Settings</string>
    <!-- Label of dismiss button in battery tips card [CHAR LIMIT=NONE] -->
    <string name="battery_tips_card_dismiss_button" translatable="false">Got it</string>
    <!-- Label of dismiss button in battery tips card [CHAR LIMIT=50] -->
    <string name="battery_tips_card_dismiss_button">Got it</string>
    <!-- Feedback card message in battery tips card [CHAR LIMIT=NONE] -->
    <string name="battery_tips_card_feedback_info" translatable="false">Is this message helpful?</string>
    <string name="battery_tips_card_feedback_info">Is this message helpful?</string>
    <!-- Filter title for battery unrestricted[CHAR_LIMIT=50]-->
    <string name="filter_battery_unrestricted_title">Unrestricted</string>
+59 −158
Original line number Diff line number Diff line
@@ -35,6 +35,7 @@ import android.os.Looper;
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.UserManager;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Log;

@@ -51,10 +52,10 @@ import java.time.Clock;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collectors;

@@ -66,6 +67,7 @@ public final class DatabaseUtils {
    /** Clear memory threshold for device booting phase. **/
    private static final long CLEAR_MEMORY_THRESHOLD_MS = Duration.ofMinutes(5).toMillis();
    private static final long CLEAR_MEMORY_DELAYED_MS = Duration.ofSeconds(2).toMillis();
    private static final long INVALID_TIMESTAMP = 0L;

    static final int DATA_RETENTION_INTERVAL_DAY = 9;
    static final String KEY_LAST_LOAD_FULL_CHARGE_TIME = "last_load_full_charge_time";
@@ -158,8 +160,8 @@ public final class DatabaseUtils {
                        .appendQueryParameter(
                                QUERY_KEY_USERID, Long.toString(userId))
                        .build();
        final long latestTimestamp =
                loadAppUsageLatestTimestampFromContentProvider(context, appUsageLatestTimestampUri);
        final long latestTimestamp = loadLongFromContentProvider(
                context, appUsageLatestTimestampUri, /*defaultValue=*/ INVALID_TIMESTAMP);
        final String latestTimestampString = utcToLocalTimeForLogging(latestTimestamp);
        Log.d(TAG, String.format(
                "getAppUsageStartTimestampOfUser() userId=%d latestTimestamp=%s in %d/ms",
@@ -196,8 +198,8 @@ public final class DatabaseUtils {
                        .appendQueryParameter(QUERY_KEY_USERID, queryUserIdString)
                        .build();

        final List<AppUsageEvent> appUsageEventList =
                loadAppUsageEventsFromContentProvider(context, appUsageEventUri);
        final List<AppUsageEvent> appUsageEventList = loadListFromContentProvider(
                context, appUsageEventUri, ConvertUtils::convertToAppUsageEvent);
        Log.d(TAG, String.format("getAppUsageEventForUser userId=%s size=%d in %d/ms",
                queryUserIdString, appUsageEventList.size(),
                (System.currentTimeMillis() - startTime)));
@@ -229,8 +231,8 @@ public final class DatabaseUtils {
                                QUERY_BATTERY_EVENT_TYPE, queryBatteryEventTypesString)
                        .build();

        final List<BatteryEvent> batteryEventList =
                loadBatteryEventsFromContentProvider(context, batteryEventUri);
        final List<BatteryEvent> batteryEventList = loadListFromContentProvider(
                context, batteryEventUri, ConvertUtils::convertToBatteryEvent);
        Log.d(TAG, String.format("getBatteryEvents size=%d in %d/ms", batteryEventList.size(),
                (System.currentTimeMillis() - startTime)));
        return batteryEventList;
@@ -257,8 +259,8 @@ public final class DatabaseUtils {
                                QUERY_KEY_TIMESTAMP, Long.toString(queryTimestamp))
                        .build();

        final List<BatteryUsageSlot> batteryUsageSlotList =
                loadBatteryUsageSlotsFromContentProvider(context, batteryUsageSlotUri);
        final List<BatteryUsageSlot> batteryUsageSlotList = loadListFromContentProvider(
                context, batteryUsageSlotUri, ConvertUtils::convertToBatteryUsageSlot);
        Log.d(TAG, String.format("getBatteryUsageSlots size=%d in %d/ms",
                batteryUsageSlotList.size(), (System.currentTimeMillis() - startTime)));
        return batteryUsageSlotList;
@@ -274,8 +276,8 @@ public final class DatabaseUtils {
                        .authority(AUTHORITY)
                        .appendPath(LAST_FULL_CHARGE_TIMESTAMP_PATH)
                        .build();
        final long lastFullChargeTime = loadLastFullChargeTimeFromContentProvider(
                context, lastFullChargeTimeUri);
        final long lastFullChargeTime = loadLongFromContentProvider(
                context, lastFullChargeTimeUri, /*defaultValue=*/ INVALID_TIMESTAMP);
        final String lastFullChargeTimeString = utcToLocalTimeForLogging(lastFullChargeTime);
        Log.d(TAG, String.format(
                "getLastFullChargeTime() lastFullChargeTime=%s in %d/ms",
@@ -297,8 +299,8 @@ public final class DatabaseUtils {
                        .appendQueryParameter(
                                QUERY_KEY_TIMESTAMP, Long.toString(queryTimestamp))
                        .build();
        final long batteryStateLatestTimestamp = loadBatteryStateLatestTimestampFromContentProvider(
                context, batteryStateLatestTimestampUri);
        final long batteryStateLatestTimestamp = loadLongFromContentProvider(
                context, batteryStateLatestTimestampUri, /*defaultValue=*/ INVALID_TIMESTAMP);
        final String batteryStateLatestTimestampString =
                utcToLocalTimeForLogging(batteryStateLatestTimestamp);
        Log.d(TAG, String.format(
@@ -322,8 +324,21 @@ public final class DatabaseUtils {
                                QUERY_KEY_TIMESTAMP, Long.toString(queryTimestamp))
                        .build();

        final Map<Long, Map<String, BatteryHistEntry>> resultMap =
                loadHistoryMapFromContentProvider(context, batteryStateUri);
        final List<BatteryHistEntry> batteryHistEntryList = loadListFromContentProvider(
                context, batteryStateUri, cursor -> new BatteryHistEntry(cursor));
        final Map<Long, Map<String, BatteryHistEntry>> resultMap = new ArrayMap();
        for (final BatteryHistEntry entry : batteryHistEntryList) {
            final long timestamp = entry.mTimestamp;
            final String key = entry.getKey();
            Map batteryHistEntryMap = resultMap.get(timestamp);
            // Creates new one if there is no corresponding map.
            if (batteryHistEntryMap == null) {
                batteryHistEntryMap = new ArrayMap();
                resultMap.put(timestamp, batteryHistEntryMap);
            }
            batteryHistEntryMap.put(key, entry);
        }

        if (resultMap == null || resultMap.isEmpty()) {
            Log.d(TAG, "getBatteryHistoryMap() returns empty or null");
        } else {
@@ -713,160 +728,46 @@ public final class DatabaseUtils {
        }
    }

    private static void writeString(
            Context context, PrintWriter writer, String prefix, String key) {
        final SharedPreferences sharedPreferences = getSharedPreferences(context);
        if (sharedPreferences != null) {
            final String content = sharedPreferences.getString(key, "");
            writer.println(String.format("\t\t%s: %s", prefix, content));
        }
    }

    private static long loadAppUsageLatestTimestampFromContentProvider(
            Context context, final Uri appUsageLatestTimestampUri) {
        // 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(
                        appUsageLatestTimestampUri, null, null, null)) {
            if (cursor == null || cursor.getCount() == 0) {
                return INVALID_USER_ID;
            }
            cursor.moveToFirst();
            // There is only one column returned so use the index 0 directly.
            final long latestTimestamp = cursor.getLong(/*columnIndex=*/ 0);
            // If there is no data for this user, 0 will be returned from the database.
            return latestTimestamp == 0 ? INVALID_USER_ID : latestTimestamp;
        }
    }

    private static List<AppUsageEvent> loadAppUsageEventsFromContentProvider(
            Context context, Uri appUsageEventUri) {
        final List<AppUsageEvent> appUsageEventList = new ArrayList<>();
    @VisibleForTesting
    static <T> T loadFromContentProvider(
            Context context, Uri uri, T defaultValue, Function<Cursor, T> cursorReader) {
        // Transfer work profile to user profile. Please see b/297036263.
        context = getParentContext(context);
        if (context == null) {
            return appUsageEventList;
        }
        try (Cursor cursor = sFakeSupplier != null
                ? sFakeSupplier.get()
                : context.getContentResolver().query(appUsageEventUri, null, null, null)) {
            if (cursor == null || cursor.getCount() == 0) {
                return appUsageEventList;
            return defaultValue;
        }
            // Loads and converts all AppUsageEvent data from cursor.
            while (cursor.moveToNext()) {
                appUsageEventList.add(ConvertUtils.convertToAppUsageEvent(cursor));
        try (Cursor cursor = sFakeSupplier != null ? sFakeSupplier.get() :
                context.getContentResolver().query(uri, null, null, null)) {
            return (cursor == null || cursor.getCount() == 0)
                    ? defaultValue : cursorReader.apply(cursor);
        }
    }
        return appUsageEventList;
    }

    private static List<BatteryEvent> loadBatteryEventsFromContentProvider(
            Context context, Uri batteryEventUri) {
        final List<BatteryEvent> batteryEventList = new ArrayList<>();
        context = getParentContext(context);
        if (context == null) {
            return batteryEventList;
        }
        try (Cursor cursor = sFakeSupplier != null
                ? sFakeSupplier.get()
                : context.getContentResolver().query(batteryEventUri, null, null, null)) {
            if (cursor == null || cursor.getCount() == 0) {
                return batteryEventList;
            }
            // Loads and converts all AppUsageEvent data from cursor.
            while (cursor.moveToNext()) {
                batteryEventList.add(ConvertUtils.convertToBatteryEvent(cursor));
            }
        }
        return batteryEventList;
    private static long loadLongFromContentProvider(
            Context context, Uri uri, final long defaultValue) {
        return loadFromContentProvider(context, uri, defaultValue,
                cursor -> cursor.moveToFirst() ? cursor.getLong(/*columnIndex=*/ 0) : defaultValue);
    }

    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.
    private static <E> List<E> loadListFromContentProvider(
            Context context, Uri uri, Function<Cursor, E> converter) {
        return loadFromContentProvider(context, uri, new ArrayList<>(),
                cursor -> {
                    final List<E> list = new ArrayList<>();
                    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;
                        list.add(converter.apply(cursor));
                    }
                    return list;
                });
    }

    private static Map<Long, Map<String, BatteryHistEntry>> loadHistoryMapFromContentProvider(
            Context context, Uri batteryStateUri) {
        context = getParentContext(context);
        if (context == null) {
            return null;
        }
        final Map<Long, Map<String, BatteryHistEntry>> resultMap = new HashMap();
        try (Cursor cursor = sFakeSupplier != null ? sFakeSupplier.get() :
                     context.getContentResolver().query(batteryStateUri, null, null, null)) {
            if (cursor == null || cursor.getCount() == 0) {
                return resultMap;
            }
            // Loads and converts all BatteryHistEntry data from cursor.
            while (cursor.moveToNext()) {
                final BatteryHistEntry entry = new BatteryHistEntry(cursor);
                final long timestamp = entry.mTimestamp;
                final String key = entry.getKey();
                Map batteryHistEntryMap = resultMap.get(timestamp);
                // Creates new one if there is no corresponding map.
                if (batteryHistEntryMap == null) {
                    batteryHistEntryMap = new HashMap<>();
                    resultMap.put(timestamp, batteryHistEntryMap);
                }
                batteryHistEntryMap.put(key, entry);
            }
    private static void writeString(
            Context context, PrintWriter writer, String prefix, String key) {
        final SharedPreferences sharedPreferences = getSharedPreferences(context);
        if (sharedPreferences != null) {
            final String content = sharedPreferences.getString(key, "");
            writer.println(String.format("\t\t%s: %s", prefix, content));
        }
        return resultMap;
    }

    private static void clearMemory() {
+16 −0
Original line number Diff line number Diff line
@@ -22,6 +22,8 @@ import static android.app.usage.UsageStatsManager.USAGE_SOURCE_TASK_ROOT_ACTIVIT
import static com.google.common.truth.Truth.assertThat;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
@@ -36,6 +38,7 @@ import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.database.MatrixCursor;
import android.net.Uri;
import android.os.BatteryManager;
import android.os.BatteryUsageStats;
import android.os.RemoteException;
@@ -530,6 +533,19 @@ public final class DatabaseUtilsTest {
        assertThat(dumpContent.contains("LastUploadFullChargeTime")).isTrue();
    }

    @Test
    public void loadFromContentProvider_workProfile_transferToUserProfile() throws Exception {
        // Test to verify b/297036263
        doReturn(mUserManager).when(mContext).getSystemService(UserManager.class);
        doReturn(true).when(mUserManager).isManagedProfile();
        doReturn(UserHandle.CURRENT).when(mContext).getUser();
        doReturn(UserHandle.SYSTEM).when(mUserManager).getProfileParent(UserHandle.CURRENT);

        DatabaseUtils.loadFromContentProvider(mContext, Uri.EMPTY, null, cursor -> 1);

        verify(mContext).createPackageContextAsUser(anyString(), anyInt(), any());
    }

    private static void verifyBatteryEntryContentValues(
            double consumedPower, ContentValues values) {
        final BatteryInformation batteryInformation =