Framework for the anomaly detection.
This cl adds the following components for anomaly dection: 1. AnomalyLoader: run all the anomaly checks in the background 2. Anomaly: Data class to represent what anomaly it is 3. Detector: Different kinds of anomaly detector with common interface 4. Action: Suggestions when facing anomaly(Force stop, uninstall) 5. AnomalyDialogFragment: show the confirm dialog for action 6. AnomalyPreferenceController: handle update and click for anomalyPreference, since it will be used in multiple fragments. 7. AnomalyUtils: utility class for anomaly This cl also adds skeleton for the wakelock check and action. Following cls will add real implementation about it. Bug: 36924669 Test: RunSettingsRoboTests Change-Id: I89fc4b6963757869b93791b4275ca53c04ab9604
This commit is contained in:
@@ -25,6 +25,9 @@
|
|||||||
android:selectable="true"
|
android:selectable="true"
|
||||||
android:layout="@layout/battery_header"/>
|
android:layout="@layout/battery_header"/>
|
||||||
|
|
||||||
|
<Preference
|
||||||
|
android:key="high_usage"/>
|
||||||
|
|
||||||
<PreferenceCategory
|
<PreferenceCategory
|
||||||
android:key="device_usage_list">
|
android:key="device_usage_list">
|
||||||
|
|
||||||
|
@@ -17,9 +17,11 @@
|
|||||||
package com.android.settings.fuelgauge;
|
package com.android.settings.fuelgauge;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
|
import android.app.LoaderManager;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.IntentFilter;
|
import android.content.IntentFilter;
|
||||||
|
import android.content.Loader;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
import android.os.BatteryStats;
|
import android.os.BatteryStats;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
@@ -59,6 +61,10 @@ import com.android.settings.dashboard.SummaryLoader;
|
|||||||
import com.android.settings.display.AutoBrightnessPreferenceController;
|
import com.android.settings.display.AutoBrightnessPreferenceController;
|
||||||
import com.android.settings.display.BatteryPercentagePreferenceController;
|
import com.android.settings.display.BatteryPercentagePreferenceController;
|
||||||
import com.android.settings.display.TimeoutPreferenceController;
|
import com.android.settings.display.TimeoutPreferenceController;
|
||||||
|
import com.android.settings.fuelgauge.anomaly.Anomaly;
|
||||||
|
import com.android.settings.fuelgauge.anomaly.AnomalyDialogFragment;
|
||||||
|
import com.android.settings.fuelgauge.anomaly.AnomalyLoader;
|
||||||
|
import com.android.settings.fuelgauge.anomaly.AnomalyPreferenceController;
|
||||||
import com.android.settings.overlay.FeatureFactory;
|
import com.android.settings.overlay.FeatureFactory;
|
||||||
import com.android.settings.search.BaseSearchIndexProvider;
|
import com.android.settings.search.BaseSearchIndexProvider;
|
||||||
import com.android.settings.widget.FooterPreferenceMixin;
|
import com.android.settings.widget.FooterPreferenceMixin;
|
||||||
@@ -74,7 +80,8 @@ import java.util.List;
|
|||||||
* Displays a list of apps and subsystems that consume power, ordered by how much power was
|
* Displays a list of apps and subsystems that consume power, ordered by how much power was
|
||||||
* consumed since the last time it was unplugged.
|
* consumed since the last time it was unplugged.
|
||||||
*/
|
*/
|
||||||
public class PowerUsageSummary extends PowerUsageBase {
|
public class PowerUsageSummary extends PowerUsageBase implements
|
||||||
|
AnomalyDialogFragment.AnomalyDialogListener {
|
||||||
|
|
||||||
static final String TAG = "PowerUsageSummary";
|
static final String TAG = "PowerUsageSummary";
|
||||||
|
|
||||||
@@ -84,6 +91,7 @@ public class PowerUsageSummary extends PowerUsageBase {
|
|||||||
private static final String KEY_BATTERY_HEADER = "battery_header";
|
private static final String KEY_BATTERY_HEADER = "battery_header";
|
||||||
private static final int MAX_ITEMS_TO_LIST = USE_FAKE_DATA ? 30 : 10;
|
private static final int MAX_ITEMS_TO_LIST = USE_FAKE_DATA ? 30 : 10;
|
||||||
private static final int MIN_AVERAGE_POWER_THRESHOLD_MILLI_AMP = 10;
|
private static final int MIN_AVERAGE_POWER_THRESHOLD_MILLI_AMP = 10;
|
||||||
|
private static final int ANOMALY_LOADER = 1;
|
||||||
|
|
||||||
private static final String KEY_SCREEN_USAGE = "screen_usage";
|
private static final String KEY_SCREEN_USAGE = "screen_usage";
|
||||||
private static final String KEY_TIME_SINCE_LAST_FULL_CHARGE = "last_full_charge";
|
private static final String KEY_TIME_SINCE_LAST_FULL_CHARGE = "last_full_charge";
|
||||||
@@ -117,8 +125,29 @@ public class PowerUsageSummary extends PowerUsageBase {
|
|||||||
|
|
||||||
private LayoutPreference mBatteryLayoutPref;
|
private LayoutPreference mBatteryLayoutPref;
|
||||||
private PreferenceGroup mAppListGroup;
|
private PreferenceGroup mAppListGroup;
|
||||||
|
private AnomalyPreferenceController mAnomalyPreferenceController;
|
||||||
private int mStatsType = BatteryStats.STATS_SINCE_CHARGED;
|
private int mStatsType = BatteryStats.STATS_SINCE_CHARGED;
|
||||||
|
|
||||||
|
private LoaderManager.LoaderCallbacks<List<Anomaly>> mAnomalyLoaderCallbacks =
|
||||||
|
new LoaderManager.LoaderCallbacks<List<Anomaly>>() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Loader<List<Anomaly>> onCreateLoader(int id, Bundle args) {
|
||||||
|
return new AnomalyLoader(getContext(), mStatsHelper);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onLoadFinished(Loader<List<Anomaly>> loader, List<Anomaly> data) {
|
||||||
|
// show high usage preference if possible
|
||||||
|
mAnomalyPreferenceController.updateAnomalyPreference(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onLoaderReset(Loader<List<Anomaly>> loader) {
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle icicle) {
|
public void onCreate(Bundle icicle) {
|
||||||
super.onCreate(icicle);
|
super.onCreate(icicle);
|
||||||
@@ -130,6 +159,7 @@ public class PowerUsageSummary extends PowerUsageBase {
|
|||||||
mLastFullChargePref = (PowerGaugePreference) findPreference(
|
mLastFullChargePref = (PowerGaugePreference) findPreference(
|
||||||
KEY_TIME_SINCE_LAST_FULL_CHARGE);
|
KEY_TIME_SINCE_LAST_FULL_CHARGE);
|
||||||
mFooterPreferenceMixin.createFooterPreference().setTitle(R.string.battery_footer_summary);
|
mFooterPreferenceMixin.createFooterPreference().setTitle(R.string.battery_footer_summary);
|
||||||
|
mAnomalyPreferenceController = new AnomalyPreferenceController(this);
|
||||||
|
|
||||||
mBatteryUtils = BatteryUtils.getInstance(getContext());
|
mBatteryUtils = BatteryUtils.getInstance(getContext());
|
||||||
|
|
||||||
@@ -163,6 +193,9 @@ public class PowerUsageSummary extends PowerUsageBase {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onPreferenceTreeClick(Preference preference) {
|
public boolean onPreferenceTreeClick(Preference preference) {
|
||||||
|
if (mAnomalyPreferenceController.onPreferenceTreeClick(preference)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
if (KEY_BATTERY_HEADER.equals(preference.getKey())) {
|
if (KEY_BATTERY_HEADER.equals(preference.getKey())) {
|
||||||
performBatteryHeaderClick();
|
performBatteryHeaderClick();
|
||||||
return true;
|
return true;
|
||||||
@@ -403,6 +436,8 @@ public class PowerUsageSummary extends PowerUsageBase {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getLoaderManager().initLoader(ANOMALY_LOADER, null, mAnomalyLoaderCallbacks);
|
||||||
|
|
||||||
cacheRemoveAllPrefs(mAppListGroup);
|
cacheRemoveAllPrefs(mAppListGroup);
|
||||||
mAppListGroup.setOrderingAsAdded(false);
|
mAppListGroup.setOrderingAsAdded(false);
|
||||||
boolean addedSome = false;
|
boolean addedSome = false;
|
||||||
@@ -690,6 +725,11 @@ public class PowerUsageSummary extends PowerUsageBase {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAnomalyHandled(Anomaly anomaly) {
|
||||||
|
mAnomalyPreferenceController.hideAnomalyPreference();
|
||||||
|
}
|
||||||
|
|
||||||
private static class SummaryProvider implements SummaryLoader.SummaryProvider {
|
private static class SummaryProvider implements SummaryLoader.SummaryProvider {
|
||||||
private final Context mContext;
|
private final Context mContext;
|
||||||
private final SummaryLoader mLoader;
|
private final SummaryLoader mLoader;
|
||||||
|
136
src/com/android/settings/fuelgauge/anomaly/Anomaly.java
Normal file
136
src/com/android/settings/fuelgauge/anomaly/Anomaly.java
Normal file
@@ -0,0 +1,136 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2017 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.anomaly;
|
||||||
|
|
||||||
|
import android.os.Parcel;
|
||||||
|
import android.os.Parcelable;
|
||||||
|
import android.support.annotation.IntDef;
|
||||||
|
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data that represents an app has been detected as anomaly. It contains
|
||||||
|
*
|
||||||
|
* 1. Basic information of the app(i.e. uid, package name)
|
||||||
|
* 2. Type of anomaly
|
||||||
|
* 3. Data that has been detected as anomaly(i.e wakelock time)
|
||||||
|
*/
|
||||||
|
public class Anomaly implements Parcelable {
|
||||||
|
@Retention(RetentionPolicy.SOURCE)
|
||||||
|
@IntDef({AnomalyType.WAKE_LOCK})
|
||||||
|
public @interface AnomalyType {
|
||||||
|
int WAKE_LOCK = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Retention(RetentionPolicy.SOURCE)
|
||||||
|
@IntDef({AnomalyActionType.FORCE_STOP})
|
||||||
|
public @interface AnomalyActionType {
|
||||||
|
int FORCE_STOP = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Type of this this anomaly
|
||||||
|
*/
|
||||||
|
public final int type;
|
||||||
|
public final int uid;
|
||||||
|
public final long wakelockTimeMs;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display name of this anomaly, usually it is the app name
|
||||||
|
*/
|
||||||
|
public final String displayName;
|
||||||
|
public final String packageName;
|
||||||
|
|
||||||
|
private Anomaly(Builder builder) {
|
||||||
|
type = builder.mType;
|
||||||
|
uid = builder.mUid;
|
||||||
|
displayName = builder.mDisplayName;
|
||||||
|
packageName = builder.mPackageName;
|
||||||
|
wakelockTimeMs = builder.mWakeLockTimeMs;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Anomaly(Parcel in) {
|
||||||
|
type = in.readInt();
|
||||||
|
uid = in.readInt();
|
||||||
|
displayName = in.readString();
|
||||||
|
packageName = in.readString();
|
||||||
|
wakelockTimeMs = in.readLong();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int describeContents() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeToParcel(Parcel dest, int flags) {
|
||||||
|
dest.writeInt(type);
|
||||||
|
dest.writeInt(uid);
|
||||||
|
dest.writeString(displayName);
|
||||||
|
dest.writeString(packageName);
|
||||||
|
dest.writeLong(wakelockTimeMs);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
|
||||||
|
public Anomaly createFromParcel(Parcel in) {
|
||||||
|
return new Anomaly(in);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Anomaly[] newArray(int size) {
|
||||||
|
return new Anomaly[size];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public static final class Builder {
|
||||||
|
@AnomalyType
|
||||||
|
private int mType;
|
||||||
|
private int mUid;
|
||||||
|
private String mDisplayName;
|
||||||
|
private String mPackageName;
|
||||||
|
private long mWakeLockTimeMs;
|
||||||
|
|
||||||
|
public Builder setType(@AnomalyType int type) {
|
||||||
|
mType = type;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder setUid(int uid) {
|
||||||
|
mUid = uid;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder setDisplayName(String displayName) {
|
||||||
|
mDisplayName = displayName;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder setPackageName(String packageName) {
|
||||||
|
mPackageName = packageName;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder setWakeLockTimeMs(long wakeLockTimeMs) {
|
||||||
|
mWakeLockTimeMs = wakeLockTimeMs;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Anomaly build() {
|
||||||
|
return new Anomaly(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,103 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2017 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.anomaly;
|
||||||
|
|
||||||
|
import android.app.AlertDialog;
|
||||||
|
import android.app.Dialog;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.DialogInterface;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.support.annotation.VisibleForTesting;
|
||||||
|
|
||||||
|
import com.android.settings.R;
|
||||||
|
import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
|
||||||
|
import com.android.settings.fuelgauge.anomaly.action.AnomalyAction;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dialog Fragment to show action dialog for each anomaly
|
||||||
|
*/
|
||||||
|
public class AnomalyDialogFragment extends InstrumentedDialogFragment implements
|
||||||
|
DialogInterface.OnClickListener {
|
||||||
|
|
||||||
|
private static final String ARG_ANOMALY = "anomaly";
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
Anomaly mAnomaly;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Listener to give the control back to target fragment
|
||||||
|
*/
|
||||||
|
public interface AnomalyDialogListener {
|
||||||
|
/**
|
||||||
|
* This method is invoked once anomaly is handled, then target fragment could do
|
||||||
|
* extra work. One example is that fragment could remove the anomaly preference
|
||||||
|
* since it has been handled
|
||||||
|
*
|
||||||
|
* @param anomaly that has been handled
|
||||||
|
*/
|
||||||
|
void onAnomalyHandled(Anomaly anomaly);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static AnomalyDialogFragment newInstance(Anomaly anomaly) {
|
||||||
|
AnomalyDialogFragment dialogFragment = new AnomalyDialogFragment();
|
||||||
|
|
||||||
|
Bundle args = new Bundle(1);
|
||||||
|
args.putParcelable(ARG_ANOMALY, anomaly);
|
||||||
|
dialogFragment.setArguments(args);
|
||||||
|
|
||||||
|
return dialogFragment;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getMetricsCategory() {
|
||||||
|
// TODO(b/37681923): add anomaly metric id
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
|
final AnomalyDialogListener lsn = (AnomalyDialogListener) getTargetFragment();
|
||||||
|
if (lsn == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final AnomalyAction anomalyAction = AnomalyUtils.getAnomalyAction(mAnomaly.type);
|
||||||
|
anomalyAction.handlePositiveAction(mAnomaly.packageName);
|
||||||
|
lsn.onAnomalyHandled(mAnomaly);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||||
|
final Bundle bundle = getArguments();
|
||||||
|
mAnomaly = bundle.getParcelable(ARG_ANOMALY);
|
||||||
|
|
||||||
|
final Context context = getContext();
|
||||||
|
final AnomalyAction anomalyAction = AnomalyUtils.getAnomalyAction(mAnomaly.type);
|
||||||
|
switch (anomalyAction.getActionType()) {
|
||||||
|
case Anomaly.AnomalyActionType.FORCE_STOP:
|
||||||
|
return new AlertDialog.Builder(context)
|
||||||
|
.setTitle(R.string.force_stop_dlg_title)
|
||||||
|
.setMessage(R.string.force_stop_dlg_text)
|
||||||
|
.setPositiveButton(R.string.dlg_ok, this)
|
||||||
|
.setNegativeButton(R.string.dlg_cancel, null)
|
||||||
|
.create();
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException("unknown type " + mAnomaly.type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2017 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.anomaly;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
|
||||||
|
import com.android.internal.os.BatteryStatsHelper;
|
||||||
|
import com.android.settings.fuelgauge.anomaly.checker.WakeLockAnomalyDetector;
|
||||||
|
import com.android.settings.utils.AsyncLoader;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loader to compute which apps are anomaly and return a anomaly list. It will return
|
||||||
|
* an empty list if there is no anomaly.
|
||||||
|
*/
|
||||||
|
//TODO(b/36924669): add test for this file, for now it seems there is nothing to test
|
||||||
|
public class AnomalyLoader extends AsyncLoader<List<Anomaly>> {
|
||||||
|
private BatteryStatsHelper mBatteryStatsHelper;
|
||||||
|
|
||||||
|
public AnomalyLoader(Context context, BatteryStatsHelper batteryStatsHelper) {
|
||||||
|
super(context);
|
||||||
|
mBatteryStatsHelper = batteryStatsHelper;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onDiscardResult(List<Anomaly> result) {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Anomaly> loadInBackground() {
|
||||||
|
final List<Anomaly> anomalies = new ArrayList<>();
|
||||||
|
anomalies.addAll(new WakeLockAnomalyDetector().detectAnomalies(mBatteryStatsHelper));
|
||||||
|
|
||||||
|
return anomalies;
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,76 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2017 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.anomaly;
|
||||||
|
|
||||||
|
import android.support.annotation.VisibleForTesting;
|
||||||
|
import android.support.v14.preference.PreferenceFragment;
|
||||||
|
import android.support.v7.preference.Preference;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Manager that responsible for updating anomaly preference and handling preference click.
|
||||||
|
*/
|
||||||
|
public class AnomalyPreferenceController {
|
||||||
|
private static final String TAG = "AnomalyPreferenceController";
|
||||||
|
@VisibleForTesting
|
||||||
|
static final String ANOMALY_KEY = "high_usage";
|
||||||
|
private static final int REQUEST_ANOMALY_ACTION = 0;
|
||||||
|
private PreferenceFragment mFragment;
|
||||||
|
@VisibleForTesting
|
||||||
|
Preference mAnomalyPreference;
|
||||||
|
@VisibleForTesting
|
||||||
|
List<Anomaly> mAnomalies;
|
||||||
|
|
||||||
|
public AnomalyPreferenceController(PreferenceFragment fragment) {
|
||||||
|
mFragment = fragment;
|
||||||
|
mAnomalyPreference = mFragment.getPreferenceScreen().findPreference(ANOMALY_KEY);
|
||||||
|
hideAnomalyPreference();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean onPreferenceTreeClick(Preference preference) {
|
||||||
|
if (mAnomalies != null && ANOMALY_KEY.equals(preference.getKey())) {
|
||||||
|
if (mAnomalies.size() == 1) {
|
||||||
|
final Anomaly anomaly = mAnomalies.get(0);
|
||||||
|
AnomalyDialogFragment dialogFragment = AnomalyDialogFragment.newInstance(anomaly);
|
||||||
|
dialogFragment.setTargetFragment(mFragment, REQUEST_ANOMALY_ACTION);
|
||||||
|
dialogFragment.show(mFragment.getFragmentManager(), TAG);
|
||||||
|
} else {
|
||||||
|
//TODO(b/37681665): start a new fragment to handle it
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update anomaly preference based on {@code anomalies}, also store a reference
|
||||||
|
* of {@paramref anomalies}, which would be used in {@link #onPreferenceTreeClick(Preference)}
|
||||||
|
*
|
||||||
|
* @param anomalies used to update the summary, this method will store a reference of it
|
||||||
|
*/
|
||||||
|
public void updateAnomalyPreference(List<Anomaly> anomalies) {
|
||||||
|
mAnomalies = anomalies;
|
||||||
|
|
||||||
|
mAnomalyPreference.setVisible(true);
|
||||||
|
//TODO(b/36924669): update summary for anomaly preference
|
||||||
|
}
|
||||||
|
|
||||||
|
public void hideAnomalyPreference() {
|
||||||
|
mAnomalyPreference.setVisible(false);
|
||||||
|
}
|
||||||
|
}
|
40
src/com/android/settings/fuelgauge/anomaly/AnomalyUtils.java
Normal file
40
src/com/android/settings/fuelgauge/anomaly/AnomalyUtils.java
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2017 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.anomaly;
|
||||||
|
|
||||||
|
import com.android.settings.fuelgauge.anomaly.action.AnomalyAction;
|
||||||
|
import com.android.settings.fuelgauge.anomaly.action.ForceStopAction;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utitily class for anomaly detection
|
||||||
|
*/
|
||||||
|
public class AnomalyUtils {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the corresponding {@link AnomalyAction} according to {@link AnomalyType}
|
||||||
|
*
|
||||||
|
* @return corresponding {@link AnomalyAction}, or null if cannot find it.
|
||||||
|
*/
|
||||||
|
public static final AnomalyAction getAnomalyAction(int anomalyType) {
|
||||||
|
switch (anomalyType) {
|
||||||
|
case Anomaly.AnomalyType.WAKE_LOCK:
|
||||||
|
return new ForceStopAction();
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,25 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2017 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.anomaly.action;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface for anomaly action, which is triggered if we need to handle the anomaly
|
||||||
|
*/
|
||||||
|
public interface AnomalyAction {
|
||||||
|
void handlePositiveAction(String packageName);
|
||||||
|
int getActionType();
|
||||||
|
}
|
@@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2017 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.anomaly.action;
|
||||||
|
|
||||||
|
import com.android.settings.fuelgauge.anomaly.Anomaly;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Force stop action for anomaly app, which means to stop the app which causes anomaly
|
||||||
|
*/
|
||||||
|
public class ForceStopAction implements AnomalyAction {
|
||||||
|
@Override
|
||||||
|
public void handlePositiveAction(String packageName) {
|
||||||
|
// force stop the package
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getActionType() {
|
||||||
|
return Anomaly.AnomalyActionType.FORCE_STOP;
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,27 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2017 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.anomaly.checker;
|
||||||
|
|
||||||
|
import com.android.internal.os.BatteryStatsHelper;
|
||||||
|
import com.android.settings.fuelgauge.anomaly.Anomaly;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public interface AnomalyDetector {
|
||||||
|
List<Anomaly> detectAnomalies(BatteryStatsHelper batteryStatsHelper);
|
||||||
|
}
|
@@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2017 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.anomaly.checker;
|
||||||
|
|
||||||
|
import com.android.internal.os.BatteryStatsHelper;
|
||||||
|
import com.android.settings.fuelgauge.anomaly.Anomaly;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check whether apps holding wakelock too long
|
||||||
|
*/
|
||||||
|
public class WakeLockAnomalyDetector implements AnomalyDetector {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Anomaly> detectAnomalies(BatteryStatsHelper batteryStatsHelper) {
|
||||||
|
//TODO(b/36921529): check anomaly using the batteryStatsHelper
|
||||||
|
final List<Anomaly> anomalies = new ArrayList<>();
|
||||||
|
return anomalies;
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,86 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2017 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.anomaly;
|
||||||
|
|
||||||
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
|
import static org.robolectric.Shadows.shadowOf;
|
||||||
|
|
||||||
|
import android.app.AlertDialog;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.DialogInterface;
|
||||||
|
|
||||||
|
import com.android.settings.R;
|
||||||
|
import com.android.settings.SettingsRobolectricTestRunner;
|
||||||
|
import com.android.settings.TestConfig;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.robolectric.RuntimeEnvironment;
|
||||||
|
import org.robolectric.annotation.Config;
|
||||||
|
import org.robolectric.shadows.ShadowAlertDialog;
|
||||||
|
import org.robolectric.shadows.ShadowDialog;
|
||||||
|
import org.robolectric.util.FragmentTestUtil;
|
||||||
|
|
||||||
|
@RunWith(SettingsRobolectricTestRunner.class)
|
||||||
|
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
|
||||||
|
public class AnomalyDialogFragmentTest {
|
||||||
|
@Anomaly.AnomalyType
|
||||||
|
private static final int ANOMALY_TYPE = Anomaly.AnomalyType.WAKE_LOCK;
|
||||||
|
private static final String PACKAGE_NAME = "com.android.app";
|
||||||
|
private static final int UID = 111;
|
||||||
|
private Anomaly mAnomaly;
|
||||||
|
private AnomalyDialogFragment mAnomalyDialogFragment;
|
||||||
|
private Context mContext;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
mContext = RuntimeEnvironment.application;
|
||||||
|
mAnomaly = new Anomaly.Builder()
|
||||||
|
.setType(ANOMALY_TYPE)
|
||||||
|
.setUid(UID)
|
||||||
|
.setPackageName(PACKAGE_NAME)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
mAnomalyDialogFragment = AnomalyDialogFragment.newInstance(mAnomaly);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testOnCreateDialog_hasCorrectData() {
|
||||||
|
FragmentTestUtil.startFragment(mAnomalyDialogFragment);
|
||||||
|
|
||||||
|
assertThat(mAnomalyDialogFragment.mAnomaly).isEqualTo(mAnomaly);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testOnCreateDialog_hasCorrectDialog() {
|
||||||
|
FragmentTestUtil.startFragment(mAnomalyDialogFragment);
|
||||||
|
|
||||||
|
final AlertDialog dialog = (AlertDialog) ShadowDialog.getLatestDialog();
|
||||||
|
ShadowAlertDialog shadowDialog = shadowOf(dialog);
|
||||||
|
|
||||||
|
assertThat(shadowDialog.getMessage()).isEqualTo(
|
||||||
|
mContext.getString(R.string.force_stop_dlg_text));
|
||||||
|
assertThat(shadowDialog.getTitle()).isEqualTo(
|
||||||
|
mContext.getString(R.string.force_stop_dlg_title));
|
||||||
|
assertThat(dialog.getButton(DialogInterface.BUTTON_POSITIVE).getText()).isEqualTo(
|
||||||
|
mContext.getString(R.string.dlg_ok));
|
||||||
|
assertThat(dialog.getButton(DialogInterface.BUTTON_NEGATIVE).getText()).isEqualTo(
|
||||||
|
mContext.getString(R.string.dlg_cancel));
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,126 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2017 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.anomaly;
|
||||||
|
|
||||||
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
|
import static org.mockito.Matchers.any;
|
||||||
|
import static org.mockito.Matchers.anyString;
|
||||||
|
import static org.mockito.Matchers.eq;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
import static org.robolectric.Shadows.shadowOf;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.app.AlertDialog;
|
||||||
|
import android.app.Fragment;
|
||||||
|
import android.app.FragmentManager;
|
||||||
|
import android.app.FragmentTransaction;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.DialogInterface;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.support.v14.preference.PreferenceFragment;
|
||||||
|
import android.support.v7.preference.Preference;
|
||||||
|
|
||||||
|
import com.android.settings.R;
|
||||||
|
import com.android.settings.Settings;
|
||||||
|
import com.android.settings.SettingsRobolectricTestRunner;
|
||||||
|
import com.android.settings.TestConfig;
|
||||||
|
import com.android.settings.core.PreferenceController;
|
||||||
|
import com.android.settings.dashboard.DashboardFragment;
|
||||||
|
import com.android.settings.fuelgauge.ButtonActionDialogFragmentTest;
|
||||||
|
import com.android.settings.testutils.shadow.SettingsShadowResources;
|
||||||
|
import com.android.settings.testutils.shadow.ShadowDynamicIndexableContentMonitor;
|
||||||
|
import com.android.settings.testutils.shadow.ShadowEventLogWriter;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.Answers;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.MockitoAnnotations;
|
||||||
|
import org.robolectric.RuntimeEnvironment;
|
||||||
|
import org.robolectric.annotation.Config;
|
||||||
|
import org.robolectric.shadows.ShadowAlertDialog;
|
||||||
|
import org.robolectric.shadows.ShadowDialog;
|
||||||
|
import org.robolectric.util.FragmentTestUtil;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@RunWith(SettingsRobolectricTestRunner.class)
|
||||||
|
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
|
||||||
|
public class AnomalyPreferenceControllerTest {
|
||||||
|
@Anomaly.AnomalyType
|
||||||
|
private static final int ANOMALY_TYPE = Anomaly.AnomalyType.WAKE_LOCK;
|
||||||
|
private static final String PACKAGE_NAME = "com.android.app";
|
||||||
|
private static final int UID = 111;
|
||||||
|
|
||||||
|
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
|
||||||
|
private PreferenceFragment mFragment;
|
||||||
|
@Mock
|
||||||
|
private FragmentManager mFragmentManager;
|
||||||
|
@Mock
|
||||||
|
private FragmentTransaction mFragmentTransaction;
|
||||||
|
private AnomalyPreferenceController mAnomalyPreferenceController;
|
||||||
|
private Preference mPreference;
|
||||||
|
private Context mContext;
|
||||||
|
private List<Anomaly> mAnomalyList;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
MockitoAnnotations.initMocks(this);
|
||||||
|
|
||||||
|
mContext = RuntimeEnvironment.application;
|
||||||
|
mPreference = new Preference(mContext);
|
||||||
|
mPreference.setKey(AnomalyPreferenceController.ANOMALY_KEY);
|
||||||
|
when(mFragment.getPreferenceManager().findPreference(any())).thenReturn(mPreference);
|
||||||
|
when(mFragment.getFragmentManager()).thenReturn(mFragmentManager);
|
||||||
|
when(mFragmentManager.beginTransaction()).thenReturn(mFragmentTransaction);
|
||||||
|
|
||||||
|
mAnomalyList = new ArrayList<>();
|
||||||
|
Anomaly anomaly = new Anomaly.Builder()
|
||||||
|
.setType(ANOMALY_TYPE)
|
||||||
|
.setUid(UID)
|
||||||
|
.setPackageName(PACKAGE_NAME)
|
||||||
|
.build();
|
||||||
|
mAnomalyList.add(anomaly);
|
||||||
|
|
||||||
|
mAnomalyPreferenceController = new AnomalyPreferenceController(mFragment);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUpdateAnomalyPreference_hasCorrectData() {
|
||||||
|
mAnomalyPreferenceController.updateAnomalyPreference(mAnomalyList);
|
||||||
|
|
||||||
|
//add more test when this method is complete
|
||||||
|
assertThat(mAnomalyPreferenceController.mAnomalies).isEqualTo(mAnomalyList);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testOnPreferenceTreeClick_oneAnomaly_showDialog() {
|
||||||
|
mAnomalyPreferenceController.mAnomalies = mAnomalyList;
|
||||||
|
|
||||||
|
mAnomalyPreferenceController.onPreferenceTreeClick(mPreference);
|
||||||
|
|
||||||
|
verify(mFragmentManager).beginTransaction();
|
||||||
|
verify(mFragmentTransaction).add(any(), anyString());
|
||||||
|
verify(mFragmentTransaction).commit();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,53 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2017 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.anomaly;
|
||||||
|
|
||||||
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
|
import com.android.settings.SettingsRobolectricTestRunner;
|
||||||
|
import com.android.settings.TestConfig;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.robolectric.annotation.Config;
|
||||||
|
|
||||||
|
@RunWith(SettingsRobolectricTestRunner.class)
|
||||||
|
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
|
||||||
|
public class AnomalyTest {
|
||||||
|
private static int TYPE = Anomaly.AnomalyType.WAKE_LOCK;
|
||||||
|
private static int UID = 111;
|
||||||
|
private static long WAKE_LOCK_TIME_MS = 1500;
|
||||||
|
private static String PACKAGE_NAME = "com.android.settings";
|
||||||
|
private static String DISPLAY_NAME = "settings";
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testBuilder_buildCorrectly() {
|
||||||
|
Anomaly anomaly = new Anomaly.Builder()
|
||||||
|
.setType(TYPE)
|
||||||
|
.setUid(UID)
|
||||||
|
.setWakeLockTimeMs(WAKE_LOCK_TIME_MS)
|
||||||
|
.setPackageName(PACKAGE_NAME)
|
||||||
|
.setDisplayName(DISPLAY_NAME)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
assertThat(anomaly.type).isEqualTo(TYPE);
|
||||||
|
assertThat(anomaly.uid).isEqualTo(UID);
|
||||||
|
assertThat(anomaly.wakelockTimeMs).isEqualTo(WAKE_LOCK_TIME_MS);
|
||||||
|
assertThat(anomaly.packageName).isEqualTo(PACKAGE_NAME);
|
||||||
|
assertThat(anomaly.displayName).isEqualTo(DISPLAY_NAME);
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2017 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.anomaly;
|
||||||
|
|
||||||
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
|
import com.android.settings.SettingsRobolectricTestRunner;
|
||||||
|
import com.android.settings.TestConfig;
|
||||||
|
import com.android.settings.fuelgauge.anomaly.action.ForceStopAction;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.robolectric.annotation.Config;
|
||||||
|
|
||||||
|
@RunWith(SettingsRobolectricTestRunner.class)
|
||||||
|
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
|
||||||
|
public class AnomalyUtilsTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetAnomalyAction_typeWakeLock_returnForceStop() {
|
||||||
|
assertThat(AnomalyUtils.getAnomalyAction(Anomaly.AnomalyType.WAKE_LOCK)).isInstanceOf(
|
||||||
|
ForceStopAction.class);
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user