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
This commit is contained in:
jackqdyulei
2018-01-16 10:12:40 -08:00
parent 80fa91891e
commit 963b7cca25
11 changed files with 534 additions and 83 deletions

View File

@@ -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);
}
}

View File

@@ -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);
}
}
}

View File

@@ -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)});
}
}
}

View File

@@ -39,7 +39,7 @@ public class HighUsageAdapter extends RecyclerView.Adapter<HighUsageAdapter.View
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 class HighUsageAdapter extends RecyclerView.Adapter<HighUsageAdapter.View
}
}
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 @@ public class HighUsageAdapter extends RecyclerView.Adapter<HighUsageAdapter.View
@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()));

View File

@@ -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];
}
};
}

View File

@@ -23,13 +23,11 @@ import android.text.format.DateUtils;
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 @@ import java.util.List;
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 @@ public class HighUsageDetector implements BatteryTipDetector {
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());
}
}

View File

@@ -23,7 +23,7 @@ import android.support.annotation.VisibleForTesting;
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 @@ public class HighUsageTip extends BatteryTip {
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 @@ public class HighUsageTip extends BatteryTip {
HighUsageTip(Parcel in) {
super(in);
mScreenTimeMs = in.readLong();
mHighUsageAppList = in.createTypedArrayList(HighUsageApp.CREATOR);
mHighUsageAppList = in.createTypedArrayList(AppInfo.CREATOR);
}
@Override
@@ -82,7 +82,7 @@ public class HighUsageTip extends BatteryTip {
return mScreenTimeMs;
}
public List<HighUsageApp> getHighUsageAppList() {
public List<AppInfo> getHighUsageAppList() {
return mHighUsageAppList;
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -22,7 +22,7 @@ import android.os.Parcel;
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 @@ public class HighUsageTipTest {
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 @@ public class HighUsageTipTest {
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);
}

View File

@@ -18,6 +18,7 @@ package com.android.settings.testutils;
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 class DatabaseTestUtils {
public static void clearDb(Context context) {
clearSearchDb(context);
clearSlicesDb(context);
clearAnomalyDb(context);
}
private static void clearSlicesDb(Context context) {
@@ -45,6 +47,21 @@ public class DatabaseTestUtils {
}
}
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();