diff --git a/src/com/android/settings/fuelgauge/anomaly/action/AnomalyAction.java b/src/com/android/settings/fuelgauge/anomaly/action/AnomalyAction.java index 3344eb6329b..87212e7b6ca 100644 --- a/src/com/android/settings/fuelgauge/anomaly/action/AnomalyAction.java +++ b/src/com/android/settings/fuelgauge/anomaly/action/AnomalyAction.java @@ -16,26 +16,47 @@ package com.android.settings.fuelgauge.anomaly.action; +import android.content.Context; +import android.util.Pair; + +import com.android.internal.logging.nano.MetricsProto; +import com.android.settings.core.instrumentation.MetricsFeatureProvider; import com.android.settings.fuelgauge.anomaly.Anomaly; +import com.android.settings.overlay.FeatureFactory; /** - * Interface for anomaly action, which is triggered if we need to handle the anomaly + * Abstract class for anomaly action, which is triggered if we need to handle the anomaly */ -public interface AnomalyAction { +public abstract class AnomalyAction { + protected Context mContext; + protected int mActionMetricKey; + + private MetricsFeatureProvider mMetricsFeatureProvider; + + public AnomalyAction(Context context) { + mContext = context; + mMetricsFeatureProvider = FeatureFactory.getFactory(context).getMetricsFeatureProvider(); + } + /** * handle the action when user clicks positive button - * @param anomaly about the app that we need to handle - * @param metricsKey key for the page that invokes the action * + * @param anomaly about the app that we need to handle + * @param contextMetricsKey key for the page that invokes the action * @see com.android.internal.logging.nano.MetricsProto */ - void handlePositiveAction(Anomaly anomaly, int metricsKey); + public void handlePositiveAction(Anomaly anomaly, int contextMetricsKey) { + mMetricsFeatureProvider.action(mContext, mActionMetricKey, anomaly.packageName, + Pair.create(MetricsProto.MetricsEvent.FIELD_CONTEXT, contextMetricsKey)); + } /** * Check whether the action is active for {@code anomaly} + * * @param anomaly about the app that we need to handle * @return {@code true} if action is active, otherwise return {@code false} */ - boolean isActionActive(Anomaly anomaly); - int getActionType(); + public abstract boolean isActionActive(Anomaly anomaly); + + public abstract int getActionType(); } diff --git a/src/com/android/settings/fuelgauge/anomaly/action/BackgroundCheckAction.java b/src/com/android/settings/fuelgauge/anomaly/action/BackgroundCheckAction.java index 16fd0dfec5b..799bddcd85a 100644 --- a/src/com/android/settings/fuelgauge/anomaly/action/BackgroundCheckAction.java +++ b/src/com/android/settings/fuelgauge/anomaly/action/BackgroundCheckAction.java @@ -19,28 +19,26 @@ package com.android.settings.fuelgauge.anomaly.action; import android.app.AppOpsManager; import android.content.Context; -import com.android.settings.core.instrumentation.MetricsFeatureProvider; +import com.android.internal.logging.nano.MetricsProto; import com.android.settings.fuelgauge.anomaly.Anomaly; -import com.android.settings.overlay.FeatureFactory; /** * Background check action for anomaly app, which means to stop app running in the background */ -public class BackgroundCheckAction implements AnomalyAction { +public class BackgroundCheckAction extends AnomalyAction { - private Context mContext; - private MetricsFeatureProvider mMetricsFeatureProvider; private AppOpsManager mAppOpsManager; public BackgroundCheckAction(Context context) { - mContext = context; - mMetricsFeatureProvider = FeatureFactory.getFactory(context).getMetricsFeatureProvider(); + super(context); mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE); + mActionMetricKey = MetricsProto.MetricsEvent.ACTION_APP_BACKGROUND_CHECK; } @Override - public void handlePositiveAction(Anomaly anomaly, int metricsKey) { - // TODO(b/37681923): add metric log here if possible + public void handlePositiveAction(Anomaly anomaly, int contextMetricsKey) { + super.handlePositiveAction(anomaly, contextMetricsKey); + mAppOpsManager.setMode(AppOpsManager.OP_RUN_IN_BACKGROUND, anomaly.uid, anomaly.packageName, AppOpsManager.MODE_IGNORED); } diff --git a/src/com/android/settings/fuelgauge/anomaly/action/ForceStopAction.java b/src/com/android/settings/fuelgauge/anomaly/action/ForceStopAction.java index 557b2a9cf1e..fb7306a175c 100644 --- a/src/com/android/settings/fuelgauge/anomaly/action/ForceStopAction.java +++ b/src/com/android/settings/fuelgauge/anomaly/action/ForceStopAction.java @@ -21,43 +21,32 @@ import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.util.Log; -import android.util.Pair; import com.android.internal.logging.nano.MetricsProto; -import com.android.settings.core.instrumentation.MetricsFeatureProvider; import com.android.settings.fuelgauge.anomaly.Anomaly; -import com.android.settings.overlay.FeatureFactory; - -import java.util.List; /** * Force stop action for anomaly app, which means to stop the app which causes anomaly */ -public class ForceStopAction implements AnomalyAction { +public class ForceStopAction extends AnomalyAction { private static final String TAG = "ForceStopAction"; - private Context mContext; - private MetricsFeatureProvider mMetricsFeatureProvider; private ActivityManager mActivityManager; private PackageManager mPackageManager; public ForceStopAction(Context context) { - mContext = context; - mMetricsFeatureProvider = FeatureFactory.getFactory(context).getMetricsFeatureProvider(); + super(context); mActivityManager = (ActivityManager) context.getSystemService( Context.ACTIVITY_SERVICE); mPackageManager = context.getPackageManager(); + mActionMetricKey = MetricsProto.MetricsEvent.ACTION_APP_FORCE_STOP; } @Override - public void handlePositiveAction(Anomaly anomaly, int metricsKey) { - final String packageName = anomaly.packageName; - // force stop the package - mMetricsFeatureProvider.action(mContext, - MetricsProto.MetricsEvent.ACTION_APP_FORCE_STOP, packageName, - Pair.create(MetricsProto.MetricsEvent.FIELD_CONTEXT, metricsKey)); + public void handlePositiveAction(Anomaly anomaly, int contextMetricsKey) { + super.handlePositiveAction(anomaly, contextMetricsKey); - mActivityManager.forceStopPackage(packageName); + mActivityManager.forceStopPackage(anomaly.packageName); } @Override diff --git a/src/com/android/settings/fuelgauge/anomaly/action/LocationCheckAction.java b/src/com/android/settings/fuelgauge/anomaly/action/LocationCheckAction.java index 4205b6e702f..6779828e30b 100644 --- a/src/com/android/settings/fuelgauge/anomaly/action/LocationCheckAction.java +++ b/src/com/android/settings/fuelgauge/anomaly/action/LocationCheckAction.java @@ -20,28 +20,28 @@ import android.content.Context; import android.content.pm.permission.RuntimePermissionPresenter; import android.support.v4.content.PermissionChecker; -import com.android.settings.core.instrumentation.MetricsFeatureProvider; +import com.android.internal.logging.nano.MetricsProto; import com.android.settings.fuelgauge.anomaly.Anomaly; -import com.android.settings.overlay.FeatureFactory; /** * Location action for anomaly app, which means to turn off location permission for this app */ -public class LocationCheckAction implements AnomalyAction { +public class LocationCheckAction extends AnomalyAction { private static final String TAG = "LocationCheckAction"; private static final String LOCATION_PERMISSION = "android.permission-group.LOCATION"; - private final Context mContext; private final RuntimePermissionPresenter mRuntimePermissionPresenter; public LocationCheckAction(Context context) { - mContext = context; + super(context); mRuntimePermissionPresenter = RuntimePermissionPresenter.getInstance(context); + mActionMetricKey = MetricsProto.MetricsEvent.ACTION_APP_LOCATION_CHECK; } @Override - public void handlePositiveAction(Anomaly anomaly, int metricsKey) { + public void handlePositiveAction(Anomaly anomaly, int contextMetricsKey) { + super.handlePositiveAction(anomaly, contextMetricsKey); mRuntimePermissionPresenter.revokeRuntimePermission(anomaly.packageName, LOCATION_PERMISSION); } diff --git a/tests/robotests/src/com/android/settings/fuelgauge/anomaly/action/AnomalyActionTest.java b/tests/robotests/src/com/android/settings/fuelgauge/anomaly/action/AnomalyActionTest.java new file mode 100644 index 00000000000..8db1a8c36c6 --- /dev/null +++ b/tests/robotests/src/com/android/settings/fuelgauge/anomaly/action/AnomalyActionTest.java @@ -0,0 +1,98 @@ +/* + * 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 static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.verify; + +import android.app.AppOpsManager; +import android.content.Context; +import android.util.Pair; + +import com.android.internal.logging.nano.MetricsProto; +import com.android.settings.TestConfig; +import com.android.settings.fuelgauge.anomaly.Anomaly; +import com.android.settings.testutils.FakeFeatureFactory; +import com.android.settings.testutils.SettingsRobolectricTestRunner; + +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.annotation.Config; + +@RunWith(SettingsRobolectricTestRunner.class) +@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION) +public class AnomalyActionTest { + private static final String PACKAGE_NAME = "com.android.app"; + private static final int UID = 111; + private static final int ACTION_KEY = 2; + private static final int METRIC_KEY = 3; + + @Mock(answer = Answers.RETURNS_DEEP_STUBS) + private Context mContext; + @Mock + private AppOpsManager mAppOpsManagerr; + private Anomaly mAnomaly; + private TestAnomalyAction mTestAnomalyAction; + private FakeFeatureFactory mFeatureFactory; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + + FakeFeatureFactory.setupForTest(mContext); + mFeatureFactory = (FakeFeatureFactory) FakeFeatureFactory.getFactory(mContext); + doReturn(mAppOpsManagerr).when(mContext).getSystemService(Context.APP_OPS_SERVICE); + + mAnomaly = new Anomaly.Builder() + .setUid(UID) + .setPackageName(PACKAGE_NAME) + .build(); + mTestAnomalyAction = new TestAnomalyAction(mContext); + } + + @Test + public void testHandlePositiveAction_logAction() { + mTestAnomalyAction.handlePositiveAction(mAnomaly, METRIC_KEY); + + verify(mFeatureFactory.metricsFeatureProvider).action(mContext, ACTION_KEY, PACKAGE_NAME, + Pair.create(MetricsProto.MetricsEvent.FIELD_CONTEXT, METRIC_KEY)); + } + + /** + * Test class for {@link AnomalyAction} + */ + public class TestAnomalyAction extends AnomalyAction { + public TestAnomalyAction(Context context) { + super(context); + mActionMetricKey = ACTION_KEY; + } + + @Override + public boolean isActionActive(Anomaly anomaly) { + return false; + } + + @Override + public int getActionType() { + return 0; + } + } +}