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
This commit is contained in:
jackqdyulei
2018-02-08 10:07:11 -08:00
parent fe13d2813a
commit af2ece7387
7 changed files with 194 additions and 8 deletions

View File

@@ -71,7 +71,7 @@ public class BatteryTipLoader extends AsyncLoader<List<BatteryTip>> {
tips.add(new SmartBatteryDetector(policy, context.getContentResolver()).detect()); tips.add(new SmartBatteryDetector(policy, context.getContentResolver()).detect());
tips.add(new EarlyWarningDetector(policy, context).detect()); tips.add(new EarlyWarningDetector(policy, context).detect());
tips.add(new SummaryDetector(policy).detect()); tips.add(new SummaryDetector(policy).detect());
tips.add(new RestrictAppDetector(policy).detect()); tips.add(new RestrictAppDetector(context, policy).detect());
Collections.sort(tips); Collections.sort(tips);
return tips; return tips;

View File

@@ -21,7 +21,9 @@ import android.content.Context;
import android.support.annotation.VisibleForTesting; import android.support.annotation.VisibleForTesting;
import com.android.settings.fuelgauge.BatteryUtils; 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.AppInfo;
import com.android.settings.fuelgauge.batterytip.BatteryDatabaseManager;
import com.android.settings.fuelgauge.batterytip.tips.RestrictAppTip; import com.android.settings.fuelgauge.batterytip.tips.RestrictAppTip;
import java.util.List; import java.util.List;
@@ -32,12 +34,15 @@ import java.util.List;
public class RestrictAppAction extends BatteryTipAction { public class RestrictAppAction extends BatteryTipAction {
private RestrictAppTip mRestrictAppTip; private RestrictAppTip mRestrictAppTip;
@VisibleForTesting @VisibleForTesting
BatteryDatabaseManager mBatteryDatabaseManager;
@VisibleForTesting
BatteryUtils mBatteryUtils; BatteryUtils mBatteryUtils;
public RestrictAppAction(Context context, RestrictAppTip tip) { public RestrictAppAction(Context context, RestrictAppTip tip) {
super(context); super(context);
mRestrictAppTip = tip; mRestrictAppTip = tip;
mBatteryUtils = BatteryUtils.getInstance(context); mBatteryUtils = BatteryUtils.getInstance(context);
mBatteryDatabaseManager = new BatteryDatabaseManager(context);
} }
/** /**
@@ -53,5 +58,7 @@ public class RestrictAppAction extends BatteryTipAction {
mBatteryUtils.setForceAppStandby(mBatteryUtils.getPackageUid(packageName), packageName, mBatteryUtils.setForceAppStandby(mBatteryUtils.getPackageUid(packageName), packageName,
AppOpsManager.MODE_IGNORED); AppOpsManager.MODE_IGNORED);
} }
mBatteryDatabaseManager.updateAnomalies(appInfos, AnomalyDatabaseHelper.State.HANDLED);
} }
} }

View File

@@ -16,7 +16,13 @@
package com.android.settings.fuelgauge.batterytip.detectors; 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.AppInfo;
import com.android.settings.fuelgauge.batterytip.BatteryDatabaseManager;
import com.android.settings.fuelgauge.batterytip.BatteryTipPolicy; import com.android.settings.fuelgauge.batterytip.BatteryTipPolicy;
import com.android.settings.fuelgauge.batterytip.tips.BatteryTip; import com.android.settings.fuelgauge.batterytip.tips.BatteryTip;
import com.android.settings.fuelgauge.batterytip.tips.RestrictAppTip; 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} * {@link BatteryTipDetector} since it need the most up-to-date {@code visibleTips}
*/ */
public class RestrictAppDetector implements BatteryTipDetector { public class RestrictAppDetector implements BatteryTipDetector {
@VisibleForTesting
static final boolean USE_FAKE_DATA = false;
private BatteryTipPolicy mPolicy; private BatteryTipPolicy mPolicy;
@VisibleForTesting
BatteryDatabaseManager mBatteryDatabaseManager;
public RestrictAppDetector(BatteryTipPolicy policy) { public RestrictAppDetector(Context context, BatteryTipPolicy policy) {
mPolicy = policy; mPolicy = policy;
mBatteryDatabaseManager = new BatteryDatabaseManager(context);
} }
@Override @Override
public BatteryTip detect() { 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<AppInfo> 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<AppInfo> 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<AppInfo> highUsageApps = new ArrayList<>(); final List<AppInfo> highUsageApps = new ArrayList<>();
return new RestrictAppTip( highUsageApps.add(new AppInfo.Builder()
highUsageApps.isEmpty() ? BatteryTip.StateType.INVISIBLE : BatteryTip.StateType.NEW, .setPackageName("com.android.settings")
highUsageApps); .build());
return new RestrictAppTip(BatteryTip.StateType.NEW, highUsageApps);
} }
} }

View File

@@ -81,7 +81,14 @@ public class RestrictAppTip extends BatteryTip {
@Override @Override
public void updateState(BatteryTip tip) { 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<AppInfo> getRestrictAppList() { public List<AppInfo> getRestrictAppList() {

View File

@@ -27,8 +27,10 @@ import com.android.settings.fuelgauge.BatteryUtils;
import com.android.settings.fuelgauge.batterytip.AppInfo; import com.android.settings.fuelgauge.batterytip.AppInfo;
import com.android.settings.fuelgauge.batterytip.tips.BatteryTip; import com.android.settings.fuelgauge.batterytip.tips.BatteryTip;
import com.android.settings.fuelgauge.batterytip.tips.RestrictAppTip; import com.android.settings.fuelgauge.batterytip.tips.RestrictAppTip;
import com.android.settings.testutils.DatabaseTestUtils;
import com.android.settings.testutils.SettingsRobolectricTestRunner; import com.android.settings.testutils.SettingsRobolectricTestRunner;
import org.junit.After;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
@@ -69,6 +71,11 @@ public class RestrictAppActionTest {
mRestrictAppAction.mBatteryUtils = mBatteryUtils; mRestrictAppAction.mBatteryUtils = mBatteryUtils;
} }
@After
public void cleanUp() {
DatabaseTestUtils.clearDb(mContext);
}
@Test @Test
public void testHandlePositiveAction() { public void testHandlePositiveAction() {
mRestrictAppAction.handlePositiveAction(); mRestrictAppAction.handlePositiveAction();
@@ -79,5 +86,4 @@ public class RestrictAppActionTest {
eq(AppOpsManager.MODE_IGNORED)); eq(AppOpsManager.MODE_IGNORED));
} }
} }

View File

@@ -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<AppInfo> 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<AppInfo>()).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<AppInfo>()).when(mBatteryDatabaseManager).queryAllAnomalies(
anyLong(), anyInt());
assertThat(mRestrictAppDetector.detect().getState()).isEqualTo(
BatteryTip.StateType.INVISIBLE);
}
@Test
public void testUseFakeData_alwaysFalse() {
assertThat(RestrictAppDetector.USE_FAKE_DATA).isFalse();
}
}

