OSDN Git Service

Add location check action for bt anomaly
authorjackqdyulei <jackqdyulei@google.com>
Tue, 20 Jun 2017 17:09:04 +0000 (10:09 -0700)
committerjackqdyulei <jackqdyulei@google.com>
Tue, 27 Jun 2017 23:21:50 +0000 (16:21 -0700)
This cl adds action to turn off location permission for both
ACCESS_FINE_LOCATION and ACCESS_COARSE_LOCATION by using API
in RuntimePermissionPresenter

Bug: 36921532
Test: runtest -x LocationCheckActionTest

Change-Id: Ibe1e2908bd745a137d92a70a8432e9f866c1be61

res/values/strings.xml
src/com/android/settings/fuelgauge/anomaly/Anomaly.java
src/com/android/settings/fuelgauge/anomaly/AnomalyDialogFragment.java
src/com/android/settings/fuelgauge/anomaly/AnomalyUtils.java
src/com/android/settings/fuelgauge/anomaly/action/LocationCheckAction.java [new file with mode: 0644]
src/com/android/settings/fuelgauge/anomaly/checker/BluetoothScanAnomalyDetector.java
tests/robotests/src/com/android/settings/fuelgauge/anomaly/AnomalyDialogFragmentTest.java
tests/robotests/src/com/android/settings/fuelgauge/anomaly/checker/BluetoothScanAnomalyDetectorTest.java
tests/unit/src/com/android/settings/fuelgauge/anomaly/action/LocationCheckActionTest.java [new file with mode: 0644]

index 9580206..069843d 100644 (file)
     <!-- Title for location dialog [CHAR LIMIT=60] -->
     <string name="dialog_location_title">Turn off location?</string>
     <!-- Message body for location dialog [CHAR LIMIT=NONE] -->
-    <string name="dialog_location_message" product="default">Your phone can’t manage battery normally because <xliff:g id="app">%1$s</xliff:g> keeps requesting your location when you're not using the app.\n\nTo fix this issue, you can turn off location for this app.</string>
+    <string name="dialog_location_message" product="default">Your phone can\'t manage battery normally because <xliff:g id="app">%1$s</xliff:g> keeps requesting your location when you\'re not using the app.\n\nTo fix this issue, you can turn off location for this app.</string>
     <!-- Message body for location dialog [CHAR LIMIT=NONE] -->
-    <string name="dialog_location_message" product="tablet">Your tablet can’t manage battery normally because <xliff:g id="app">%1$s</xliff:g> keeps requesting your location when you're not using the app.\n\nTo fix this issue, you can turn off location for this app.</string>
+    <string name="dialog_location_message" product="tablet">Your tablet can\'t manage battery normally because <xliff:g id="app">%1$s</xliff:g> keeps requesting your location when you\'re not using the app.\n\nTo fix this issue, you can turn off location for this app.</string>
     <!-- Message body for location dialog [CHAR LIMIT=NONE] -->
-    <string name="dialog_location_message" product="device">Your device can’t manage battery normally because <xliff:g id="app">%1$s</xliff:g> keeps requesting your location when you're not using the app.\n\nTo fix this issue, you can turn off location for this app.</string>
+    <string name="dialog_location_message" product="device">Your device can\'t manage battery normally because <xliff:g id="app">%1$s</xliff:g> keeps requesting your location when you\'re not using the app.\n\nTo fix this issue, you can turn off location for this app.</string>
 
     <!-- Text for OK button in location dialog [CHAR LIMIT=30] -->
     <string name="dialog_location_ok">Turn off</string>
index 746bd7f..2a4282a 100644 (file)
@@ -45,10 +45,12 @@ public class Anomaly implements Parcelable {
 
     @Retention(RetentionPolicy.SOURCE)
     @IntDef({AnomalyActionType.FORCE_STOP,
-            AnomalyActionType.BACKGROUND_CHECK})
+            AnomalyActionType.BACKGROUND_CHECK,
+            AnomalyActionType.LOCATION_CHECK})
     public @interface AnomalyActionType {
         int FORCE_STOP = 0;
         int BACKGROUND_CHECK = 1;
+        int LOCATION_CHECK = 2;
     }
 
     @AnomalyType
