Update database clear & job refresh mechanism for time change intent
- Ignore time change intent for time format update
- Clear data after current time in DB and refresh periodic job
- Take a snapshot of current battery usage stats if no periodic job in DB
Bug: 336423923
Bug: 314921894
Fix: 314921894
Test: atest SettingsRoboTests:com.android.settings.fuelgauge.batteryusagei
Change-Id: Iec0f5e8e97f18c4603de711a5884336ba0af23a9
diff --git a/src/com/android/settings/fuelgauge/batteryusage/BootBroadcastReceiver.java b/src/com/android/settings/fuelgauge/batteryusage/BootBroadcastReceiver.java
index e407c63..5fa04eb 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/BootBroadcastReceiver.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/BootBroadcastReceiver.java
@@ -67,7 +67,7 @@
refreshJobs(context);
break;
case Intent.ACTION_TIME_CHANGED:
- Log.d(TAG, "refresh job and clear all data from action=" + action);
+ Log.d(TAG, "refresh job and clear data from action=" + action);
DatabaseUtils.clearDataAfterTimeChangedIfNeeded(context, intent);
break;
default:
diff --git a/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtils.java b/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtils.java
index a41e9bd..b40f71a 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtils.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtils.java
@@ -16,8 +16,6 @@
package com.android.settings.fuelgauge.batteryusage;
-import static android.content.Intent.FLAG_RECEIVER_REPLACE_PENDING;
-
import static com.android.settings.fuelgauge.batteryusage.ConvertUtils.utcToLocalTimeForLogging;
import android.app.usage.IUsageStatsManager;
@@ -436,6 +434,23 @@
});
}
+ /** Clears data after a specific startTimestamp in the battery usage database. */
+ public static void clearAllAfter(Context context, long startTimestamp) {
+ AsyncTask.execute(
+ () -> {
+ try {
+ final BatteryStateDatabase database =
+ BatteryStateDatabase.getInstance(context.getApplicationContext());
+ database.appUsageEventDao().clearAllAfter(startTimestamp);
+ database.batteryEventDao().clearAllAfter(startTimestamp);
+ database.batteryStateDao().clearAllAfter(startTimestamp);
+ database.batteryUsageSlotDao().clearAllAfter(startTimestamp);
+ } catch (RuntimeException e) {
+ Log.e(TAG, "clearAllAfter() failed", e);
+ }
+ });
+ }
+
/** Clears all out-of-date data in the battery usage database. */
public static void clearExpiredDataIfNeeded(Context context) {
AsyncTask.execute(
@@ -456,14 +471,14 @@
});
}
- /** Clears all data and jobs if current timestamp is out of the range of last recorded job. */
+ /** Clears data after new updated time and refresh periodic job. */
public static void clearDataAfterTimeChangedIfNeeded(Context context, Intent intent) {
- if ((intent.getFlags() & FLAG_RECEIVER_REPLACE_PENDING) != 0) {
+ if ((intent.hasExtra(Intent.EXTRA_TIME_PREF_24_HOUR_FORMAT))) {
BatteryUsageLogUtils.writeLog(
context,
Action.TIME_UPDATED,
- "Database is not cleared because the time change intent is only"
- + " for the existing pending receiver.");
+ "Database is not cleared because the time change intent is"
+ + " for time format change");
return;
}
AsyncTask.execute(
@@ -861,36 +876,23 @@
}
private static void clearDataAfterTimeChangedIfNeededInternal(Context context) {
+ final long currentTime = System.currentTimeMillis();
+ final String logInfo =
+ String.format(Locale.ENGLISH, "clear data after current time = %d", currentTime);
+ Log.d(TAG, logInfo);
+ BatteryUsageLogUtils.writeLog(context, Action.TIME_UPDATED, logInfo);
+ DatabaseUtils.clearAllAfter(context, currentTime);
+ PeriodicJobManager.getInstance(context).refreshJob(/* fromBoot= */ false);
+
final List<BatteryEvent> batteryLevelRecordEvents =
DatabaseUtils.getBatteryEvents(
context,
Calendar.getInstance(),
getLastFullChargeTime(context),
BATTERY_LEVEL_RECORD_EVENTS);
- final long lastRecordTimestamp =
- batteryLevelRecordEvents.isEmpty()
- ? INVALID_TIMESTAMP
- : batteryLevelRecordEvents.get(0).getTimestamp();
- final long nextRecordTimestamp =
- TimestampUtils.getNextEvenHourTimestamp(lastRecordTimestamp);
- final long currentTime = System.currentTimeMillis();
- final boolean isOutOfTimeRange =
- lastRecordTimestamp == INVALID_TIMESTAMP
- || currentTime < lastRecordTimestamp
- || currentTime > nextRecordTimestamp;
- final String logInfo =
- String.format(
- Locale.ENGLISH,
- "clear database = %b, current time = %d, last record time = %d",
- isOutOfTimeRange,
- currentTime,
- lastRecordTimestamp);
- Log.d(TAG, logInfo);
- BatteryUsageLogUtils.writeLog(context, Action.TIME_UPDATED, logInfo);
- if (isOutOfTimeRange) {
- DatabaseUtils.clearAll(context);
- PeriodicJobManager.getInstance(context)
- .refreshJob(/* fromBoot= */ false);
+ if (batteryLevelRecordEvents.isEmpty()) {
+ // Take a snapshot of battery usage data immediately if there's no battery events.
+ BatteryUsageDataLoader.enqueueWork(context, /* isFullChargeStart= */ true);
}
}
diff --git a/src/com/android/settings/fuelgauge/batteryusage/db/AppUsageEventDao.java b/src/com/android/settings/fuelgauge/batteryusage/db/AppUsageEventDao.java
index d220b15..2497801 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/db/AppUsageEventDao.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/db/AppUsageEventDao.java
@@ -55,6 +55,10 @@
@Query("DELETE FROM AppUsageEventEntity WHERE timestamp <= :timestamp")
void clearAllBefore(long timestamp);
+ /** Deletes all recorded data after a specific timestamp. */
+ @Query("DELETE FROM AppUsageEventEntity WHERE timestamp >= :timestamp")
+ void clearAllAfter(long timestamp);
+
/** Clears all recorded data in the database. */
@Query("DELETE FROM AppUsageEventEntity")
void clearAll();
diff --git a/src/com/android/settings/fuelgauge/batteryusage/db/BatteryEventDao.java b/src/com/android/settings/fuelgauge/batteryusage/db/BatteryEventDao.java
index 8b696fe..19d2043 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/db/BatteryEventDao.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/db/BatteryEventDao.java
@@ -65,6 +65,10 @@
@Query("DELETE FROM BatteryEventEntity WHERE timestamp <= :timestamp")
void clearAllBefore(long timestamp);
+ /** Deletes all recorded data after a specific timestamp. */
+ @Query("DELETE FROM BatteryEventEntity WHERE timestamp >= :timestamp")
+ void clearAllAfter(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/BatteryStateDao.java b/src/com/android/settings/fuelgauge/batteryusage/db/BatteryStateDao.java
index 520c6be..049251e 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/db/BatteryStateDao.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/db/BatteryStateDao.java
@@ -61,6 +61,10 @@
@Query("DELETE FROM BatteryState WHERE timestamp <= :timestamp")
void clearAllBefore(long timestamp);
+ /** Deletes all recorded data after a specific timestamp. */
+ @Query("DELETE FROM BatteryState WHERE timestamp >= :timestamp")
+ void clearAllAfter(long timestamp);
+
/** Clears all recorded data in the database. */
@Query("DELETE FROM BatteryState")
void clearAll();
diff --git a/src/com/android/settings/fuelgauge/batteryusage/db/BatteryUsageSlotDao.java b/src/com/android/settings/fuelgauge/batteryusage/db/BatteryUsageSlotDao.java
index d8cf41d..d53b0cf 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/db/BatteryUsageSlotDao.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/db/BatteryUsageSlotDao.java
@@ -52,6 +52,10 @@
@Query("DELETE FROM BatteryUsageSlotEntity WHERE timestamp <= :timestamp")
void clearAllBefore(long timestamp);
+ /** Deletes all recorded data after a specific timestamp. */
+ @Query("DELETE FROM BatteryUsageSlotEntity WHERE timestamp >= :timestamp")
+ void clearAllAfter(long timestamp);
+
/** Clears all recorded data in the database. */
@Query("DELETE FROM BatteryUsageSlotEntity")
void clearAll();
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BootBroadcastReceiverTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BootBroadcastReceiverTest.java
index df330a3..3e53b03 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BootBroadcastReceiverTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BootBroadcastReceiverTest.java
@@ -35,7 +35,6 @@
import org.junit.After;
import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
@@ -64,9 +63,8 @@
// Inserts fake data into database for testing.
final BatteryStateDatabase database = BatteryTestUtils.setUpBatteryStateDatabase(mContext);
- BatteryTestUtils.insertDataToBatteryStateTable(
- mContext, Clock.systemUTC().millis(), "com.android.systemui");
mDao = database.batteryStateDao();
+ mDao.clearAll();
clearSharedPreferences();
}
@@ -129,10 +127,13 @@
assertThat(mShadowAlarmManager.peekNextScheduledAlarm()).isNull();
}
- @Ignore("b/314921894")
@Test
- public void onReceive_withTimeChangedIntent_clearsAllDataAndRefreshesJob()
+ public void onReceive_withTimeChangedIntentSetEarlierTime_refreshesJob()
throws InterruptedException {
+ BatteryTestUtils.insertDataToBatteryStateTable(
+ mContext, Clock.systemUTC().millis() + 60000, "com.android.systemui");
+ assertThat(mDao.getAllAfter(0).size()).isEqualTo(1);
+
mReceiver.onReceive(mContext, new Intent(Intent.ACTION_TIME_CHANGED));
TimeUnit.MILLISECONDS.sleep(100);
@@ -141,6 +142,38 @@
}
@Test
+ public void onReceive_withTimeChangedIntentSetLaterTime_clearNoDataAndRefreshesJob()
+ throws InterruptedException {
+ BatteryTestUtils.insertDataToBatteryStateTable(
+ mContext, Clock.systemUTC().millis() - 60000, "com.android.systemui");
+ assertThat(mDao.getAllAfter(0).size()).isEqualTo(1);
+
+ mReceiver.onReceive(mContext, new Intent(Intent.ACTION_TIME_CHANGED));
+
+ TimeUnit.MILLISECONDS.sleep(100);
+ assertThat(mDao.getAllAfter(0).size()).isEqualTo(1);
+ assertThat(mShadowAlarmManager.peekNextScheduledAlarm()).isNotNull();
+ }
+
+ @Test
+ public void onReceive_withTimeFormatChangedIntent_skipRefreshJob() throws InterruptedException {
+ BatteryTestUtils.insertDataToBatteryStateTable(
+ mContext, Clock.systemUTC().millis() + 60000, "com.android.systemui");
+ assertThat(mDao.getAllAfter(0).size()).isEqualTo(1);
+
+ mReceiver.onReceive(
+ mContext,
+ new Intent(Intent.EXTRA_INTENT)
+ .putExtra(
+ Intent.EXTRA_TIME_PREF_24_HOUR_FORMAT,
+ Intent.EXTRA_TIME_PREF_VALUE_USE_12_HOUR));
+
+ TimeUnit.MILLISECONDS.sleep(100);
+ assertThat(mDao.getAllAfter(0).size()).isEqualTo(1);
+ assertThat(mShadowAlarmManager.peekNextScheduledAlarm()).isNull();
+ }
+
+ @Test
public void invokeJobRecheck_broadcastsIntent() {
BootBroadcastReceiver.invokeJobRecheck(mContext);