From af2ece738730f605ecbbbffe78b6319faac39172 Mon Sep 17 00:00:00 2001 From: jackqdyulei Date: Thu, 8 Feb 2018 10:07:11 -0800 Subject: [PATCH] Update detector and action for restrict app 1. In detector, read data from database and display it. 2. Update the RestrictAppAction to mark anomaly as handled if restriction is toggled. 3. Update the RestrictAppTip to handle state change. Bug: 72385333 Test: RunSettingsRoboTests Change-Id: I0bbe6f6fd049bf2e7a2bee1dee08d5199f922e31 --- .../batterytip/BatteryTipLoader.java | 2 +- .../batterytip/actions/RestrictAppAction.java | 7 ++ .../detectors/RestrictAppDetector.java | 45 ++++++- .../batterytip/tips/RestrictAppTip.java | 9 +- .../actions/RestrictAppActionTest.java | 8 +- .../detectors/RestrictAppDetectorTest.java | 113 ++++++++++++++++++ .../batterytip/tips/RestrictAppTipTest.java | 18 +++ 7 files changed, 194 insertions(+), 8 deletions(-) create mode 100644 tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/RestrictAppDetectorTest.java diff --git a/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoader.java b/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoader.java index a61584168bc..ebb4790cd96 100644 --- a/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoader.java +++ b/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoader.java @@ -71,7 +71,7 @@ public class BatteryTipLoader extends AsyncLoader> { tips.add(new SmartBatteryDetector(policy, context.getContentResolver()).detect()); tips.add(new EarlyWarningDetector(policy, context).detect()); tips.add(new SummaryDetector(policy).detect()); - tips.add(new RestrictAppDetector(policy).detect()); + tips.add(new RestrictAppDetector(context, policy).detect()); Collections.sort(tips); return tips; diff --git a/src/com/android/settings/fuelgauge/batterytip/actions/RestrictAppAction.java b/src/com/android/settings/fuelgauge/batterytip/actions/RestrictAppAction.java index 9c49822bb18..886a6d534e6 100644 --- a/src/com/android/settings/fuelgauge/batterytip/actions/RestrictAppAction.java +++ b/src/com/android/settings/fuelgauge/batterytip/actions/RestrictAppAction.java @@ -21,7 +21,9 @@ import android.content.Context; import android.support.annotation.VisibleForTesting; import com.android.settings.fuelgauge.BatteryUtils; +import com.android.settings.fuelgauge.batterytip.AnomalyDatabaseHelper; import com.android.settings.fuelgauge.batterytip.AppInfo; +import com.android.settings.fuelgauge.batterytip.BatteryDatabaseManager; import com.android.settings.fuelgauge.batterytip.tips.RestrictAppTip; import java.util.List; @@ -32,12 +34,15 @@ import java.util.List; public class RestrictAppAction extends BatteryTipAction { private RestrictAppTip mRestrictAppTip; @VisibleForTesting + BatteryDatabaseManager mBatteryDatabaseManager; + @VisibleForTesting BatteryUtils mBatteryUtils; public RestrictAppAction(Context context, RestrictAppTip tip) { super(context); mRestrictAppTip = tip; mBatteryUtils = BatteryUtils.getInstance(context); + mBatteryDatabaseManager = new BatteryDatabaseManager(context); } /** @@ -53,5 +58,7 @@ public class RestrictAppAction extends BatteryTipAction { mBatteryUtils.setForceAppStandby(mBatteryUtils.getPackageUid(packageName), packageName, AppOpsManager.MODE_IGNORED); } + + mBatteryDatabaseManager.updateAnomalies(appInfos, AnomalyDatabaseHelper.State.HANDLED); } } diff --git a/src/com/android/settings/fuelgauge/batterytip/detectors/RestrictAppDetector.java b/src/com/android/settings/fuelgauge/batterytip/detectors/RestrictAppDetector.java index 46e241a24d5..e3c9b9ed612 100644 --- a/src/com/android/settings/fuelgauge/batterytip/detectors/RestrictAppDetector.java +++ b/src/com/android/settings/fuelgauge/batterytip/detectors/RestrictAppDetector.java @@ -16,7 +16,13 @@ package com.android.settings.fuelgauge.batterytip.detectors; +import android.content.Context; +import android.support.annotation.VisibleForTesting; +import android.text.format.DateUtils; + +import com.android.settings.fuelgauge.batterytip.AnomalyDatabaseHelper; import com.android.settings.fuelgauge.batterytip.AppInfo; +import com.android.settings.fuelgauge.batterytip.BatteryDatabaseManager; import com.android.settings.fuelgauge.batterytip.BatteryTipPolicy; import com.android.settings.fuelgauge.batterytip.tips.BatteryTip; import com.android.settings.fuelgauge.batterytip.tips.RestrictAppTip; @@ -29,18 +35,47 @@ import java.util.List; * {@link BatteryTipDetector} since it need the most up-to-date {@code visibleTips} */ public class RestrictAppDetector implements BatteryTipDetector { + @VisibleForTesting + static final boolean USE_FAKE_DATA = false; private BatteryTipPolicy mPolicy; + @VisibleForTesting + BatteryDatabaseManager mBatteryDatabaseManager; - public RestrictAppDetector(BatteryTipPolicy policy) { + public RestrictAppDetector(Context context, BatteryTipPolicy policy) { mPolicy = policy; + mBatteryDatabaseManager = new BatteryDatabaseManager(context); } @Override public BatteryTip detect() { - // TODO(b/70570352): Detect restrict apps here, get data from database + if (USE_FAKE_DATA) { + return getFakeData(); + } + if (mPolicy.appRestrictionEnabled) { + // TODO(b/72385333): hook up the query timestamp to server side + final long oneDayBeforeMs = System.currentTimeMillis() - DateUtils.DAY_IN_MILLIS; + final List highUsageApps = mBatteryDatabaseManager.queryAllAnomalies( + oneDayBeforeMs, AnomalyDatabaseHelper.State.NEW); + if (!highUsageApps.isEmpty()) { + // If there are new anomalies, show them + return new RestrictAppTip(BatteryTip.StateType.NEW, highUsageApps); + } else { + // Otherwise, show auto-handled one if it exists + final List autoHandledApps = mBatteryDatabaseManager.queryAllAnomalies( + oneDayBeforeMs, AnomalyDatabaseHelper.State.AUTO_HANDLED); + return new RestrictAppTip(autoHandledApps.isEmpty() ? BatteryTip.StateType.INVISIBLE + : BatteryTip.StateType.HANDLED, autoHandledApps); + } + } else { + return new RestrictAppTip(BatteryTip.StateType.INVISIBLE, new ArrayList<>()); + } + } + + private BatteryTip getFakeData() { final List highUsageApps = new ArrayList<>(); - return new RestrictAppTip( - highUsageApps.isEmpty() ? BatteryTip.StateType.INVISIBLE : BatteryTip.StateType.NEW, - highUsageApps); + highUsageApps.add(new AppInfo.Builder() + .setPackageName("com.android.settings") + .build()); + return new RestrictAppTip(BatteryTip.StateType.NEW, highUsageApps); } } diff --git a/src/com/android/settings/fuelgauge/batterytip/tips/RestrictAppTip.java b/src/com/android/settings/fuelgauge/batterytip/tips/RestrictAppTip.java index 1d84d7fb94b..a40f292a0eb 100644 --- a/src/com/android/settings/fuelgauge/batterytip/tips/RestrictAppTip.java +++ b/src/com/android/settings/fuelgauge/batterytip/tips/RestrictAppTip.java @@ -81,7 +81,14 @@ public class RestrictAppTip extends BatteryTip { @Override public void updateState(BatteryTip tip) { - mState = tip.mState; + if (tip.mState == StateType.NEW) { + // Display it if new anomaly comes + mState = StateType.NEW; + mRestrictAppList = ((RestrictAppTip) tip).mRestrictAppList; + } else if (mState == StateType.NEW && tip.mState == StateType.INVISIBLE) { + // If anomaly becomes invisible, show it as handled + mState = StateType.HANDLED; + } } public List getRestrictAppList() { diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/actions/RestrictAppActionTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/actions/RestrictAppActionTest.java index 47785d555b3..728bbff991d 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/actions/RestrictAppActionTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/actions/RestrictAppActionTest.java @@ -27,8 +27,10 @@ import com.android.settings.fuelgauge.BatteryUtils; import com.android.settings.fuelgauge.batterytip.AppInfo; import com.android.settings.fuelgauge.batterytip.tips.BatteryTip; import com.android.settings.fuelgauge.batterytip.tips.RestrictAppTip; +import com.android.settings.testutils.DatabaseTestUtils; import com.android.settings.testutils.SettingsRobolectricTestRunner; +import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -69,6 +71,11 @@ public class RestrictAppActionTest { mRestrictAppAction.mBatteryUtils = mBatteryUtils; } + @After + public void cleanUp() { + DatabaseTestUtils.clearDb(mContext); + } + @Test public void testHandlePositiveAction() { mRestrictAppAction.handlePositiveAction(); @@ -79,5 +86,4 @@ public class RestrictAppActionTest { eq(AppOpsManager.MODE_IGNORED)); } - } diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/RestrictAppDetectorTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/RestrictAppDetectorTest.java new file mode 100644 index 00000000000..6a25c6d26df --- /dev/null +++ b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/RestrictAppDetectorTest.java @@ -0,0 +1,113 @@ +/* + * 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.detectors; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.Matchers.anyInt; +import static org.mockito.Matchers.anyLong; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.spy; + +import android.content.Context; + +import com.android.settings.TestConfig; +import com.android.settings.fuelgauge.batterytip.AnomalyDatabaseHelper; +import com.android.settings.fuelgauge.batterytip.AppInfo; +import com.android.settings.fuelgauge.batterytip.BatteryDatabaseManager; +import com.android.settings.fuelgauge.batterytip.BatteryTipPolicy; +import com.android.settings.fuelgauge.batterytip.tips.BatteryTip; +import com.android.settings.testutils.DatabaseTestUtils; +import com.android.settings.testutils.SettingsRobolectricTestRunner; + +import org.junit.After; +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 java.util.ArrayList; +import java.util.List; + +@RunWith(SettingsRobolectricTestRunner.class) +@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION) +public class RestrictAppDetectorTest { + private static final String PACKAGE_NAME = "com.android.app"; + private Context mContext; + private BatteryTipPolicy mPolicy; + private RestrictAppDetector mRestrictAppDetector; + private List mAppInfoList; + @Mock + private BatteryDatabaseManager mBatteryDatabaseManager; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + + mAppInfoList = new ArrayList<>(); + mAppInfoList.add(new AppInfo.Builder() + .setPackageName(PACKAGE_NAME) + .build()); + + mContext = RuntimeEnvironment.application; + mPolicy = spy(new BatteryTipPolicy(mContext)); + mRestrictAppDetector = new RestrictAppDetector(mContext, mPolicy); + mRestrictAppDetector.mBatteryDatabaseManager = mBatteryDatabaseManager; + } + + @After + public void cleanUp() { + DatabaseTestUtils.clearDb(mContext); + } + + @Test + public void testDetect_hasAnomaly_tipNew() { + doReturn(mAppInfoList).when(mBatteryDatabaseManager).queryAllAnomalies(anyLong(), + eq(AnomalyDatabaseHelper.State.NEW)); + + assertThat(mRestrictAppDetector.detect().getState()).isEqualTo(BatteryTip.StateType.NEW); + } + + @Test + public void testDetect_hasAutoHandledAnomaly_tipHandled() { + doReturn(new ArrayList()).when(mBatteryDatabaseManager).queryAllAnomalies( + anyLong(), eq(AnomalyDatabaseHelper.State.NEW)); + doReturn(mAppInfoList).when(mBatteryDatabaseManager).queryAllAnomalies(anyLong(), + eq(AnomalyDatabaseHelper.State.AUTO_HANDLED)); + + assertThat(mRestrictAppDetector.detect().getState()).isEqualTo( + BatteryTip.StateType.HANDLED); + } + + @Test + public void testDetect_noAnomaly_tipInvisible() { + doReturn(new ArrayList()).when(mBatteryDatabaseManager).queryAllAnomalies( + anyLong(), anyInt()); + + assertThat(mRestrictAppDetector.detect().getState()).isEqualTo( + BatteryTip.StateType.INVISIBLE); + } + + @Test + public void testUseFakeData_alwaysFalse() { + assertThat(RestrictAppDetector.USE_FAKE_DATA).isFalse(); + } +} diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/RestrictAppTipTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/RestrictAppTipTest.java index e1dea17c1f6..74536a53031 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/RestrictAppTipTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/RestrictAppTipTest.java @@ -49,6 +49,7 @@ public class RestrictAppTipTest { private Context mContext; private RestrictAppTip mNewBatteryTip; private RestrictAppTip mHandledBatteryTip; + private RestrictAppTip mInvisibleBatteryTip; private List mUsageAppList; @Mock private ApplicationInfo mApplicationInfo; @@ -71,6 +72,7 @@ public class RestrictAppTipTest { .build()); mNewBatteryTip = new RestrictAppTip(BatteryTip.StateType.NEW, mUsageAppList); mHandledBatteryTip = new RestrictAppTip(BatteryTip.StateType.HANDLED, mUsageAppList); + mInvisibleBatteryTip = new RestrictAppTip(BatteryTip.StateType.INVISIBLE, mUsageAppList); } @Test @@ -108,4 +110,20 @@ public class RestrictAppTipTest { assertThat(mHandledBatteryTip.getSummary(mContext)).isEqualTo( "App changes are in progress"); } + + @Test + public void testUpdate_anomalyBecomeInvisible_stateHandled() { + mNewBatteryTip.updateState(mInvisibleBatteryTip); + + assertThat(mNewBatteryTip.getState()).isEqualTo(BatteryTip.StateType.HANDLED); + } + + @Test + public void testUpdate_newAnomalyComes_stateNew() { + mInvisibleBatteryTip.updateState(mNewBatteryTip); + assertThat(mInvisibleBatteryTip.getState()).isEqualTo(BatteryTip.StateType.NEW); + + mHandledBatteryTip.updateState(mNewBatteryTip); + assertThat(mHandledBatteryTip.getState()).isEqualTo(BatteryTip.StateType.NEW); + } }