Merge "Add database to store anomaly data"
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
101
src/com/android/settings/fuelgauge/batterytip/AppInfo.java
Normal file
101
src/com/android/settings/fuelgauge/batterytip/AppInfo.java
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
@@ -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)});
|
||||
}
|
||||
}
|
||||
}
|
@@ -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()));
|
||||
|
@@ -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];
|
||||
}
|
||||
};
|
||||
}
|
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -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;
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user