View File

@@ -49,6 +49,7 @@ public class RestrictAppTipTest {
private Context mContext; private Context mContext;
private RestrictAppTip mNewBatteryTip; private RestrictAppTip mNewBatteryTip;
private RestrictAppTip mHandledBatteryTip; private RestrictAppTip mHandledBatteryTip;
private RestrictAppTip mInvisibleBatteryTip;
private List<AppInfo> mUsageAppList; private List<AppInfo> mUsageAppList;
@Mock @Mock
private ApplicationInfo mApplicationInfo; private ApplicationInfo mApplicationInfo;
@@ -71,6 +72,7 @@ public class RestrictAppTipTest {
.build()); .build());
mNewBatteryTip = new RestrictAppTip(BatteryTip.StateType.NEW, mUsageAppList); mNewBatteryTip = new RestrictAppTip(BatteryTip.StateType.NEW, mUsageAppList);
mHandledBatteryTip = new RestrictAppTip(BatteryTip.StateType.HANDLED, mUsageAppList); mHandledBatteryTip = new RestrictAppTip(BatteryTip.StateType.HANDLED, mUsageAppList);
mInvisibleBatteryTip = new RestrictAppTip(BatteryTip.StateType.INVISIBLE, mUsageAppList);
} }
@Test @Test
@@ -108,4 +110,20 @@ public class RestrictAppTipTest {
assertThat(mHandledBatteryTip.getSummary(mContext)).isEqualTo( assertThat(mHandledBatteryTip.getSummary(mContext)).isEqualTo(
"App changes are in progress"); "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);
}
} }