index 2d0030d..452cc35 100644 (file)
@@ -38,7 +38,8 @@ public class AnomalyDialogFragment extends InstrumentedDialogFragment implements
 
     @VisibleForTesting
     Anomaly mAnomaly;
-    private AnomalyUtils mAnomalyUtils;
+    @VisibleForTesting
+    AnomalyUtils mAnomalyUtils;
 
     /**
      * Listener to give the control back to target fragment
@@ -68,6 +69,11 @@ public class AnomalyDialogFragment extends InstrumentedDialogFragment implements
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
+        initAnomalyUtils();
+    }
+
+    @VisibleForTesting
+    void initAnomalyUtils() {
         mAnomalyUtils = AnomalyUtils.getInstance(getContext());
     }
 
@@ -114,6 +120,14 @@ public class AnomalyDialogFragment extends InstrumentedDialogFragment implements
                         .setPositiveButton(R.string.dialog_background_check_ok, this)
                         .setNegativeButton(R.string.dlg_cancel, null)
                         .create();
+            case Anomaly.AnomalyActionType.LOCATION_CHECK:
+                return new AlertDialog.Builder(context)
+                        .setTitle(R.string.dialog_location_title)
+                        .setMessage(getString(R.string.dialog_location_message,
+                                mAnomaly.displayName))
+                        .setPositiveButton(R.string.dialog_location_ok, this)
+                        .setNegativeButton(R.string.dlg_cancel, null)
+                        .create();
             default:
                 throw new IllegalArgumentException("unknown type " + mAnomaly.type);
         }
index de9f7aa..9d0e1d0 100644 (file)
@@ -22,6 +22,7 @@ import android.support.annotation.VisibleForTesting;
 import com.android.settings.fuelgauge.anomaly.action.AnomalyAction;
 import com.android.settings.fuelgauge.anomaly.action.BackgroundCheckAction;
 import com.android.settings.fuelgauge.anomaly.action.ForceStopAction;
+import com.android.settings.fuelgauge.anomaly.action.LocationCheckAction;
 import com.android.settings.fuelgauge.anomaly.checker.AnomalyDetector;
 import com.android.settings.fuelgauge.anomaly.checker.BluetoothScanAnomalyDetector;
 import com.android.settings.fuelgauge.anomaly.checker.WakeLockAnomalyDetector;
@@ -57,8 +58,9 @@ public class AnomalyUtils {
             case Anomaly.AnomalyType.WAKE_LOCK:
                 return new ForceStopAction(mContext);
             case Anomaly.AnomalyType.WAKEUP_ALARM:
-            case Anomaly.AnomalyType.BLUETOOTH_SCAN:
                 return new BackgroundCheckAction(mContext);
+            case Anomaly.AnomalyType.BLUETOOTH_SCAN:
+                return new LocationCheckAction(mContext);
             default:
                 return null;
         }
diff --git a/src/com/android/settings/fuelgauge/anomaly/action/LocationCheckAction.java b/src/com/android/settings/fuelgauge/anomaly/action/LocationCheckAction.java
new file mode 100644 (file)
index 0000000..4205b6e
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * 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 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.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 {
+
+    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;
+        mRuntimePermissionPresenter = RuntimePermissionPresenter.getInstance(context);
+    }
+
+    @Override
+    public void handlePositiveAction(Anomaly anomaly, int metricsKey) {
+        mRuntimePermissionPresenter.revokeRuntimePermission(anomaly.packageName,
+                LOCATION_PERMISSION);
+    }
+
+    @Override
+    public boolean isActionActive(Anomaly anomaly) {
+        return PermissionChecker.checkPermission(mContext, LOCATION_PERMISSION, -1, anomaly.uid,
+                anomaly.packageName) == PermissionChecker.PERMISSION_GRANTED;
+    }
+
+    @Override
+    public int getActionType() {
+        return Anomaly.AnomalyActionType.LOCATION_CHECK;
+    }
+}
index 619386e..4281743 100644 (file)
@@ -48,15 +48,17 @@ public class BluetoothScanAnomalyDetector implements AnomalyDetector {
     private Context mContext;
 
     public BluetoothScanAnomalyDetector(Context context) {
-        this(context, new AnomalyDetectionPolicy(context));
+        this(context, new AnomalyDetectionPolicy(context),
+                AnomalyUtils.getInstance(context).getAnomalyAction(
+                        Anomaly.AnomalyType.BLUETOOTH_SCAN));
     }
 
     @VisibleForTesting
-    BluetoothScanAnomalyDetector(Context context, AnomalyDetectionPolicy policy) {
+    BluetoothScanAnomalyDetector(Context context, AnomalyDetectionPolicy policy,
+            AnomalyAction anomalyAction) {
         mContext = context;
         mBatteryUtils = BatteryUtils.getInstance(context);
-        mAnomalyAction = AnomalyUtils.getInstance(context).getAnomalyAction(
-                Anomaly.AnomalyType.BLUETOOTH_SCAN);
+        mAnomalyAction = anomalyAction;
         mBluetoothScanningThreshold = policy.bluetoothScanThreshold;
     }
 
index 365a14a..e8e4bab 100644 (file)
@@ -18,6 +18,10 @@ package com.android.settings.fuelgauge.anomaly;
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
 import static org.robolectric.Shadows.shadowOf;
 
 import android.app.AlertDialog;
@@ -25,12 +29,15 @@ import android.content.Context;
 import android.content.DialogInterface;
 
 import com.android.settings.R;
+import com.android.settings.fuelgauge.anomaly.action.AnomalyAction;
 import com.android.settings.testutils.SettingsRobolectricTestRunner;
 import com.android.settings.TestConfig;
 
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
 import org.robolectric.RuntimeEnvironment;
 import org.robolectric.annotation.Config;
 import org.robolectric.shadows.ShadowAlertDialog;
@@ -43,13 +50,21 @@ public class AnomalyDialogFragmentTest {
     private static final String PACKAGE_NAME = "com.android.app";
     private static final String DISPLAY_NAME = "app";
     private static final int UID = 111;
+
+    @Mock
+    private AnomalyUtils mAnomalyUtils;
+    @Mock
+    private AnomalyAction mAnomalyAction;
     private Anomaly mWakeLockAnomaly;
     private Anomaly mWakeupAlarmAnomaly;
+    private Anomaly mBluetoothAnomaly;
     private AnomalyDialogFragment mAnomalyDialogFragment;
     private Context mContext;
 
     @Before
     public void setUp() {
+        MockitoAnnotations.initMocks(this);
+
         mContext = RuntimeEnvironment.application;
         mWakeLockAnomaly = new Anomaly.Builder()
                 .setType(Anomaly.AnomalyType.WAKE_LOCK)
@@ -63,6 +78,12 @@ public class AnomalyDialogFragmentTest {
                 .setPackageName(PACKAGE_NAME)
                 .setDisplayName(DISPLAY_NAME)
                 .build();
+        mBluetoothAnomaly = new Anomaly.Builder()
+                .setType(Anomaly.AnomalyType.BLUETOOTH_SCAN)
+                .setUid(UID)
+                .setPackageName(PACKAGE_NAME)
+                .setDisplayName(DISPLAY_NAME)
+                .build();
     }
 
     @Test
@@ -114,4 +135,29 @@ public class AnomalyDialogFragmentTest {
         assertThat(dialog.getButton(DialogInterface.BUTTON_NEGATIVE).getText()).isEqualTo(
                 mContext.getString(R.string.dlg_cancel));
     }
+
+    @Test
+    public void testOnCreateDialog_bluetoothAnomaly_fireLocationCheckDialog() {
+        mAnomalyDialogFragment = spy(AnomalyDialogFragment.newInstance(mBluetoothAnomaly,
+                0 /* metricskey */));
+        mAnomalyDialogFragment.mAnomalyUtils = mAnomalyUtils;
+        doReturn(mAnomalyAction).when(mAnomalyUtils).getAnomalyAction(anyInt());
+        doNothing().when(mAnomalyDialogFragment).initAnomalyUtils();
+        doReturn(Anomaly.AnomalyActionType.LOCATION_CHECK).when(mAnomalyAction).getActionType();
+
+        FragmentTestUtil.startFragment(mAnomalyDialogFragment);
+
+        final AlertDialog dialog = (AlertDialog) ShadowDialog.getLatestDialog();
+        ShadowAlertDialog shadowDialog = shadowOf(dialog);
+
+        assertThat(shadowDialog.getMessage()).isEqualTo(
+                mContext.getString(R.string.dialog_location_message,
+                        mWakeLockAnomaly.displayName));
+        assertThat(shadowDialog.getTitle()).isEqualTo(
+                mContext.getString(R.string.dialog_location_title));
+        assertThat(dialog.getButton(DialogInterface.BUTTON_POSITIVE).getText()).isEqualTo(
+                mContext.getString(R.string.dialog_location_ok));
+        assertThat(dialog.getButton(DialogInterface.BUTTON_NEGATIVE).getText()).isEqualTo(
+                mContext.getString(R.string.dlg_cancel));
+    }
 }
