Add database to store anomaly data
1. Refactor HighUsageApp to AppInfo so it could be
reused both in dialog and app restriction
2. Add BatteryDatabaseHelper to store the anomaly log
Bug: 70570352
Test: RunSettingsRoboTests
Change-Id: I900cd9746ff7f1e19bd6f3948463588b7cf72b85
diff --git a/src/com/android/settings/fuelgauge/batterytip/AnomalyDatabaseHelper.java b/src/com/android/settings/fuelgauge/batterytip/AnomalyDatabaseHelper.java
new file mode 100644
index 0000000..a13df25
--- /dev/null
+++ b/src/com/android/settings/fuelgauge/batterytip/AnomalyDatabaseHelper.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2018 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.batterytip;
+
+import android.content.Context;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteOpenHelper;
+import android.util.Log;
+
+import com.android.settings.fuelgauge.anomaly.Anomaly;
+
+/**
+ * Database controls the anomaly logging(e.g. packageName, anomalyType and time)
+ */
+public class AnomalyDatabaseHelper extends SQLiteOpenHelper {
+ private static final String TAG = "BatteryDatabaseHelper";
+
+ private static final String DATABASE_NAME = "battery_settings.db";
+ private static final int DATABASE_VERSION = 1;
+
+ public interface Tables {
+ String TABLE_ANOMALY = "anomaly";
+ }
+
+ public interface AnomalyColumns {
+ /**
+ * The package name of the anomaly app
+ */
+ String PACKAGE_NAME = "package_name";
+ /**
+ * The type of the anomaly app
+ * @see Anomaly.AnomalyType
+ */
+ String ANOMALY_TYPE = "anomaly_type";
+ /**
+ * The time when anomaly happens
+ */
+ String TIME_STAMP_MS = "time_stamp_ms";
+ }
+
+ private static final String CREATE_ANOMALY_TABLE =
+ "CREATE TABLE " + Tables.TABLE_ANOMALY +
+ "(" +
+ AnomalyColumns.PACKAGE_NAME +
+ " TEXT, " +
+ AnomalyColumns.ANOMALY_TYPE +
+ " INTEGER, " +
+ AnomalyColumns.TIME_STAMP_MS +
+ " INTEGER)";
+
+ private static AnomalyDatabaseHelper sSingleton;
+
+ public static synchronized AnomalyDatabaseHelper getInstance(Context context) {
+ if (sSingleton == null) {
+ sSingleton = new AnomalyDatabaseHelper(context.getApplicationContext());
+ }
+ return sSingleton;
+ }
+
+ private AnomalyDatabaseHelper(Context context) {
+ super(context, DATABASE_NAME, null, DATABASE_VERSION);
+ }
+
+ @Override
+ public void onCreate(SQLiteDatabase db) {
+ bootstrapDB(db);
+ }
+
+ private void bootstrapDB(SQLiteDatabase db) {
+ db.execSQL(CREATE_ANOMALY_TABLE);
+ Log.i(TAG, "Bootstrapped database");
+ }
+
+ @Override
+ public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+ if (oldVersion < DATABASE_VERSION) {
+ Log.w(TAG, "Detected schema version '" + oldVersion + "'. " +
+ "Index needs to be rebuilt for schema version '" + newVersion + "'.");
+ // We need to drop the tables and recreate them
+ reconstruct(db);
+ }
+ }
+
+ @Override
+ public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+ Log.w(TAG, "Detected schema version '" + oldVersion + "'. " +
+ "Index needs to be rebuilt for schema version '" + newVersion + "'.");
+ // We need to drop the tables and recreate them
+ reconstruct(db);
+ }
+
+ public void reconstruct(SQLiteDatabase db) {
+ dropTables(db);
+ bootstrapDB(db);
+ }
+
+ private void dropTables(SQLiteDatabase db) {
+ db.execSQL("DROP TABLE IF EXISTS " + Tables.TABLE_ANOMALY);
+ }
+}
diff --git a/src/com/android/settings/fuelgauge/batterytip/AppInfo.java b/src/com/android/settings/fuelgauge/batterytip/AppInfo.java
new file mode 100644
index 0000000..1daff36
--- /dev/null
+++ b/src/com/android/settings/fuelgauge/batterytip/AppInfo.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2018 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.batterytip;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.support.annotation.VisibleForTesting;
+
+import com.android.settings.fuelgauge.anomaly.Anomaly;
+
+/**
+ * Model class stores app info(e.g. package name, type..) that used in battery tip
+ */
+public class AppInfo implements Comparable<AppInfo>, Parcelable {
+ public final String packageName;
+ /**
+ * Anomaly type of the app
+ * @see Anomaly.AnomalyType
+ */
+ public final int anomalyType;
+ public final long screenOnTimeMs;
+
+ private AppInfo(AppInfo.Builder builder) {
+ packageName = builder.mPackageName;
+ anomalyType = builder.mAnomalyType;
+ screenOnTimeMs = builder.mScreenOnTimeMs;
+ }
+
+ @VisibleForTesting
+ AppInfo(Parcel in) {
+ packageName = in.readString();
+ anomalyType = in.readInt();
+ screenOnTimeMs = in.readLong();
+ }
+
+ @Override
+ public int compareTo(AppInfo o) {
+ return Long.compare(screenOnTimeMs, o.screenOnTimeMs);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(packageName);
+ dest.writeInt(anomalyType);
+ dest.writeLong(screenOnTimeMs);
+ }
+
+ public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
+ public AppInfo createFromParcel(Parcel in) {
+ return new AppInfo(in);
+ }
+
+ public AppInfo[] newArray(int size) {
+ return new AppInfo[size];
+ }
+ };
+
+ public static final class Builder {
+ private int mAnomalyType;
+ private String mPackageName;
+ private long mScreenOnTimeMs;
+
+ public Builder setAnomalyType(int type) {
+ mAnomalyType = type;
+ return this;
+ }
+
+ public Builder setPackageName(String packageName) {
+ mPackageName = packageName;
+ return this;
+ }
+
+ public Builder setScreenOnTimeMs(long screenOnTimeMs) {
+ mScreenOnTimeMs = screenOnTimeMs;
+ return this;
+ }
+
+ public AppInfo build() {
+ return new AppInfo(this);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/com/android/settings/fuelgauge/batterytip/BatteryDatabaseManager.java b/src/com/android/settings/fuelgauge/batterytip/BatteryDatabaseManager.java
new file mode 100644
index 0000000..f87501f
--- /dev/null
+++ b/src/com/android/settings/fuelgauge/batterytip/BatteryDatabaseManager.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2018 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.batterytip;
+
+import static com.android.settings.fuelgauge.batterytip.AnomalyDatabaseHelper.AnomalyColumns
+ .PACKAGE_NAME;
+import static com.android.settings.fuelgauge.batterytip.AnomalyDatabaseHelper.AnomalyColumns
+ .ANOMALY_TYPE;
+import static com.android.settings.fuelgauge.batterytip.AnomalyDatabaseHelper.AnomalyColumns
+ .TIME_STAMP_MS;
+import static com.android.settings.fuelgauge.batterytip.AnomalyDatabaseHelper.Tables.TABLE_ANOMALY;
+
+import android.content.ContentValues;
+import android.content.Context;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Database manager for battery data. Now it only contains anomaly data stored in {@link AppInfo}.
+ */
+public class BatteryDatabaseManager {
+ private final AnomalyDatabaseHelper mDatabaseHelper;
+
+ public BatteryDatabaseManager(Context context) {
+ mDatabaseHelper = AnomalyDatabaseHelper.getInstance(context);
+ }
+
+ /**
+ * Insert an anomaly log to database.
+ *
+ * @param packageName the package name of the app
+ * @param type the type of the anomaly
+ * @param timestampMs the time when it is happened
+ */
+ public void insertAnomaly(String packageName, int type, long timestampMs) {
+ try (SQLiteDatabase db = mDatabaseHelper.getWritableDatabase()) {
+ ContentValues values = new ContentValues();
+ values.put(PACKAGE_NAME, packageName);
+ values.put(ANOMALY_TYPE, type);
+ values.put(TIME_STAMP_MS, timestampMs);
+
+ db.insert(TABLE_ANOMALY, null, values);
+ }
+ }
+
+ /**
+ * Query all the anomalies that happened after {@code timestampMs}.
+ */
+ public List<AppInfo> queryAllAnomaliesAfter(long timestampMs) {
+ final List<AppInfo> appInfos = new ArrayList<>();
+ try (SQLiteDatabase db = mDatabaseHelper.getReadableDatabase()) {
+ final String[] projection = {PACKAGE_NAME, ANOMALY_TYPE};
+ final String orderBy = AnomalyDatabaseHelper.AnomalyColumns.TIME_STAMP_MS + " DESC";
+
+ try (Cursor cursor = db.query(TABLE_ANOMALY, projection, TIME_STAMP_MS + " > ?",
+ new String[]{String.valueOf(timestampMs)}, null, null, orderBy)) {
+ while (cursor.moveToNext()) {
+ AppInfo appInfo = new AppInfo.Builder()
+ .setPackageName(cursor.getString(cursor.getColumnIndex(PACKAGE_NAME)))
+ .setAnomalyType(cursor.getInt(cursor.getColumnIndex(ANOMALY_TYPE)))
+ .build();
+ appInfos.add(appInfo);
+ }
+ }
+ }
+
+ return appInfos;
+ }
+
+ public void deleteAllAnomaliesBeforeTimeStamp(long timestampMs) {
+ try (SQLiteDatabase db = mDatabaseHelper.getWritableDatabase()) {
+ db.delete(TABLE_ANOMALY, TIME_STAMP_MS + " < ?",
+ new String[]{String.valueOf(timestampMs)});
+ }
+ }
+}
diff --git a/src/com/android/settings/fuelgauge/batterytip/HighUsageAdapter.java b/src/com/android/settings/fuelgauge/batterytip/HighUsageAdapter.java
index 8b74394..60aa6c8 100644
--- a/src/com/android/settings/fuelgauge/batterytip/HighUsageAdapter.java
+++ b/src/com/android/settings/fuelgauge/batterytip/HighUsageAdapter.java
@@ -39,7 +39,7 @@
private final Context mContext;
private final IconDrawableFactory mIconDrawableFactory;
private final PackageManager mPackageManager;
- private final List<HighUsageApp> mHighUsageAppList;
+ private final List<AppInfo> mHighUsageAppList;
public static class ViewHolder extends RecyclerView.ViewHolder {
public View view;
@@ -56,7 +56,7 @@
}
}
- public HighUsageAdapter(Context context, List<HighUsageApp> highUsageAppList) {
+ public HighUsageAdapter(Context context, List<AppInfo> highUsageAppList) {
mContext = context;
mHighUsageAppList = highUsageAppList;
mIconDrawableFactory = IconDrawableFactory.newInstance(context);
@@ -72,7 +72,7 @@
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
- final HighUsageApp app = mHighUsageAppList.get(position);
+ final AppInfo app = mHighUsageAppList.get(position);
holder.appIcon.setImageDrawable(
Utils.getBadgedIcon(mIconDrawableFactory, mPackageManager, app.packageName,
UserHandle.myUserId()));
diff --git a/src/com/android/settings/fuelgauge/batterytip/HighUsageApp.java b/src/com/android/settings/fuelgauge/batterytip/HighUsageApp.java
deleted file mode 100644
index f75ecf0..0000000
--- a/src/com/android/settings/fuelgauge/batterytip/HighUsageApp.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (C) 2018 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.batterytip;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-
-/**
- * Class representing app with high screen usage
- */
-public class HighUsageApp implements Comparable<HighUsageApp>, Parcelable {
- public final String packageName;
- public final long screenOnTimeMs;
-
- public HighUsageApp(String packageName, long screenOnTimeMs) {
- this.packageName = packageName;
- this.screenOnTimeMs = screenOnTimeMs;
- }
-
- private HighUsageApp(Parcel in) {
- packageName = in.readString();
- screenOnTimeMs = in.readLong();
- }
-
- @Override
- public int compareTo(HighUsageApp o) {
- return Long.compare(screenOnTimeMs, o.screenOnTimeMs);
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeString(packageName);
- dest.writeLong(screenOnTimeMs);
- }
-
- public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
- public HighUsageApp createFromParcel(Parcel in) {
- return new HighUsageApp(in);
- }
-
- public HighUsageApp[] newArray(int size) {
- return new HighUsageApp[size];
- }
- };
-}
\ No newline at end of file
diff --git a/src/com/android/settings/fuelgauge/batterytip/detectors/HighUsageDetector.java b/src/com/android/settings/fuelgauge/batterytip/detectors/HighUsageDetector.java
index 237f430..3c69667 100644
--- a/src/com/android/settings/fuelgauge/batterytip/detectors/HighUsageDetector.java
+++ b/src/com/android/settings/fuelgauge/batterytip/detectors/HighUsageDetector.java
@@ -23,13 +23,11 @@
import com.android.internal.os.BatterySipper;
import com.android.internal.os.BatteryStatsHelper;
-import com.android.settings.Utils;
import com.android.settings.fuelgauge.BatteryUtils;
import com.android.settings.fuelgauge.batterytip.BatteryTipPolicy;
-import com.android.settings.fuelgauge.batterytip.HighUsageApp;
+import com.android.settings.fuelgauge.batterytip.AppInfo;
import com.android.settings.fuelgauge.batterytip.tips.BatteryTip;
import com.android.settings.fuelgauge.batterytip.tips.HighUsageTip;
-import com.android.settings.fuelgauge.batterytip.tips.SummaryTip;
import java.util.ArrayList;
import java.util.Collections;
@@ -42,7 +40,7 @@
public class HighUsageDetector implements BatteryTipDetector {
private BatteryTipPolicy mPolicy;
private BatteryStatsHelper mBatteryStatsHelper;
- private List<HighUsageApp> mHighUsageAppList;
+ private List<AppInfo> mHighUsageAppList;
private Context mContext;
@VisibleForTesting
BatteryUtils mBatteryUtils;
@@ -68,9 +66,10 @@
final long foregroundTimeMs = mBatteryUtils.getProcessTimeMs(
BatteryUtils.StatusType.FOREGROUND, batterySipper.uidObj,
BatteryStats.STATS_SINCE_CHARGED);
- mHighUsageAppList.add(new HighUsageApp(
- mBatteryUtils.getPackageName(batterySipper.getUid()),
- foregroundTimeMs));
+ mHighUsageAppList.add(new AppInfo.Builder()
+ .setPackageName(mBatteryUtils.getPackageName(batterySipper.getUid()))
+ .setScreenOnTimeMs(foregroundTimeMs)
+ .build());
}
}
diff --git a/src/com/android/settings/fuelgauge/batterytip/tips/HighUsageTip.java b/src/com/android/settings/fuelgauge/batterytip/tips/HighUsageTip.java
index 0316832..2aabf98 100644
--- a/src/com/android/settings/fuelgauge/batterytip/tips/HighUsageTip.java
+++ b/src/com/android/settings/fuelgauge/batterytip/tips/HighUsageTip.java
@@ -23,7 +23,7 @@
import com.android.settings.R;
import com.android.settings.Utils;
-import com.android.settings.fuelgauge.batterytip.HighUsageApp;
+import com.android.settings.fuelgauge.batterytip.AppInfo;
import java.util.List;
@@ -34,9 +34,9 @@
private final long mScreenTimeMs;
@VisibleForTesting
- final List<HighUsageApp> mHighUsageAppList;
+ final List<AppInfo> mHighUsageAppList;
- public HighUsageTip(long screenTimeMs, List<HighUsageApp> appList) {
+ public HighUsageTip(long screenTimeMs, List<AppInfo> appList) {
super(TipType.HIGH_DEVICE_USAGE, appList.isEmpty() ? StateType.INVISIBLE : StateType.NEW,
true /* showDialog */);
mScreenTimeMs = screenTimeMs;
@@ -47,7 +47,7 @@
HighUsageTip(Parcel in) {
super(in);
mScreenTimeMs = in.readLong();
- mHighUsageAppList = in.createTypedArrayList(HighUsageApp.CREATOR);
+ mHighUsageAppList = in.createTypedArrayList(AppInfo.CREATOR);
}
@Override
@@ -82,7 +82,7 @@
return mScreenTimeMs;
}
- public List<HighUsageApp> getHighUsageAppList() {
+ public List<AppInfo> getHighUsageAppList() {
return mHighUsageAppList;
}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryDatabaseManagerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryDatabaseManagerTest.java
new file mode 100644
index 0000000..ac8800e
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryDatabaseManagerTest.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2018 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;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.spy;
+
+import android.content.Context;
+import android.text.format.DateUtils;
+
+import com.android.settings.TestConfig;
+import com.android.settings.fuelgauge.batterytip.AppInfo;
+import com.android.settings.fuelgauge.batterytip.BatteryDatabaseManager;
+import com.android.settings.testutils.DatabaseTestUtils;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+
+import java.util.List;
+
+@RunWith(RobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public class BatteryDatabaseManagerTest {
+ private static String PACKAGE_NAME_NEW = "com.android.app1";
+ private static int TYPE_NEW = 1;
+ private static String PACKAGE_NAME_OLD = "com.android.app2";
+ private static int TYPE_OLD = 2;
+ private static long NOW = System.currentTimeMillis();
+ private static long ONE_DAY_BEFORE = NOW - DateUtils.DAY_IN_MILLIS;
+ private static long TWO_DAYS_BEFORE = NOW - 2 * DateUtils.DAY_IN_MILLIS;
+ private Context mContext;
+ private BatteryDatabaseManager mBatteryDatabaseManager;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
+ mContext = RuntimeEnvironment.application;
+ mBatteryDatabaseManager = spy(new BatteryDatabaseManager(mContext));
+ }
+
+ @After
+ public void cleanUp() {
+ DatabaseTestUtils.clearDb(mContext);
+ }
+
+ @Test
+ public void testAllFunctions() {
+ mBatteryDatabaseManager.insertAnomaly(PACKAGE_NAME_NEW, TYPE_NEW, NOW);
+ mBatteryDatabaseManager.insertAnomaly(PACKAGE_NAME_OLD, TYPE_OLD, TWO_DAYS_BEFORE);
+
+ // In database, it contains two record
+ List<AppInfo> totalAppInfos = mBatteryDatabaseManager.queryAllAnomaliesAfter(0);
+ assertThat(totalAppInfos).hasSize(2);
+ verifyAppInfo(totalAppInfos.get(0), PACKAGE_NAME_NEW, TYPE_NEW);
+ verifyAppInfo(totalAppInfos.get(1), PACKAGE_NAME_OLD, TYPE_OLD);
+
+ // Only one record shows up if we query by timestamp
+ List<AppInfo> appInfos = mBatteryDatabaseManager.queryAllAnomaliesAfter(ONE_DAY_BEFORE);
+ assertThat(appInfos).hasSize(1);
+ verifyAppInfo(appInfos.get(0), PACKAGE_NAME_NEW, TYPE_NEW);
+
+ mBatteryDatabaseManager.deleteAllAnomaliesBeforeTimeStamp(ONE_DAY_BEFORE);
+
+ // The obsolete record is removed from database
+ List<AppInfo> appInfos1 = mBatteryDatabaseManager.queryAllAnomaliesAfter(0);
+ assertThat(appInfos1).hasSize(1);
+ verifyAppInfo(appInfos1.get(0), PACKAGE_NAME_NEW, TYPE_NEW);
+
+ }
+
+ private void verifyAppInfo(final AppInfo appInfo, String packageName, int type) {
+ assertThat(appInfo.packageName).isEqualTo(packageName);
+ assertThat(appInfo.anomalyType).isEqualTo(type);
+ }
+
+}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/AppInfoTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/AppInfoTest.java
new file mode 100644
index 0000000..16b45df
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/AppInfoTest.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2018 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.batterytip;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.os.Parcel;
+import android.text.format.DateUtils;
+
+import com.android.settings.TestConfig;
+import com.android.settings.fuelgauge.anomaly.Anomaly;
+import com.android.settings.testutils.SettingsRobolectricTestRunner;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.annotation.Config;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public class AppInfoTest {
+ private static final String PACKAGE_NAME = "com.android.app";
+ private static final int ANOMALY_TYPE = Anomaly.AnomalyType.WAKE_LOCK;
+ private static final long SCREEN_TIME_MS = DateUtils.HOUR_IN_MILLIS;
+
+ private AppInfo mAppInfo;
+
+ @Before
+ public void setUp() {
+ mAppInfo = new AppInfo.Builder()
+ .setPackageName(PACKAGE_NAME)
+ .setAnomalyType(ANOMALY_TYPE)
+ .setScreenOnTimeMs(SCREEN_TIME_MS)
+ .build();
+ }
+
+ @Test
+ public void testParcel() {
+ Parcel parcel = Parcel.obtain();
+ mAppInfo.writeToParcel(parcel, mAppInfo.describeContents());
+ parcel.setDataPosition(0);
+
+ final AppInfo appInfo = new AppInfo(parcel);
+
+ assertThat(appInfo.packageName).isEqualTo(PACKAGE_NAME);
+ assertThat(appInfo.anomalyType).isEqualTo(ANOMALY_TYPE);
+ assertThat(appInfo.screenOnTimeMs).isEqualTo(SCREEN_TIME_MS);
+ }
+
+ @Test
+ public void testCompareTo_hasCorrectOrder() {
+ final AppInfo appInfo = new AppInfo.Builder()
+ .setPackageName(PACKAGE_NAME)
+ .setAnomalyType(ANOMALY_TYPE)
+ .setScreenOnTimeMs(SCREEN_TIME_MS + 100)
+ .build();
+
+ List<AppInfo> appInfos = new ArrayList<>();
+ appInfos.add(appInfo);
+ appInfos.add(mAppInfo);
+
+ Collections.sort(appInfos);
+ assertThat(appInfos.get(0).screenOnTimeMs).isLessThan(appInfos.get(1).screenOnTimeMs);
+ }
+
+ @Test
+ public void testBuilder() {
+ assertThat(mAppInfo.packageName).isEqualTo(PACKAGE_NAME);
+ assertThat(mAppInfo.anomalyType).isEqualTo(ANOMALY_TYPE);
+ assertThat(mAppInfo.screenOnTimeMs).isEqualTo(SCREEN_TIME_MS);
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/HighUsageTipTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/HighUsageTipTest.java
index e2f8a26..0689778 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/HighUsageTipTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/HighUsageTipTest.java
@@ -22,7 +22,7 @@
import android.text.format.DateUtils;
import com.android.settings.TestConfig;
-import com.android.settings.fuelgauge.batterytip.HighUsageApp;
+import com.android.settings.fuelgauge.batterytip.AppInfo;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import org.junit.Before;
@@ -42,14 +42,17 @@
private Context mContext;
private HighUsageTip mBatteryTip;
- private List<HighUsageApp> mUsageAppList;
+ private List<AppInfo> mUsageAppList;
@Before
public void setUp() {
mContext = RuntimeEnvironment.application;
mUsageAppList = new ArrayList<>();
- mUsageAppList.add(new HighUsageApp(PACKAGE_NAME, SCREEN_TIME));
+ mUsageAppList.add(new AppInfo.Builder()
+ .setPackageName(PACKAGE_NAME)
+ .setScreenOnTimeMs(SCREEN_TIME)
+ .build());
mBatteryTip = new HighUsageTip(SCREEN_TIME, mUsageAppList);
}
@@ -67,7 +70,7 @@
assertThat(parcelTip.getState()).isEqualTo(BatteryTip.StateType.NEW);
assertThat(parcelTip.getScreenTimeMs()).isEqualTo(SCREEN_TIME);
assertThat(parcelTip.mHighUsageAppList.size()).isEqualTo(1);
- final HighUsageApp app = parcelTip.mHighUsageAppList.get(0);
+ final AppInfo app = parcelTip.mHighUsageAppList.get(0);
assertThat(app.packageName).isEqualTo(PACKAGE_NAME);
assertThat(app.screenOnTimeMs).isEqualTo(SCREEN_TIME);
}
diff --git a/tests/robotests/src/com/android/settings/testutils/DatabaseTestUtils.java b/tests/robotests/src/com/android/settings/testutils/DatabaseTestUtils.java
index 11e740a..499a2f7 100644
--- a/tests/robotests/src/com/android/settings/testutils/DatabaseTestUtils.java
+++ b/tests/robotests/src/com/android/settings/testutils/DatabaseTestUtils.java
@@ -18,6 +18,7 @@
import android.content.Context;
+import com.android.settings.fuelgauge.batterytip.AnomalyDatabaseHelper;
import com.android.settings.search.IndexDatabaseHelper;
import com.android.settings.slices.SlicesDatabaseHelper;
@@ -28,6 +29,7 @@
public static void clearDb(Context context) {
clearSearchDb(context);
clearSlicesDb(context);
+ clearAnomalyDb(context);
}
private static void clearSlicesDb(Context context) {
@@ -45,6 +47,21 @@
}
}
+ private static void clearAnomalyDb(Context context) {
+ AnomalyDatabaseHelper helper = AnomalyDatabaseHelper.getInstance(context);
+ helper.close();
+
+ Field instance;
+ Class clazz = AnomalyDatabaseHelper.class;
+ try {
+ instance = clazz.getDeclaredField("sSingleton");
+ instance.setAccessible(true);
+ instance.set(null, null);
+ } catch (Exception e) {
+ throw new RuntimeException();
+ }
+ }
+
private static void clearSearchDb(Context context) {
IndexDatabaseHelper helper = IndexDatabaseHelper.getInstance(context);
helper.close();