mAppUsageEventList = new ArrayList<>();
/**
* The indexed {@link AppUsagePeriod} list data for each corresponding time slot.
* {@code Long} stands for the userId.
@@ -146,6 +148,8 @@ public class DataProcessManager {
loadDatabaseAppUsageList();
// Loads the latest app usage list from the service.
loadCurrentAppUsageList();
+ // Loads the battery event list from database.
+ loadBatteryEventList();
} else {
// If there is no battery level data, only load the battery history data from service
// and show it as the app list directly.
@@ -174,6 +178,11 @@ public class DataProcessManager {
return mIsDatabaseAppUsageLoaded;
}
+ @VisibleForTesting
+ boolean getIsBatteryEventLoaded() {
+ return mIsBatteryEventLoaded;
+ }
+
@VisibleForTesting
boolean getIsCurrentBatteryHistoryLoaded() {
return mIsCurrentBatteryHistoryLoaded;
@@ -290,7 +299,7 @@ public class DataProcessManager {
return null;
}
final long startTime = System.currentTimeMillis();
- // Loads the current battery usage data from the battery stats service.
+ // Loads the app usage data from the database.
final List appUsageEventList =
DatabaseUtils.getAppUsageEventForUsers(
mContext, Calendar.getInstance(), getCurrentUserIds(),
@@ -314,6 +323,35 @@ public class DataProcessManager {
}.execute();
}
+ private void loadBatteryEventList() {
+ new AsyncTask>() {
+ @Override
+ protected List doInBackground(Void... voids) {
+ final long startTime = System.currentTimeMillis();
+ // Loads the battery event data from the database.
+ final List batteryEventList =
+ DatabaseUtils.getBatteryEvents(
+ mContext, Calendar.getInstance(), mRawStartTimestamp);
+ Log.d(TAG, String.format("execute loadBatteryEventList size=%d in %d/ms",
+ batteryEventList.size(), (System.currentTimeMillis() - startTime)));
+ return batteryEventList;
+ }
+
+ @Override
+ protected void onPostExecute(
+ final List batteryEventList) {
+ if (batteryEventList == null || batteryEventList.isEmpty()) {
+ Log.d(TAG, "batteryEventList is null or empty");
+ } else {
+ mBatteryEventList.clear();
+ mBatteryEventList.addAll(batteryEventList);
+ }
+ mIsBatteryEventLoaded = true;
+ tryToProcessAppUsageData();
+ }
+ }.execute();
+ }
+
private void loadAndApplyBatteryMapFromServiceOnly() {
new AsyncTask() {
@Override
@@ -344,9 +382,8 @@ public class DataProcessManager {
}
private void tryToProcessAppUsageData() {
- // Only when all app usage events has been loaded, start processing app usage data to an
- // intermediate result for further use.
- if (!mIsCurrentAppUsageLoaded || !mIsDatabaseAppUsageLoaded) {
+ // Ignore processing the data if any required data is not loaded.
+ if (!mIsCurrentAppUsageLoaded || !mIsDatabaseAppUsageLoaded || !mIsBatteryEventLoaded) {
return;
}
processAppUsageData();
@@ -360,16 +397,16 @@ public class DataProcessManager {
}
// Generates the indexed AppUsagePeriod list data for each corresponding time slot for
// further use.
- mAppUsagePeriodMap = DataProcessor.generateAppUsagePeriodMap(
- mRawStartTimestamp, mHourlyBatteryLevelsPerDay, mAppUsageEventList);
+ mAppUsagePeriodMap = DataProcessor.generateAppUsagePeriodMap(mRawStartTimestamp,
+ mHourlyBatteryLevelsPerDay, mAppUsageEventList, mBatteryEventList);
}
private void tryToGenerateFinalDataAndApplyCallback() {
- // Only when both battery history data and app usage events data has been loaded, start the
- // final data processing.
+ // Ignore processing the data if any required data is not loaded.
if (!mIsCurrentBatteryHistoryLoaded
|| !mIsCurrentAppUsageLoaded
- || !mIsDatabaseAppUsageLoaded) {
+ || !mIsDatabaseAppUsageLoaded
+ || !mIsBatteryEventLoaded) {
return;
}
generateFinalDataAndApplyCallback();
diff --git a/src/com/android/settings/fuelgauge/batteryusage/DataProcessor.java b/src/com/android/settings/fuelgauge/batteryusage/DataProcessor.java
index 38d4e69c66e..6270eb3f8a1 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/DataProcessor.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/DataProcessor.java
@@ -94,6 +94,14 @@ public final class DataProcessor {
@VisibleForTesting
static final int SELECTED_INDEX_ALL = BatteryChartViewModel.SELECTED_INDEX_ALL;
+ @VisibleForTesting
+ static final Comparator APP_USAGE_EVENT_TIMESTAMP_COMPARATOR =
+ Comparator.comparing(AppUsageEvent::getTimestamp);
+
+ @VisibleForTesting
+ static final Comparator BATTERY_EVENT_TIMESTAMP_COMPARATOR =
+ Comparator.comparing(BatteryEvent::getTimestamp);
+
@VisibleForTesting
static boolean sDebug = false;
@@ -110,8 +118,6 @@ public final class DataProcessor {
public static final String CURRENT_TIME_BATTERY_HISTORY_PLACEHOLDER =
"CURRENT_TIME_BATTERY_HISTORY_PLACEHOLDER";
- public static final Comparator TIMESTAMP_COMPARATOR =
- Comparator.comparing(AppUsageEvent::getTimestamp);
/** A callback listener when battery usage loading async task is executed. */
public interface UsageMapAsyncResponse {
@@ -266,14 +272,16 @@ public final class DataProcessor {
generateAppUsagePeriodMap(
final long rawStartTimestamp,
final List hourlyBatteryLevelsPerDay,
- final List appUsageEventList) {
+ final List appUsageEventList,
+ final List batteryEventList) {
if (appUsageEventList.isEmpty()) {
Log.w(TAG, "appUsageEventList is empty");
return null;
}
- // Sorts the appUsageEventList in ascending order based on the timestamp before
- // distribution.
- Collections.sort(appUsageEventList, TIMESTAMP_COMPARATOR);
+ // Sorts the appUsageEventList and batteryEventList in ascending order based on the
+ // timestamp before distribution.
+ Collections.sort(appUsageEventList, APP_USAGE_EVENT_TIMESTAMP_COMPARATOR);
+ Collections.sort(batteryEventList, BATTERY_EVENT_TIMESTAMP_COMPARATOR);
final Map>>>> resultMap =
new ArrayMap<>();
@@ -309,8 +317,8 @@ public final class DataProcessor {
// The value could be null when there is no data in the hourly slot.
dailyMap.put(
hourlyIndex,
- buildAppUsagePeriodList(
- hourlyAppUsageEventList, startTimestamp, endTimestamp));
+ buildAppUsagePeriodList(hourlyAppUsageEventList, batteryEventList,
+ startTimestamp, endTimestamp));
}
}
return resultMap;
@@ -717,7 +725,8 @@ public final class DataProcessor {
@VisibleForTesting
@Nullable
static Map>> buildAppUsagePeriodList(
- final List allAppUsageEvents, final long startTime, final long endTime) {
+ final List allAppUsageEvents, final List batteryEventList,
+ final long startTime, final long endTime) {
if (allAppUsageEvents.isEmpty()) {
return null;
}
@@ -763,12 +772,14 @@ public final class DataProcessor {
usageEvents.addAll(deviceEvents);
// Sorts the usageEvents in ascending order based on the timestamp before computing the
// period.
- Collections.sort(usageEvents, TIMESTAMP_COMPARATOR);
+ Collections.sort(usageEvents, APP_USAGE_EVENT_TIMESTAMP_COMPARATOR);
// A package might have multiple instances. Computes the usage period per instance id
// and then merges them into the same user-package map.
final List usagePeriodList =
- buildAppUsagePeriodListPerInstance(usageEvents, startTime, endTime);
+ excludePowerConnectedTimeFromAppUsagePeriodList(
+ buildAppUsagePeriodListPerInstance(usageEvents, startTime, endTime),
+ batteryEventList);
if (!usagePeriodList.isEmpty()) {
addToUsagePeriodMap(allUsagePeriods, usagePeriodList, eventUserId, packageName);
}
@@ -836,6 +847,53 @@ public final class DataProcessor {
return usagePeriodList;
}
+ @VisibleForTesting
+ static List excludePowerConnectedTimeFromAppUsagePeriodList(
+ final List usagePeriodList,
+ final List batteryEventList) {
+ final List resultList = new ArrayList<>();
+ for (AppUsagePeriod inputPeriod : usagePeriodList) {
+ long lastStartTime = inputPeriod.getStartTime();
+ for (BatteryEvent batteryEvent : batteryEventList) {
+ if (batteryEvent.getTimestamp() < inputPeriod.getStartTime()) {
+ // Because the batteryEventList has been sorted, here is to mark the power
+ // connection state when the usage period starts. If power is connected when
+ // the usage period starts, the starting period will be ignored; otherwise it
+ // will be added.
+ if (batteryEvent.getType() == BatteryEventType.POWER_CONNECTED) {
+ lastStartTime = 0;
+ } else if (batteryEvent.getType() == BatteryEventType.POWER_DISCONNECTED) {
+ lastStartTime = inputPeriod.getStartTime();
+ }
+ continue;
+ }
+ if (batteryEvent.getTimestamp() > inputPeriod.getEndTime()) {
+ // Because the batteryEventList has been sorted, if any event is already after
+ // the end time, all the following events should be able to drop directly.
+ break;
+ }
+
+ if (batteryEvent.getType() == BatteryEventType.POWER_CONNECTED
+ && lastStartTime != 0) {
+ resultList.add(AppUsagePeriod.newBuilder()
+ .setStartTime(lastStartTime)
+ .setEndTime(batteryEvent.getTimestamp())
+ .build());
+ lastStartTime = 0;
+ } else if (batteryEvent.getType() == BatteryEventType.POWER_DISCONNECTED) {
+ lastStartTime = batteryEvent.getTimestamp();
+ }
+ }
+ if (lastStartTime != 0) {
+ resultList.add(AppUsagePeriod.newBuilder()
+ .setStartTime(lastStartTime)
+ .setEndTime(inputPeriod.getEndTime())
+ .build());
+ }
+ }
+ return resultList;
+ }
+
@VisibleForTesting
static long getScreenOnTime(
final Map>> appUsageMap,
diff --git a/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtils.java b/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtils.java
index ef1434cb4a0..84a39bb811f 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtils.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtils.java
@@ -64,10 +64,12 @@ public final class DatabaseUtils {
/** An authority name of the battery content provider. */
public static final String AUTHORITY = "com.android.settings.battery.usage.provider";
- /** A table name for battery usage history. */
- public static final String BATTERY_STATE_TABLE = "BatteryState";
/** A table name for app usage events. */
public static final String APP_USAGE_EVENT_TABLE = "AppUsageEvent";
+ /** A table name for battery events. */
+ public static final String BATTERY_EVENT_TABLE = "BatteryEvent";
+ /** A table name for battery usage history. */
+ public static final String BATTERY_STATE_TABLE = "BatteryState";
/** A path name for app usage latest timestamp query. */
public static final String APP_USAGE_LATEST_TIMESTAMP_PATH = "appUsageLatestTimestamp";
/** A class name for battery usage data provider. */
@@ -84,13 +86,6 @@ public final class DatabaseUtils {
*/
public static final long USAGE_QUERY_BUFFER_HOURS = Duration.ofHours(3).toMillis();
- /** A content URI to access battery usage states data. */
- public static final Uri BATTERY_CONTENT_URI =
- new Uri.Builder()
- .scheme(ContentResolver.SCHEME_CONTENT)
- .authority(AUTHORITY)
- .appendPath(BATTERY_STATE_TABLE)
- .build();
/** A content URI to access app usage events data. */
public static final Uri APP_USAGE_EVENT_URI =
new Uri.Builder()
@@ -98,6 +93,20 @@ public final class DatabaseUtils {
.authority(AUTHORITY)
.appendPath(APP_USAGE_EVENT_TABLE)
.build();
+ /** A content URI to access battery events data. */
+ public static final Uri BATTERY_EVENT_URI =
+ new Uri.Builder()
+ .scheme(ContentResolver.SCHEME_CONTENT)
+ .authority(AUTHORITY)
+ .appendPath(BATTERY_EVENT_TABLE)
+ .build();
+ /** A content URI to access battery usage states data. */
+ public static final Uri BATTERY_CONTENT_URI =
+ new Uri.Builder()
+ .scheme(ContentResolver.SCHEME_CONTENT)
+ .authority(AUTHORITY)
+ .appendPath(BATTERY_STATE_TABLE)
+ .build();
// For testing only.
@VisibleForTesting
@@ -106,6 +115,8 @@ public final class DatabaseUtils {
static Supplier sFakeAppUsageEventSupplier;
@VisibleForTesting
static Supplier sFakeAppUsageLatestTimestampSupplier;
+ @VisibleForTesting
+ static Supplier sFakeBatteryEventSupplier;
private DatabaseUtils() {
}
@@ -176,6 +187,32 @@ public final class DatabaseUtils {
return appUsageEventList;
}
+ /** Returns the battery event data since the query timestamp in battery event table. */
+ public static List getBatteryEvents(
+ Context context,
+ final Calendar calendar,
+ final long rawStartTimestamp) {
+ final long startTime = System.currentTimeMillis();
+ final long sixDaysAgoTimestamp = getTimestampSixDaysAgo(calendar);
+ final long queryTimestamp = Math.max(rawStartTimestamp, sixDaysAgoTimestamp);
+ Log.d(TAG, "getBatteryEvents for timestamp: " + queryTimestamp);
+ // Builds the content uri everytime to avoid cache.
+ final Uri batteryEventUri =
+ new Uri.Builder()
+ .scheme(ContentResolver.SCHEME_CONTENT)
+ .authority(AUTHORITY)
+ .appendPath(BATTERY_EVENT_TABLE)
+ .appendQueryParameter(
+ QUERY_KEY_TIMESTAMP, Long.toString(queryTimestamp))
+ .build();
+
+ final List batteryEventList =
+ loadBatteryEventsFromContentProvider(context, batteryEventUri);
+ Log.d(TAG, String.format("getBatteryEvents size=%d in %d/ms", batteryEventList.size(),
+ (System.currentTimeMillis() - startTime)));
+ return batteryEventList;
+ }
+
/** Long: for timestamp and String: for BatteryHistEntry.getKey() */
public static Map> getHistoryMapSinceLastFullCharge(
Context context, Calendar calendar) {
@@ -210,8 +247,9 @@ public final class DatabaseUtils {
try {
final BatteryStateDatabase database = BatteryStateDatabase
.getInstance(context.getApplicationContext());
- database.batteryStateDao().clearAll();
database.appUsageEventDao().clearAll();
+ database.batteryEventDao().clearAll();
+ database.batteryStateDao().clearAll();
} catch (RuntimeException e) {
Log.e(TAG, "clearAll() failed", e);
}
@@ -226,8 +264,9 @@ public final class DatabaseUtils {
.getInstance(context.getApplicationContext());
final long earliestTimestamp = Clock.systemUTC().millis()
- Duration.ofDays(DATA_RETENTION_INTERVAL_DAY).toMillis();
- database.batteryStateDao().clearAllBefore(earliestTimestamp);
database.appUsageEventDao().clearAllBefore(earliestTimestamp);
+ database.batteryEventDao().clearAllBefore(earliestTimestamp);
+ database.batteryStateDao().clearAllBefore(earliestTimestamp);
} catch (RuntimeException e) {
Log.e(TAG, "clearAllBefore() failed", e);
}
@@ -292,6 +331,23 @@ public final class DatabaseUtils {
return valuesList;
}
+ static ContentValues sendBatteryEventData(
+ final Context context, final BatteryEvent batteryEvent) {
+ final long startTime = System.currentTimeMillis();
+ ContentValues contentValues = ConvertUtils.convertBatteryEventToContentValues(batteryEvent);
+ final ContentResolver resolver = context.getContentResolver();
+ try {
+ resolver.insert(BATTERY_EVENT_URI, contentValues);
+ Log.d(TAG, "insert() battery event data into database: " + batteryEvent.toString());
+ } catch (Exception e) {
+ Log.e(TAG, "insert() battery event data into database error:\n" + e);
+ }
+ Log.d(TAG, String.format("sendBatteryEventData() in %d/ms",
+ (System.currentTimeMillis() - startTime)));
+ clearMemory();
+ return contentValues;
+ }
+
static List sendBatteryEntryData(
final Context context,
final List batteryEntryList,
@@ -392,6 +448,8 @@ public final class DatabaseUtils {
public static void dump(Context context, PrintWriter writer) {
writeString(context, writer, "BatteryLevelChanged",
Intent.ACTION_BATTERY_LEVEL_CHANGED);
+ writeString(context, writer, "BatteryPlugging",
+ BatteryUsageBroadcastReceiver.ACTION_BATTERY_PLUGGING);
writeString(context, writer, "BatteryUnplugging",
BatteryUsageBroadcastReceiver.ACTION_BATTERY_UNPLUGGING);
writeString(context, writer, "ClearBatteryCacheData",
@@ -475,6 +533,32 @@ public final class DatabaseUtils {
return appUsageEventList;
}
+ private static List loadBatteryEventsFromContentProvider(
+ Context context, Uri batteryEventUri) {
+ final List batteryEventList = new ArrayList<>();
+ context = getParentContext(context);
+ if (context == null) {
+ return batteryEventList;
+ }
+ try (Cursor cursor = sFakeBatteryEventSupplier != null
+ ? sFakeBatteryEventSupplier.get()
+ : context.getContentResolver().query(batteryEventUri, null, null, null)) {
+ if (cursor == null || cursor.getCount() == 0) {
+ return batteryEventList;
+ }
+ // Loads and recovers all AppUsageEvent data from cursor.
+ while (cursor.moveToNext()) {
+ batteryEventList.add(ConvertUtils.convertToBatteryEventFromCursor(cursor));
+ }
+ try {
+ cursor.close();
+ } catch (Exception e) {
+ Log.e(TAG, "cursor.close() failed", e);
+ }
+ }
+ return batteryEventList;
+ }
+
private static Map> loadHistoryMapFromContentProvider(
Context context, Uri batteryStateUri) {
context = DatabaseUtils.getParentContext(context);
diff --git a/src/com/android/settings/fuelgauge/batteryusage/db/BatteryEventDao.java b/src/com/android/settings/fuelgauge/batteryusage/db/BatteryEventDao.java
new file mode 100644
index 00000000000..a638d094519
--- /dev/null
+++ b/src/com/android/settings/fuelgauge/batteryusage/db/BatteryEventDao.java
@@ -0,0 +1,50 @@
+/*
+ * 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 BatteryEventEntity} in the database. */
+@Dao
+public interface BatteryEventDao {
+ /** Inserts a {@link BatteryEventEntity} data into the database. */
+ @Insert(onConflict = OnConflictStrategy.REPLACE)
+ void insert(BatteryEventEntity event);
+
+ /** Gets all recorded data. */
+ @Query("SELECT * FROM BatteryEventEntity ORDER BY timestamp DESC")
+ List getAll();
+
+ /** Gets the {@link Cursor} of all recorded data after a specific timestamp. */
+ @Query("SELECT * FROM BatteryEventEntity WHERE timestamp > :timestamp ORDER BY timestamp DESC")
+ Cursor getAllAfter(long timestamp);
+
+ /** Deletes all recorded data before a specific timestamp. */
+ @Query("DELETE FROM BatteryEventEntity WHERE timestamp <= :timestamp")
+ void clearAllBefore(long timestamp);
+
+ /** Clears all recorded data in the database. */
+ @Query("DELETE FROM BatteryEventEntity")
+ void clearAll();
+}
diff --git a/src/com/android/settings/fuelgauge/batteryusage/db/BatteryEventEntity.java b/src/com/android/settings/fuelgauge/batteryusage/db/BatteryEventEntity.java
new file mode 100644
index 00000000000..66cadda4530
--- /dev/null
+++ b/src/com/android/settings/fuelgauge/batteryusage/db/BatteryEventEntity.java
@@ -0,0 +1,133 @@
+/*
+ * 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 events into database. */
+@Entity
+public class BatteryEventEntity {
+ /** Keys for accessing {@link ContentValues}. */
+ public static final String KEY_TIMESTAMP = "timestamp";
+ public static final String KEY_BATTERY_EVENT_TYPE = "batteryEventType";
+ public static final String KEY_BATTERY_LEVEL = "batteryLevel";
+
+ @PrimaryKey(autoGenerate = true)
+ private long mId;
+
+ public final long timestamp;
+ public final int batteryEventType;
+ public final int batteryLevel;
+
+ public BatteryEventEntity(
+ final long timestamp,
+ final int batteryEventType,
+ final int batteryLevel) {
+ this.timestamp = timestamp;
+ this.batteryEventType = batteryEventType;
+ this.batteryLevel = batteryLevel;
+ }
+
+ /** 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("\nBatteryEvent{")
+ .append(String.format(Locale.US,
+ "\n\ttimestamp=%s|batteryEventType=%d|batteryLevel=%d",
+ recordAtDateTime, batteryEventType, batteryLevel))
+ .append("\n}");
+ return builder.toString();
+ }
+
+ /** Creates new {@link BatteryEventEntity} from {@link ContentValues}. */
+ public static BatteryEventEntity create(ContentValues contentValues) {
+ Builder builder = BatteryEventEntity.newBuilder();
+ if (contentValues.containsKey(KEY_TIMESTAMP)) {
+ builder.setTimestamp(contentValues.getAsLong(KEY_TIMESTAMP));
+ }
+ if (contentValues.containsKey(KEY_BATTERY_EVENT_TYPE)) {
+ builder.setBatteryEventType(contentValues.getAsInteger(KEY_BATTERY_EVENT_TYPE));
+ }
+ if (contentValues.containsKey(KEY_BATTERY_LEVEL)) {
+ builder.setBatteryLevel(contentValues.getAsInteger(KEY_BATTERY_LEVEL));
+ }
+ 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 int mBatteryEventType;
+ private int mBatteryLevel;
+
+ /** Sets the timestamp. */
+ @CanIgnoreReturnValue
+ public Builder setTimestamp(final long timestamp) {
+ mTimestamp = timestamp;
+ return this;
+ }
+
+ /** Sets the battery event type. */
+ @CanIgnoreReturnValue
+ public Builder setBatteryEventType(final int batteryEventType) {
+ mBatteryEventType = batteryEventType;
+ return this;
+ }
+
+ /** Sets the battery level. */
+ @CanIgnoreReturnValue
+ public Builder setBatteryLevel(final int batteryLevel) {
+ mBatteryLevel = batteryLevel;
+ return this;
+ }
+
+ /** Builds the {@link BatteryEventEntity}. */
+ public BatteryEventEntity build() {
+ return new BatteryEventEntity(
+ mTimestamp,
+ mBatteryEventType,
+ mBatteryLevel);
+ }
+
+ private Builder() {}
+ }
+}
diff --git a/src/com/android/settings/fuelgauge/batteryusage/db/BatteryStateDatabase.java b/src/com/android/settings/fuelgauge/batteryusage/db/BatteryStateDatabase.java
index 4c8df7e0ad5..466a7ca4740 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/db/BatteryStateDatabase.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/db/BatteryStateDatabase.java
@@ -25,24 +25,26 @@ import androidx.room.RoomDatabase;
/** A {@link RoomDatabase} for battery usage states history. */
@Database(
- entities = {BatteryState.class, AppUsageEventEntity.class},
+ entities = {AppUsageEventEntity.class, BatteryEventEntity.class, BatteryState.class},
version = 1)
public abstract class BatteryStateDatabase extends RoomDatabase {
private static final String TAG = "BatteryStateDatabase";
private static BatteryStateDatabase sBatteryStateDatabase;
- /** Provides DAO for battery state table. */
- public abstract BatteryStateDao batteryStateDao();
/** Provides DAO for app usage event table. */
public abstract AppUsageEventDao appUsageEventDao();
+ /** Provides DAO for battery event table. */
+ public abstract BatteryEventDao batteryEventDao();
+ /** Provides DAO for battery state table. */
+ public abstract BatteryStateDao batteryStateDao();
/** Gets or creates an instance of {@link RoomDatabase}. */
public static BatteryStateDatabase getInstance(Context context) {
if (sBatteryStateDatabase == null) {
sBatteryStateDatabase =
Room.databaseBuilder(
- context, BatteryStateDatabase.class, "battery-usage-db-v7")
+ context, BatteryStateDatabase.class, "battery-usage-db-v8")
// Allows accessing data in the main thread for dumping bugreport.
.allowMainThreadQueries()
.fallbackToDestructiveMigration()
diff --git a/src/com/android/settings/fuelgauge/protos/Android.bp b/src/com/android/settings/fuelgauge/protos/Android.bp
index 2c63af40a09..3af2aef0796 100644
--- a/src/com/android/settings/fuelgauge/protos/Android.bp
+++ b/src/com/android/settings/fuelgauge/protos/Android.bp
@@ -7,6 +7,22 @@ package {
default_applicable_licenses: ["packages_apps_Settings_license"],
}
+java_library {
+ name: "app-usage-event-protos-lite",
+ proto: {
+ type: "lite",
+ },
+ srcs: ["app_usage_event.proto"],
+}
+
+java_library {
+ name: "battery-event-protos-lite",
+ proto: {
+ type: "lite",
+ },
+ srcs: ["battery_event.proto"],
+}
+
java_library {
name: "fuelgauge-usage-state-protos-lite",
proto: {
@@ -14,11 +30,3 @@ java_library {
},
srcs: ["fuelgauge_usage_state.proto"],
}
-
-java_library {
- name: "app-usage-event-protos-lite",
- proto: {
- type: "lite",
- },
- srcs: ["app_usage_event.proto"],
-}
\ No newline at end of file
diff --git a/src/com/android/settings/fuelgauge/protos/battery_event.proto b/src/com/android/settings/fuelgauge/protos/battery_event.proto
new file mode 100644
index 00000000000..80ccb3b24f4
--- /dev/null
+++ b/src/com/android/settings/fuelgauge/protos/battery_event.proto
@@ -0,0 +1,17 @@
+syntax = "proto2";
+
+option java_multiple_files = true;
+option java_package = "com.android.settings.fuelgauge.batteryusage";
+option java_outer_classname = "BatteryEventProto";
+
+enum BatteryEventType {
+ UNKNOWN_EVENT = 0;
+ POWER_CONNECTED = 1;
+ POWER_DISCONNECTED = 2;
+}
+
+message BatteryEvent {
+ optional int64 timestamp = 1;
+ optional BatteryEventType type = 2;
+ optional int32 battery_level = 3;
+}
diff --git a/src/com/android/settings/inputmethod/NewKeyboardLayoutPickerController.java b/src/com/android/settings/inputmethod/NewKeyboardLayoutPickerController.java
index 893ad4cea01..8278be88d98 100644
--- a/src/com/android/settings/inputmethod/NewKeyboardLayoutPickerController.java
+++ b/src/com/android/settings/inputmethod/NewKeyboardLayoutPickerController.java
@@ -28,6 +28,7 @@ import androidx.preference.Preference;
import androidx.preference.PreferenceScreen;
import com.android.settings.core.BasePreferenceController;
+import com.android.settings.widget.TickButtonPreference;
import com.android.settingslib.core.lifecycle.LifecycleObserver;
import com.android.settingslib.core.lifecycle.events.OnStart;
import com.android.settingslib.core.lifecycle.events.OnStop;
@@ -38,7 +39,7 @@ import java.util.Map;
public class NewKeyboardLayoutPickerController extends BasePreferenceController implements
InputManager.InputDeviceListener, LifecycleObserver, OnStart, OnStop {
private final InputManager mIm;
- private final Map mPreferenceMap;
+ private final Map mPreferenceMap;
private Fragment mParent;
private int mInputDeviceId;
@@ -102,16 +103,15 @@ public class NewKeyboardLayoutPickerController extends BasePreferenceController
@Override
public boolean handlePreferenceTreeClick(Preference preference) {
-
- if (!(preference instanceof KeyboardLayoutPreference)) {
+ if (!(preference instanceof TickButtonPreference)) {
return false;
}
- final KeyboardLayoutPreference pref = (KeyboardLayoutPreference) preference;
- pref.setCheckMark(true);
+ final TickButtonPreference pref = (TickButtonPreference) preference;
+ pref.setSelected(true);
if (mPreviousSelection != null && !mPreviousSelection.equals(preference.getKey())) {
- KeyboardLayoutPreference preSelectedPref = mScreen.findPreference(mPreviousSelection);
- preSelectedPref.setCheckMark(false);
+ TickButtonPreference preSelectedPref = mScreen.findPreference(mPreviousSelection);
+ preSelectedPref.setSelected(false);
}
setLayout(pref);
mPreviousSelection = preference.getKey();
@@ -140,12 +140,13 @@ public class NewKeyboardLayoutPickerController extends BasePreferenceController
return;
}
for (KeyboardLayout layout : mKeyboardLayouts) {
- final KeyboardLayoutPreference pref;
+ final TickButtonPreference pref;
+ pref = new TickButtonPreference(mScreen.getContext());
+ pref.setTitle(layout.getLabel());
+
if (mLayout.equals(layout.getLabel())) {
- pref = new KeyboardLayoutPreference(mScreen.getContext(), layout.getLabel(), true);
+ pref.setSelected(true);
mPreviousSelection = layout.getDescriptor();
- } else {
- pref = new KeyboardLayoutPreference(mScreen.getContext(), layout.getLabel(), false);
}
pref.setKey(layout.getDescriptor());
mScreen.addPreference(pref);
@@ -153,7 +154,7 @@ public class NewKeyboardLayoutPickerController extends BasePreferenceController
}
}
- private void setLayout(KeyboardLayoutPreference preference) {
+ private void setLayout(TickButtonPreference preference) {
mIm.setKeyboardLayoutForInputDevice(
mInputDeviceIdentifier,
mUserId,
diff --git a/src/com/android/settings/regionalpreferences/NumberingSystemItemController.java b/src/com/android/settings/regionalpreferences/NumberingSystemItemController.java
index 8e2d735ce08..8b851b86eb0 100644
--- a/src/com/android/settings/regionalpreferences/NumberingSystemItemController.java
+++ b/src/com/android/settings/regionalpreferences/NumberingSystemItemController.java
@@ -34,6 +34,7 @@ import com.android.internal.app.LocaleStore;
import com.android.settings.core.BasePreferenceController;
import com.android.settings.core.SubSettingLauncher;
import com.android.settings.dashboard.DashboardFragment;
+import com.android.settings.widget.TickButtonPreference;
import java.util.Locale;
@@ -138,7 +139,7 @@ public class NumberingSystemItemController extends BasePreferenceController {
String key = supportedLocale.getUnicodeLocaleType(
ExtensionTypes.NUMBERING_SYSTEM);
pref.setKey(key == null ? RegionalPreferencesDataUtils.DEFAULT_VALUE : key);
- pref.setTickEnable(isSameNumberingSystem(targetLocale, supportedLocale));
+ pref.setSelected(isSameNumberingSystem(targetLocale, supportedLocale));
screen.addPreference(pref);
}
}
@@ -162,7 +163,7 @@ public class NumberingSystemItemController extends BasePreferenceController {
TickButtonPreference pref = (TickButtonPreference) mPreferenceScreen.getPreference(i);
Log.i(TAG, "[onPreferenceClick] key is " + pref.getKey());
if (pref.getKey().equals(preference.getKey())) {
- pref.setTickEnable(true);
+ pref.setSelected(true);
Locale updatedLocale =
saveNumberingSystemToLocale(
Locale.forLanguageTag(mSelectedLanguage), pref.getKey());
@@ -176,7 +177,7 @@ public class NumberingSystemItemController extends BasePreferenceController {
mParentFragment.setArguments(bundle);
continue;
}
- pref.setTickEnable(false);
+ pref.setSelected(false);
}
}
diff --git a/src/com/android/settings/regionalpreferences/RegionalPreferencesFragment.java b/src/com/android/settings/regionalpreferences/RegionalPreferencesFragment.java
index 03bc8ac5d57..ea9b7b39073 100644
--- a/src/com/android/settings/regionalpreferences/RegionalPreferencesFragment.java
+++ b/src/com/android/settings/regionalpreferences/RegionalPreferencesFragment.java
@@ -29,6 +29,7 @@ import androidx.preference.PreferenceScreen;
import com.android.settings.R;
import com.android.settings.SettingsPreferenceFragment;
+import com.android.settings.widget.TickButtonPreference;
/** A fragment to include each kind of regional preferences. */
public class RegionalPreferencesFragment extends SettingsPreferenceFragment {
@@ -63,7 +64,7 @@ public class RegionalPreferencesFragment extends SettingsPreferenceFragment {
TickButtonPreference pref = (TickButtonPreference) mPreferenceScreen.getPreference(i);
Log.i(TAG, "[onPreferenceClick] key is " + pref.getKey());
if (pref.getKey().equals(preference.getKey())) {
- pref.setTickEnable(true);
+ pref.setSelected(true);
RegionalPreferencesDataUtils.savePreference(
getPrefContext(),
mType,
@@ -72,7 +73,7 @@ public class RegionalPreferencesFragment extends SettingsPreferenceFragment {
? null : preference.getKey());
continue;
}
- pref.setTickEnable(false);
+ pref.setSelected(false);
}
return true;
}
@@ -115,7 +116,7 @@ public class RegionalPreferencesFragment extends SettingsPreferenceFragment {
String value = RegionalPreferencesDataUtils.getDefaultUnicodeExtensionData(
getPrefContext(), mType);
pref.setKey(item);
- pref.setTickEnable(!value.isEmpty() && item.equals(value));
+ pref.setSelected(!value.isEmpty() && item.equals(value));
mPreferenceScreen.addPreference(pref);
}
return super.onCreateView(inflater, container, savedInstanceState);
diff --git a/src/com/android/settings/regionalpreferences/TickButtonPreference.java b/src/com/android/settings/regionalpreferences/TickButtonPreference.java
deleted file mode 100644
index c01521f548d..00000000000
--- a/src/com/android/settings/regionalpreferences/TickButtonPreference.java
+++ /dev/null
@@ -1,69 +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.regionalpreferences;
-
-import android.content.Context;
-import android.view.View;
-
-import androidx.preference.PreferenceViewHolder;
-
-import com.android.settings.R;
-import com.android.settingslib.widget.TwoTargetPreference;
-
-/** A preference with tick button */
-public class TickButtonPreference extends TwoTargetPreference {
- private static final String TAG = TickButtonPreference.class.getSimpleName();
- private boolean mIsTickEnabled;
- private View mWidgetFrame;
- private View mDivider;
-
- public TickButtonPreference(Context context) {
- super(context, null);
- }
-
- /** Set this preference to be selected. */
- public void setTickEnable(boolean isEnable) {
- mIsTickEnabled = isEnable;
- if (mWidgetFrame != null) {
- mWidgetFrame.setVisibility(isEnable ? View.VISIBLE : View.INVISIBLE);
- }
- }
-
- /** Check if this preference is selected. */
- public boolean isTickEnabled() {
- return mIsTickEnabled;
- }
-
- @Override
- public void onBindViewHolder(PreferenceViewHolder holder) {
- super.onBindViewHolder(holder);
- mDivider = holder.findViewById(R.id.two_target_divider);
- mWidgetFrame = holder.findViewById(android.R.id.widget_frame);
- if (mDivider != null) {
- mDivider.setVisibility(View.GONE);
- }
- if (mWidgetFrame != null) {
- mWidgetFrame.setVisibility(mIsTickEnabled ? View.VISIBLE : View.INVISIBLE);
- }
- }
-
- @Override
- protected int getSecondTargetResId() {
- super.getSecondTargetResId();
- return R.layout.preference_widget_tick;
- }
-}
diff --git a/src/com/android/settings/inputmethod/KeyboardLayoutPreference.java b/src/com/android/settings/widget/TickButtonPreference.java
similarity index 61%
rename from src/com/android/settings/inputmethod/KeyboardLayoutPreference.java
rename to src/com/android/settings/widget/TickButtonPreference.java
index f9f858b6bc8..c55da2c1077 100644
--- a/src/com/android/settings/inputmethod/KeyboardLayoutPreference.java
+++ b/src/com/android/settings/widget/TickButtonPreference.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2022 The Android Open Source Project
+ * 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.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.settings.inputmethod;
+package com.android.settings.widget;
import android.content.Context;
import android.view.View;
@@ -25,29 +25,33 @@ import androidx.preference.PreferenceViewHolder;
import com.android.settings.R;
-public class KeyboardLayoutPreference extends Preference {
-
+/** A preference with tick icon. */
+public class TickButtonPreference extends Preference {
private ImageView mCheckIcon;
- private boolean mIsMark;
+ private boolean mIsSelected = false;
- public KeyboardLayoutPreference(Context context, String layoutName, boolean defaultMark) {
+ public TickButtonPreference(Context context) {
super(context);
setWidgetLayoutResource(R.layout.preference_check_icon);
- setTitle(layoutName);
- mIsMark = defaultMark;
}
@Override
public void onBindViewHolder(PreferenceViewHolder holder) {
super.onBindViewHolder(holder);
- mCheckIcon = (ImageView) holder.findViewById(R.id.keyboard_check_icon);
- setCheckMark(mIsMark);
+ mCheckIcon = (ImageView) holder.findViewById(R.id.check_icon);
+ setSelected(mIsSelected);
}
- public void setCheckMark(boolean isMark) {
+ /** Set icon state.*/
+ public void setSelected(boolean isSelected) {
if (mCheckIcon != null) {
- mCheckIcon.setVisibility(isMark ? View.VISIBLE : View.INVISIBLE);
- mIsMark = isMark;
+ mCheckIcon.setVisibility(isSelected ? View.VISIBLE : View.INVISIBLE);
}
+ mIsSelected = isSelected;
+ }
+
+ /** Return state of presenting icon. */
+ public boolean isSelected() {
+ return mIsSelected;
}
}
diff --git a/src/com/android/settings/wifi/dpp/WifiDppConfiguratorActivity.java b/src/com/android/settings/wifi/dpp/WifiDppConfiguratorActivity.java
index 6c9d4980f44..e6f0b31f384 100644
--- a/src/com/android/settings/wifi/dpp/WifiDppConfiguratorActivity.java
+++ b/src/com/android/settings/wifi/dpp/WifiDppConfiguratorActivity.java
@@ -28,7 +28,6 @@ import android.os.UserManager;
import android.provider.Settings;
import android.util.EventLog;
import android.util.Log;
-import android.view.WindowManager;
import androidx.annotation.VisibleForTesting;
import androidx.fragment.app.FragmentTransaction;
@@ -100,7 +99,6 @@ public class WifiDppConfiguratorActivity extends WifiDppBaseActivity implements
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- getWindow().addFlags(WindowManager.LayoutParams.FLAG_SECURE);
if (savedInstanceState != null) {
String qrCode = savedInstanceState.getString(KEY_QR_CODE);
diff --git a/tests/robotests/src/com/android/settings/datausage/DataUsageSummaryTest.java b/tests/robotests/src/com/android/settings/datausage/DataUsageSummaryTest.java
index 68d49fc6352..4ac73877c21 100644
--- a/tests/robotests/src/com/android/settings/datausage/DataUsageSummaryTest.java
+++ b/tests/robotests/src/com/android/settings/datausage/DataUsageSummaryTest.java
@@ -31,13 +31,14 @@ import android.app.usage.NetworkStatsManager;
import android.content.Context;
import android.content.res.Resources;
import android.net.NetworkPolicyManager;
+import android.os.UserManager;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import androidx.fragment.app.FragmentActivity;
+import androidx.test.core.app.ApplicationProvider;
import com.android.settings.R;
-
import com.android.settings.testutils.shadow.ShadowDashboardFragment;
import com.android.settings.testutils.shadow.ShadowDataUsageUtils;
import com.android.settings.testutils.shadow.ShadowUserManager;
@@ -45,13 +46,15 @@ import com.android.settings.testutils.shadow.ShadowUtils;
import org.junit.Before;
import org.junit.Ignore;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
+import org.mockito.Spy;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
import org.robolectric.Robolectric;
import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
import org.robolectric.Shadows;
import org.robolectric.annotation.Config;
import org.robolectric.shadows.ShadowApplication;
@@ -66,16 +69,22 @@ import org.robolectric.shadows.ShadowTelephonyManager;
})
@RunWith(RobolectricTestRunner.class)
public class DataUsageSummaryTest {
-
+ @Rule
+ public final MockitoRule mMockitoRule = MockitoJUnit.rule();
+ @Spy
+ Context mContext = ApplicationProvider.getApplicationContext();
+ @Mock
+ private UserManager mUserManager;
@Mock
private NetworkPolicyManager mNetworkPolicyManager;
@Mock
private NetworkStatsManager mNetworkStatsManager;
private TelephonyManager mTelephonyManager;
- private Context mContext;
private Resources mResources;
private FragmentActivity mActivity;
+ private DataUsageSummary mDataUsageSummary;
+
/**
* This set up is contrived to get a passing test so that the build doesn't block without tests.
* These tests should be updated as code gets refactored to improve testability.
@@ -83,12 +92,13 @@ public class DataUsageSummaryTest {
@Before
public void setUp() {
- MockitoAnnotations.initMocks(this);
+ doReturn(mUserManager).when(mContext).getSystemService(UserManager.class);
+ doReturn(false).when(mUserManager).isGuestUser();
+
ShadowApplication shadowContext = ShadowApplication.getInstance();
ShadowUserManager.getShadow().setIsAdminUser(true);
shadowContext.setSystemService(Context.NETWORK_POLICY_SERVICE, mNetworkPolicyManager);
- mContext = spy(RuntimeEnvironment.application);
mTelephonyManager = mContext.getSystemService(TelephonyManager.class);
final ShadowTelephonyManager shadowTelephonyManager = Shadows.shadowOf(mTelephonyManager);
shadowTelephonyManager.setTelephonyManagerForSubscriptionId(
@@ -101,6 +111,12 @@ public class DataUsageSummaryTest {
doReturn(true).when(mResources).getBoolean(R.bool.config_show_sim_info);
doReturn(mNetworkStatsManager).when(mActivity).getSystemService(NetworkStatsManager.class);
+
+ mDataUsageSummary = spy(new DataUsageSummary());
+ doReturn(mContext).when(mDataUsageSummary).getContext();
+ doNothing().when(mDataUsageSummary).enableProxySubscriptionManager(any());
+ doReturn(true).when(mDataUsageSummary).removePreference(anyString());
+ doNothing().when(mDataUsageSummary).addWifiSection();
}
@Test
@@ -201,4 +217,22 @@ public class DataUsageSummaryTest {
verify(dataUsageSummary).addWifiSection();
verify(dataUsageSummary, never()).addMobileSection(anyInt());
}
+
+ @Test
+ public void onCreate_isNotGuestUser_shouldNotFinish() {
+ doReturn(false).when(mUserManager).isGuestUser();
+
+ mDataUsageSummary.onCreate(null);
+
+ verify(mDataUsageSummary, never()).finish();
+ }
+
+ @Test
+ public void onCreate_isGuestUser_shouldFinish() {
+ doReturn(true).when(mUserManager).isGuestUser();
+
+ mDataUsageSummary.onCreate(null);
+
+ verify(mDataUsageSummary).finish();
+ }
}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batterysaver/BatterySaverButtonPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterysaver/BatterySaverButtonPreferenceControllerTest.java
index 9a7ef409f95..7398e5ce024 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batterysaver/BatterySaverButtonPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batterysaver/BatterySaverButtonPreferenceControllerTest.java
@@ -26,7 +26,6 @@ import static org.mockito.Mockito.when;
import android.content.Context;
import android.os.PowerManager;
-import android.provider.Settings;
import android.provider.SettingsSlicesContract;
import androidx.preference.PreferenceScreen;
@@ -72,24 +71,6 @@ public class BatterySaverButtonPreferenceControllerTest {
.isEqualTo(SettingsSlicesContract.AUTHORITY);
}
- @Test
- public void onSwitchChanged_isCheckedButNotAcked_preferenceIsUnchecked() {
- setLowPowerWarningAcked(/* acked= */ 0);
-
- mController.onSwitchChanged(/* switchView= */ null, /* isChecked= */ true);
-
- assertThat(mPreference.isChecked()).isFalse();
- }
-
- @Test
- public void onSwitchChanged_isCheckedAndAcked_setPowerSaveMode() {
- setLowPowerWarningAcked(/* acked= */ 1);
-
- mController.onSwitchChanged(/* switchView= */ null, /* isChecked= */ true);
-
- verify(mPowerManager).setPowerSaveModeEnabled(true);
- }
-
@Test
public void updateState_lowPowerOn_preferenceIsChecked() {
when(mPowerManager.isPowerSaveMode()).thenReturn(true);
@@ -140,16 +121,4 @@ public class BatterySaverButtonPreferenceControllerTest {
public void isPublicSlice_returnsTrue() {
assertThat(mController.isPublicSlice()).isTrue();
}
-
- // 0 means not acked, 1 means acked.
- private void setLowPowerWarningAcked(int acked) {
- Settings.Secure.putInt(
- mContext.getContentResolver(),
- Settings.Secure.LOW_POWER_WARNING_ACKNOWLEDGED,
- acked);
- Settings.Secure.putInt(
- mContext.getContentResolver(),
- Settings.Secure.EXTRA_LOW_POWER_WARNING_ACKNOWLEDGED,
- acked);
- }
}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageContentProviderTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageContentProviderTest.java
index e5547c59b5c..05a6f2bc89c 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageContentProviderTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageContentProviderTest.java
@@ -31,6 +31,7 @@ import android.net.Uri;
import androidx.test.core.app.ApplicationProvider;
import com.android.settings.fuelgauge.batteryusage.db.AppUsageEventEntity;
+import com.android.settings.fuelgauge.batteryusage.db.BatteryEventEntity;
import com.android.settings.fuelgauge.batteryusage.db.BatteryState;
import com.android.settings.fuelgauge.batteryusage.db.BatteryStateDatabase;
import com.android.settings.testutils.BatteryTestUtils;
@@ -353,6 +354,28 @@ public final class BatteryUsageContentProviderTest {
assertThat(entities.get(0).taskRootPackageName).isEqualTo("com.android.settings2");
}
+ @Test
+ public void insert_batteryEvent_returnsExpectedResult() {
+ mProvider.onCreate();
+ ContentValues values = new ContentValues();
+ values.put(BatteryEventEntity.KEY_TIMESTAMP, 10001L);
+ values.put(BatteryEventEntity.KEY_BATTERY_EVENT_TYPE,
+ BatteryEventType.POWER_CONNECTED.getNumber());
+ values.put(BatteryEventEntity.KEY_BATTERY_LEVEL, 66);
+
+ final Uri uri = mProvider.insert(DatabaseUtils.BATTERY_EVENT_URI, values);
+
+ assertThat(uri).isEqualTo(DatabaseUtils.BATTERY_EVENT_URI);
+ // Verifies the AppUsageEventEntity content.
+ final List entities =
+ BatteryStateDatabase.getInstance(mContext).batteryEventDao().getAll();
+ assertThat(entities).hasSize(1);
+ assertThat(entities.get(0).timestamp).isEqualTo(10001L);
+ assertThat(entities.get(0).batteryEventType).isEqualTo(
+ BatteryEventType.POWER_CONNECTED.getNumber());
+ assertThat(entities.get(0).batteryLevel).isEqualTo(66);
+ }
+
@Test
public void delete_throwsUnsupportedOperationException() {
assertThrows(
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/ConvertUtilsTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/ConvertUtilsTest.java
index fe1bff6ce00..6b8073b68ee 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/ConvertUtilsTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/ConvertUtilsTest.java
@@ -39,6 +39,7 @@ import android.os.RemoteException;
import android.os.UserHandle;
import com.android.settings.fuelgauge.batteryusage.db.AppUsageEventEntity;
+import com.android.settings.fuelgauge.batteryusage.db.BatteryEventEntity;
import org.junit.Before;
import org.junit.Test;
@@ -194,6 +195,22 @@ public final class ConvertUtilsTest {
.isEqualTo("com.android.settings2");
}
+ @Test
+ public void convertBatteryEventToContentValues_normalCase_returnsExpectedContentValues() {
+ final BatteryEvent batteryEvent =
+ BatteryEvent.newBuilder()
+ .setTimestamp(10001L)
+ .setType(BatteryEventType.POWER_CONNECTED)
+ .setBatteryLevel(66)
+ .build();
+ final ContentValues values =
+ ConvertUtils.convertBatteryEventToContentValues(batteryEvent);
+ assertThat(values.getAsLong(BatteryEventEntity.KEY_TIMESTAMP)).isEqualTo(10001L);
+ assertThat(values.getAsInteger(BatteryEventEntity.KEY_BATTERY_EVENT_TYPE)).isEqualTo(
+ BatteryEventType.POWER_CONNECTED.getNumber());
+ assertThat(values.getAsInteger(BatteryEventEntity.KEY_BATTERY_LEVEL)).isEqualTo(66);
+ }
+
@Test
public void convertToBatteryHistEntry_returnsExpectedResult() {
final int expectedType = 3;
@@ -405,6 +422,15 @@ public final class ConvertUtilsTest {
assertThat(appUsageEvent.getInstanceId()).isEqualTo(0);
}
+ @Test
+ public void convertToBatteryEvent_normalCase_returnsExpectedResult() {
+ final BatteryEvent batteryEvent = ConvertUtils.convertToBatteryEvent(
+ 666L, BatteryEventType.POWER_DISCONNECTED, 88);
+ assertThat(batteryEvent.getTimestamp()).isEqualTo(666L);
+ assertThat(batteryEvent.getType()).isEqualTo(BatteryEventType.POWER_DISCONNECTED);
+ assertThat(batteryEvent.getBatteryLevel()).isEqualTo(88);
+ }
+
@Test
public void getLocale_nullContext_returnDefaultLocale() {
assertThat(ConvertUtils.getLocale(/*context=*/ null))
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DataProcessManagerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DataProcessManagerTest.java
index aab91e0a590..753a7f7a1d0 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DataProcessManagerTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DataProcessManagerTest.java
@@ -183,7 +183,7 @@ public final class DataProcessManagerTest {
assertThat(dataProcessManager.getIsCurrentBatteryHistoryLoaded()).isTrue();
assertThat(dataProcessManager.getShowScreenOnTime()).isTrue();
final List appUsageEventList = dataProcessManager.getAppUsageEventList();
- Collections.sort(appUsageEventList, DataProcessor.TIMESTAMP_COMPARATOR);
+ Collections.sort(appUsageEventList, DataProcessor.APP_USAGE_EVENT_TIMESTAMP_COMPARATOR);
assertThat(appUsageEventList.size()).isEqualTo(6);
assertAppUsageEvent(
appUsageEventList.get(0), AppUsageEventType.ACTIVITY_RESUMED, /*timestamp=*/ 1);
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DataProcessorTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DataProcessorTest.java
index aa1547216d2..66e48c09246 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DataProcessorTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DataProcessorTest.java
@@ -250,7 +250,7 @@ public final class DataProcessorTest {
final Map>>>> periodMap =
DataProcessor.generateAppUsagePeriodMap(
- 14400000L, hourlyBatteryLevelsPerDay, appUsageEventList);
+ 14400000L, hourlyBatteryLevelsPerDay, appUsageEventList, new ArrayList<>());
assertThat(periodMap).hasSize(3);
// Day 1
@@ -288,7 +288,7 @@ public final class DataProcessorTest {
hourlyBatteryLevelsPerDay.add(
new BatteryLevelData.PeriodBatteryLevelData(new ArrayList<>(), new ArrayList<>()));
assertThat(DataProcessor.generateAppUsagePeriodMap(
- 0L, hourlyBatteryLevelsPerDay, new ArrayList<>())).isNull();
+ 0L, hourlyBatteryLevelsPerDay, new ArrayList<>(), new ArrayList<>())).isNull();
}
@Test
@@ -1669,7 +1669,8 @@ public final class DataProcessorTest {
/*instanceId=*/ 4, packageName2));
final Map>> appUsagePeriodMap =
- DataProcessor.buildAppUsagePeriodList(appUsageEvents, 0, 5);
+ DataProcessor.buildAppUsagePeriodList(
+ appUsageEvents, new ArrayList<>(), 0, 5);
assertThat(appUsagePeriodMap).hasSize(2);
final Map> userMap1 = appUsagePeriodMap.get(1L);
@@ -1693,7 +1694,7 @@ public final class DataProcessorTest {
@Test
public void buildAppUsagePeriodList_emptyEventList_returnNull() {
assertThat(DataProcessor.buildAppUsagePeriodList(
- new ArrayList<>(), 0, 1)).isNull();
+ new ArrayList<>(), new ArrayList<>(), 0, 1)).isNull();
}
@Test
@@ -1705,7 +1706,7 @@ public final class DataProcessorTest {
AppUsageEventType.DEVICE_SHUTDOWN, /*timestamp=*/ 2));
assertThat(DataProcessor.buildAppUsagePeriodList(
- appUsageEvents, 0, 3)).isNull();
+ appUsageEvents, new ArrayList<>(), 0, 3)).isNull();
}
@Test
@@ -1765,6 +1766,89 @@ public final class DataProcessorTest {
assertAppUsagePeriod(appUsagePeriodList.get(6), 1000000, 1100000);
}
+ @Test
+ public void excludePowerConnectedTime_startEndNotCharging_returnExpectedResult() {
+ final List appUsagePeriodList = List.of(
+ AppUsagePeriod.newBuilder().setStartTime(100).setEndTime(200).build());
+ final List batteryEventList = List.of(
+ BatteryEvent.newBuilder().setTimestamp(50).setType(
+ BatteryEventType.POWER_DISCONNECTED).build(),
+ BatteryEvent.newBuilder().setTimestamp(166).setType(
+ BatteryEventType.POWER_CONNECTED).build(),
+ BatteryEvent.newBuilder().setTimestamp(188).setType(
+ BatteryEventType.POWER_DISCONNECTED).build(),
+ BatteryEvent.newBuilder().setTimestamp(280).setType(
+ BatteryEventType.POWER_CONNECTED).build());
+
+ final List resultList =
+ DataProcessor.excludePowerConnectedTimeFromAppUsagePeriodList(
+ appUsagePeriodList, batteryEventList);
+
+ assertThat(resultList).hasSize(2);
+ assertAppUsagePeriod(resultList.get(0), 100, 166);
+ assertAppUsagePeriod(resultList.get(1), 188, 200);
+ }
+
+ @Test
+ public void excludePowerConnectedTime_startEndInCharging_returnExpectedResult() {
+ final List appUsagePeriodList = List.of(
+ AppUsagePeriod.newBuilder().setStartTime(100).setEndTime(200).build());
+ final List batteryEventList = List.of(
+ BatteryEvent.newBuilder().setTimestamp(50).setType(
+ BatteryEventType.POWER_DISCONNECTED).build(),
+ BatteryEvent.newBuilder().setTimestamp(80).setType(
+ BatteryEventType.POWER_CONNECTED).build(),
+ BatteryEvent.newBuilder().setTimestamp(120).setType(
+ BatteryEventType.POWER_DISCONNECTED).build(),
+ BatteryEvent.newBuilder().setTimestamp(150).setType(
+ BatteryEventType.POWER_CONNECTED).build(),
+ BatteryEvent.newBuilder().setTimestamp(160).setType(
+ BatteryEventType.POWER_DISCONNECTED).build(),
+ BatteryEvent.newBuilder().setTimestamp(180).setType(
+ BatteryEventType.POWER_CONNECTED).build());
+
+ final List resultList =
+ DataProcessor.excludePowerConnectedTimeFromAppUsagePeriodList(
+ appUsagePeriodList, batteryEventList);
+
+ assertThat(resultList).hasSize(2);
+ assertAppUsagePeriod(resultList.get(0), 120, 150);
+ assertAppUsagePeriod(resultList.get(1), 160, 180);
+ }
+
+ @Test
+ public void excludePowerConnectedTime_wholePeriodNotCharging_returnExpectedResult() {
+ final List appUsagePeriodList = List.of(
+ AppUsagePeriod.newBuilder().setStartTime(100).setEndTime(200).build());
+ final List batteryEventList = List.of(
+ BatteryEvent.newBuilder().setTimestamp(50).setType(
+ BatteryEventType.POWER_DISCONNECTED).build(),
+ BatteryEvent.newBuilder().setTimestamp(80).setType(
+ BatteryEventType.POWER_CONNECTED).build());
+
+ final List resultList =
+ DataProcessor.excludePowerConnectedTimeFromAppUsagePeriodList(
+ appUsagePeriodList, batteryEventList);
+
+ assertThat(resultList).isEmpty();
+ }
+
+ @Test
+ public void excludePowerConnectedTime_wholePeriodInCharging_returnExpectedResult() {
+ final List appUsagePeriodList = List.of(
+ AppUsagePeriod.newBuilder().setStartTime(100).setEndTime(200).build());
+ final List batteryEventList = List.of(
+ BatteryEvent.newBuilder().setTimestamp(50).setType(
+ BatteryEventType.POWER_DISCONNECTED).build());
+
+ final List resultList =
+ DataProcessor.excludePowerConnectedTimeFromAppUsagePeriodList(
+ appUsagePeriodList, batteryEventList);
+
+ assertThat(resultList).hasSize(1);
+ assertAppUsagePeriod(resultList.get(0), 100, 200);
+ }
+
@Test
public void getScreenOnTime_returnExpectedResult() {
final long userId = 1;
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtilsTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtilsTest.java
index 0cb3d1d50d4..20799d403d3 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtilsTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtilsTest.java
@@ -36,6 +36,7 @@ import android.os.UserHandle;
import android.os.UserManager;
import com.android.settings.fuelgauge.batteryusage.db.AppUsageEventEntity;
+import com.android.settings.fuelgauge.batteryusage.db.BatteryEventEntity;
import com.android.settings.testutils.BatteryTestUtils;
import org.junit.Before;
@@ -136,6 +137,28 @@ public final class DatabaseUtilsTest {
verifyNoMoreInteractions(mMockContentResolver);
}
+ @Test
+ public void sendBatteryEventData_returnsExpectedList() {
+ final BatteryEvent batteryEvent =
+ BatteryEvent.newBuilder()
+ .setTimestamp(10001L)
+ .setType(BatteryEventType.POWER_CONNECTED)
+ .setBatteryLevel(66)
+ .build();
+
+ final ContentValues contentValues =
+ DatabaseUtils.sendBatteryEventData(mContext, batteryEvent);
+
+ assertThat(contentValues.getAsInteger(BatteryEventEntity.KEY_TIMESTAMP))
+ .isEqualTo(10001L);
+ assertThat(contentValues.getAsInteger(BatteryEventEntity.KEY_BATTERY_EVENT_TYPE))
+ .isEqualTo(BatteryEventType.POWER_CONNECTED.getNumber());
+ assertThat(contentValues.getAsInteger(BatteryEventEntity.KEY_BATTERY_LEVEL))
+ .isEqualTo(66);
+ // Verifies the inserted ContentValues into content provider.
+ verify(mMockContentResolver).insert(DatabaseUtils.BATTERY_EVENT_URI, contentValues);
+ }
+
@Test
public void sendBatteryEntryData_nullBatteryIntent_returnsNullValue() {
doReturn(null).when(mContext).registerReceiver(any(), any());
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/db/BatteryEventDaoTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/db/BatteryEventDaoTest.java
new file mode 100644
index 00000000000..941f444e552
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/db/BatteryEventDaoTest.java
@@ -0,0 +1,80 @@
+/*
+ * 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;
+
+/** Tests for {@link BatteryEventDao}. */
+@RunWith(RobolectricTestRunner.class)
+public final class BatteryEventDaoTest {
+ private Context mContext;
+ private BatteryStateDatabase mDatabase;
+ private BatteryEventDao mBatteryEventDao;
+
+ @Before
+ public void setUp() {
+ mContext = ApplicationProvider.getApplicationContext();
+ mDatabase = BatteryTestUtils.setUpBatteryStateDatabase(mContext);
+ mBatteryEventDao = mDatabase.batteryEventDao();
+ }
+
+ @After
+ public void closeDb() {
+ mDatabase.close();
+ BatteryStateDatabase.setBatteryStateDatabase(/*database=*/ null);
+ }
+
+ @Test
+ public void getAllAfter_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(160L);
+ assertThat(cursor.getCount()).isEqualTo(1);
+ cursor.moveToFirst();
+ assertThat(cursor.getLong(cursor.getColumnIndex(BatteryEventEntity.KEY_TIMESTAMP)))
+ .isEqualTo(200L);
+ assertThat(cursor.getInt(cursor.getColumnIndex(BatteryEventEntity.KEY_BATTERY_EVENT_TYPE)))
+ .isEqualTo(2);
+ assertThat(cursor.getInt(cursor.getColumnIndex(BatteryEventEntity.KEY_BATTERY_LEVEL)))
+ .isEqualTo(88);
+
+ mBatteryEventDao.clearAll();
+ assertThat(mBatteryEventDao.getAll()).isEmpty();
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/db/BatteryEventEntityTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/db/BatteryEventEntityTest.java
new file mode 100644
index 00000000000..a34d6515982
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/db/BatteryEventEntityTest.java
@@ -0,0 +1,47 @@
+/*
+ * 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 BatteryEventEntity}. */
+@RunWith(RobolectricTestRunner.class)
+public final class BatteryEventEntityTest {
+
+ @Test
+ public void testBuilder_returnsExpectedResult() {
+ final long timestamp = 10001L;
+ final int batteryEventType = 1;
+ final int batteryLevel = 66;
+
+ BatteryEventEntity entity = BatteryEventEntity
+ .newBuilder()
+ .setTimestamp(timestamp)
+ .setBatteryEventType(batteryEventType)
+ .setBatteryLevel(batteryLevel)
+ .build();
+
+ // Verifies the app relative information.
+ assertThat(entity.timestamp).isEqualTo(timestamp);
+ assertThat(entity.batteryEventType).isEqualTo(batteryEventType);
+ assertThat(entity.batteryLevel).isEqualTo(batteryLevel);
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/wifi/dpp/WifiDppConfiguratorActivityTest.java b/tests/robotests/src/com/android/settings/wifi/dpp/WifiDppConfiguratorActivityTest.java
index 88fa83afbf7..d8605ded829 100644
--- a/tests/robotests/src/com/android/settings/wifi/dpp/WifiDppConfiguratorActivityTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/dpp/WifiDppConfiguratorActivityTest.java
@@ -16,10 +16,6 @@
package com.android.settings.wifi.dpp;
-import static android.view.WindowManager.LayoutParams.FLAG_SECURE;
-
-import static com.google.common.truth.Truth.assertThat;
-
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
@@ -76,12 +72,6 @@ public class WifiDppConfiguratorActivityTest {
Robolectric.setupActivity(WifiDppConfiguratorActivity.class);
}
- @Test
- public void launchActivity_shouldAddFlagSecure() {
- assertThat(mActivity.getWindow().getAttributes().flags & FLAG_SECURE)
- .isEqualTo(FLAG_SECURE);
- }
-
@Test
public void handleIntent_isGuestUser_shouldFinish() {
when(mUserManager.isGuestUser()).thenReturn(true);
diff --git a/tests/unit/src/com/android/settings/regionalpreferences/NumberingSystemItemControllerTest.java b/tests/unit/src/com/android/settings/regionalpreferences/NumberingSystemItemControllerTest.java
index 5ec33db8095..708987efc7d 100644
--- a/tests/unit/src/com/android/settings/regionalpreferences/NumberingSystemItemControllerTest.java
+++ b/tests/unit/src/com/android/settings/regionalpreferences/NumberingSystemItemControllerTest.java
@@ -33,6 +33,8 @@ import androidx.preference.PreferenceScreen;
import androidx.test.annotation.UiThreadTest;
import androidx.test.core.app.ApplicationProvider;
+import com.android.settings.widget.TickButtonPreference;
+
import org.junit.After;
import org.junit.Before;
import org.junit.Test;