index 941e9cd..a687e2f 100644 (file)
@@ -106,7 +106,8 @@ public class BluetoothScanAnomalyDetectorTest {
         mUsageList.add(mTargetSipper);
         doReturn(mUsageList).when(mBatteryStatsHelper).getUsageList();
 
-        mBluetoothScanAnomalyDetector = spy(new BluetoothScanAnomalyDetector(mContext, mPolicy));
+        mBluetoothScanAnomalyDetector = spy(
+                new BluetoothScanAnomalyDetector(mContext, mPolicy, mAnomalyAction));
         mBluetoothScanAnomalyDetector.mBatteryUtils = mBatteryUtils;
         mBluetoothScanAnomalyDetector.mAnomalyAction = mAnomalyAction;
         doReturn(false).when(mBatteryUtils).shouldHideSipper(any());
diff --git a/tests/unit/src/com/android/settings/fuelgauge/anomaly/action/LocationCheckActionTest.java b/tests/unit/src/com/android/settings/fuelgauge/anomaly/action/LocationCheckActionTest.java
new file mode 100644 (file)
index 0000000..8be3320
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * 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 com.google.common.truth.Truth.assertThat;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import com.android.settings.fuelgauge.anomaly.Anomaly;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class LocationCheckActionTest {
+    private static final String PACKAGE_NAME = "com.android.chrome";
+
+    private Context mContext;
+    private LocationCheckAction mLocationCheckAction;
+    private Anomaly mAnomaly;
+
+    @Before
+    public void setUp() {
+        mContext = InstrumentationRegistry.getTargetContext();
+        mLocationCheckAction = new LocationCheckAction(mContext);
+
+        mAnomaly = new Anomaly.Builder()
+                .setUid(getPackageUid(mContext, PACKAGE_NAME))
+                .setPackageName(PACKAGE_NAME)
+                .build();
+    }
+
+    @Test
+    public void testRevokeAndCheck() {
+        mLocationCheckAction.handlePositiveAction(mAnomaly, 0 /* metric key */);
+
+        assertThat(mLocationCheckAction.isActionActive(mAnomaly)).isFalse();
+    }
+
+    private int getPackageUid(Context context, String packageName) {
+        try {
+            return context.getPackageManager().getPackageUid(packageName,
+                    PackageManager.GET_META_DATA);
+        } catch (PackageManager.NameNotFoundException e) {
+            return -1;
+        }
+    }
+}
+
+
+
+