1ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei/*
2ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei * Copyright (C) 2016 The Android Open Source Project
3ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei *
4ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei * use this file except in compliance with the License. You may obtain a copy of
6ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei * the License at
7ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei *
8ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei * http://www.apache.org/licenses/LICENSE-2.0
9ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei *
10ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei * Unless required by applicable law or agreed to in writing, software
11ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei * License for the specific language governing permissions and limitations under
14ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei * the License.
15ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei */
16ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei
17ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyuleipackage com.android.storagemanager.deletionhelper;
18ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei
19ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyuleiimport android.app.usage.UsageStats;
20ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyuleiimport android.app.usage.UsageStatsManager;
21ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyuleiimport android.content.Context;
22ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyuleiimport android.content.pm.ApplicationInfo;
23ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyuleiimport android.content.pm.PackageInfo;
24ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyuleiimport android.os.Looper;
25ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyuleiimport com.android.settingslib.applications.ApplicationsState;
26ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyuleiimport com.android.storagemanager.testing.TestingConstants;
27ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyuleiimport com.android.storagemanager.deletionhelper.AppStateUsageStatsBridge.UsageStatsState;
28ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyuleiimport org.junit.Before;
29ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyuleiimport org.junit.Test;
30ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyuleiimport org.junit.runner.RunWith;
31ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyuleiimport org.mockito.ArgumentCaptor;
32ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyuleiimport org.mockito.Mock;
33ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyuleiimport org.mockito.MockitoAnnotations;
34ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyuleiimport org.robolectric.RobolectricTestRunner;
35ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyuleiimport org.robolectric.RuntimeEnvironment;
36ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyuleiimport org.robolectric.Shadows;
37ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyuleiimport org.robolectric.annotation.Config;
38ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyuleiimport org.robolectric.res.builder.RobolectricPackageManager;
39bfc2b11b9357c4508756243f540760458611b3b8jackqdyuleiimport org.robolectric.shadows.ShadowApplication;
40ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei
41ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyuleiimport java.util.ArrayList;
42ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyuleiimport java.util.HashMap;
43ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyuleiimport java.util.concurrent.TimeUnit;
44ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei
45ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyuleiimport static com.google.common.truth.Truth.assertThat;
46ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyuleiimport static org.mockito.Matchers.any;
47ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyuleiimport static org.mockito.Matchers.anyLong;
48ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyuleiimport static org.mockito.Mockito.atLeastOnce;
49ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyuleiimport static org.mockito.Mockito.mock;
50b96906a082511a5390700818257c8a215637b9e9jackqdyuleiimport static org.mockito.Mockito.verify;
51ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyuleiimport static org.mockito.Mockito.when;
52ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei
53ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei@RunWith(RobolectricTestRunner.class)
54ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei@Config(manifest=TestingConstants.MANIFEST, sdk=23)
55ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyuleipublic class AppStateUsageStatsBridgeTest {
56ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei
57ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei    public static final String PACKAGE_SYSTEM = "package.system";
58ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei    private static final long STARTING_TIME = TimeUnit.DAYS.toMillis(1000);
59ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei    private static final String PACKAGE_NAME = "package.mcpackageface";
60ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei    public static final String PACKAGE_CLEARABLE = "package.clearable";
61ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei    public static final String PACKAGE_TOO_NEW_TO_DELETE = "package.tooNewToDelete";
62ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei
63ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei    @Mock private ApplicationsState mState;
64ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei    @Mock private ApplicationsState.Session mSession;
65ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei    @Mock private UsageStatsManager mUsageStatsManager;
66ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei    @Mock private AppStateUsageStatsBridge.Clock mClock;
67ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei    private AppStateUsageStatsBridge mBridge;
68ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei    private ArrayList<ApplicationsState.AppEntry> mApps;
69ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei    private HashMap<String, UsageStats> mUsageStats;
70ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei    private RobolectricPackageManager mPm;
71ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei
72ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei    @Before
73ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei    public void setUp() {
74ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei        MockitoAnnotations.initMocks(this);
75ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei
76ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei        // Set up the application state.
77ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei        when(mState.newSession(any(ApplicationsState.Callbacks.class))).thenReturn(mSession);
78ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei        when(mState.getBackgroundLooper()).thenReturn(Looper.getMainLooper());
79ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei
80ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei        // Set up the ApplicationState's session to return our fake list of apps.
81ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei        mApps = new ArrayList<>();
82ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei        when(mSession.getAllApps()).thenReturn(mApps);
83ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei
84bfc2b11b9357c4508756243f540760458611b3b8jackqdyulei        // Set up our mock usage stats service.
85bfc2b11b9357c4508756243f540760458611b3b8jackqdyulei        ShadowApplication app = Shadows.shadowOf(RuntimeEnvironment.application);
86ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei        mPm = RuntimeEnvironment.getRobolectricPackageManager();
87ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei        app.setSystemService(Context.USAGE_STATS_SERVICE, mUsageStatsManager);
88ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei
89ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei        // Set up the AppStateUsageStatsBridge with a fake clock for us to manipulate the time.
90ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei        when(mClock.getCurrentTime()).thenReturn(STARTING_TIME);
91ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei        mBridge = new AppStateUsageStatsBridge(RuntimeEnvironment.application, mState, null);
92ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei        mBridge.mClock = mClock;
93ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei        AppStateUsageStatsBridge.FILTER_USAGE_STATS.init();
94ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei
95ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei        // Set up our fake usage stats.
96b96906a082511a5390700818257c8a215637b9e9jackqdyulei        mUsageStats = new HashMap<>();
97b96906a082511a5390700818257c8a215637b9e9jackqdyulei        when(mUsageStatsManager.queryAndAggregateUsageStats(anyLong(),
98bfc2b11b9357c4508756243f540760458611b3b8jackqdyulei                anyLong())).thenReturn(mUsageStats);
99ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei    }
100ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei
101ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei    @Test
102ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei    public void test_appInstalledSameDayNeverUsed_isInvalid() {
103ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei        ApplicationsState.AppEntry app =
104ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei                addPackageToPackageManager(PACKAGE_NAME, TimeUnit.DAYS.toMillis(1000));
105ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei
106ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei        mBridge.updateExtraInfo(app, PACKAGE_NAME, 0);
107ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei        UsageStatsState stats = (UsageStatsState) app.extraInfo;
108ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei
109ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei        assertThat(app.extraInfo).isNotNull();
110ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei        assertThat(stats.daysSinceFirstInstall).isEqualTo(0);
111ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei        assertThat(stats.daysSinceLastUse).isEqualTo(AppStateUsageStatsBridge.NEVER_USED);
112ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei        assertThat(AppStateUsageStatsBridge.FILTER_USAGE_STATS.filterApp(app)).isFalse();
113bfc2b11b9357c4508756243f540760458611b3b8jackqdyulei    }
114bfc2b11b9357c4508756243f540760458611b3b8jackqdyulei
115ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei    @Test
116ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei    public void test_noThresholdFilter_appInstalledSameDayNeverUsed_isValid() {
117ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei        ApplicationsState.AppEntry app =
118ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei                addPackageToPackageManager(PACKAGE_NAME, TimeUnit.DAYS.toMillis(1000));
119ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei
120ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei        mBridge.updateExtraInfo(app, PACKAGE_NAME, 0);
121ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei        UsageStatsState stats = (UsageStatsState) app.extraInfo;
122ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei
123ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei        assertThat(app.extraInfo).isNotNull();
124ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei        assertThat(stats.daysSinceFirstInstall).isEqualTo(0);
125ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei        assertThat(stats.daysSinceLastUse).isEqualTo(AppStateUsageStatsBridge.NEVER_USED);
126ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei        assertThat(AppStateUsageStatsBridge.FILTER_NO_THRESHOLD.filterApp(app)).isTrue();
127ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei    }
128ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei
129ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei    @Test
130ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei    public void test_unusedApp_isValid() {
131ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei        ApplicationsState.AppEntry app =
132ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei                addPackageToPackageManager(PACKAGE_NAME, TimeUnit.DAYS.toMillis(910));
133ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei
134ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei        mBridge.updateExtraInfo(app, PACKAGE_NAME, 0);
135ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei        UsageStatsState stats = (UsageStatsState) app.extraInfo;
136ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei
137ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei        assertThat(app.extraInfo).isNotNull();
138ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei        assertThat(stats.daysSinceFirstInstall).isEqualTo(90);
139ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei        assertThat(stats.daysSinceLastUse).isEqualTo(AppStateUsageStatsBridge.NEVER_USED);
140ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei        assertThat(AppStateUsageStatsBridge.FILTER_USAGE_STATS.filterApp(app)).isTrue();
141ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei    }
142ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei
143ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei    @Test
144ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei    public void test_noThresholdFilter_unusedApp_isValid() {
145ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei        ApplicationsState.AppEntry app =
146ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei                addPackageToPackageManager(PACKAGE_NAME, TimeUnit.DAYS.toMillis(910));
147ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei
148ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei        mBridge.updateExtraInfo(app, PACKAGE_NAME, 0);
149ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei        UsageStatsState stats = (UsageStatsState) app.extraInfo;
150ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei
151ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei        assertThat(app.extraInfo).isNotNull();
152ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei        assertThat(stats.daysSinceFirstInstall).isEqualTo(90);
153ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei        assertThat(stats.daysSinceLastUse).isEqualTo(AppStateUsageStatsBridge.NEVER_USED);
154ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei        assertThat(AppStateUsageStatsBridge.FILTER_NO_THRESHOLD.filterApp(app)).isTrue();
155ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei    }
156ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei
157ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei    @Test
158edfebbaa4f3ffa98c99e1e41b054853ccbff06c7jackqdyulei    public void test_unknownLastUse_isFilteredOut() {
159ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei        ApplicationsState.AppEntry app =
160ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei                addPackageToPackageManager(PACKAGE_NAME, TimeUnit.DAYS.toMillis(910));
161ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei        registerLastUse(PACKAGE_NAME, -1);
162ec8e127ed3a616a7ca223a5bc6d9c4bbc036cd90jackqdyulei
163        mBridge.updateExtraInfo(app, PACKAGE_NAME, 0);
164        UsageStatsState stats = (UsageStatsState) app.extraInfo;
165
166        assertThat(app.extraInfo).isNotNull();
167        assertThat(stats.daysSinceFirstInstall).isEqualTo(90);
168        assertThat(stats.daysSinceLastUse).isEqualTo(AppStateUsageStatsBridge.UNKNOWN_LAST_USE);
169        assertThat(AppStateUsageStatsBridge.FILTER_USAGE_STATS.filterApp(app)).isFalse();
170    }
171
172    @Test
173    public void test_noThresholdFilter_unknownLastUse_isFilteredOut() {
174        ApplicationsState.AppEntry app =
175                addPackageToPackageManager(PACKAGE_NAME, TimeUnit.DAYS.toMillis(910));
176        registerLastUse(PACKAGE_NAME, -1);
177
178        mBridge.updateExtraInfo(app, PACKAGE_NAME, 0);
179        UsageStatsState stats = (UsageStatsState) app.extraInfo;
180
181        assertThat(app.extraInfo).isNotNull();
182        assertThat(stats.daysSinceFirstInstall).isEqualTo(90);
183        assertThat(stats.daysSinceLastUse).isEqualTo(AppStateUsageStatsBridge.UNKNOWN_LAST_USE);
184        assertThat(AppStateUsageStatsBridge.FILTER_NO_THRESHOLD.filterApp(app)).isFalse();
185    }
186
187    @Test
188    public void test_oldAppRecentlyUsed_isNotValid() {
189        ApplicationsState.AppEntry app =
190                addPackageToPackageManager(PACKAGE_NAME, TimeUnit.DAYS.toMillis(800));
191        registerLastUse(PACKAGE_NAME, TimeUnit.DAYS.toMillis(999));
192
193        mBridge.updateExtraInfo(app, PACKAGE_NAME, 0);
194        UsageStatsState stats = (UsageStatsState) app.extraInfo;
195
196        assertThat(app.extraInfo).isNotNull();
197        assertThat(stats.daysSinceFirstInstall).isEqualTo(200);
198        assertThat(stats.daysSinceLastUse).isEqualTo(1);
199        assertThat(AppStateUsageStatsBridge.FILTER_USAGE_STATS.filterApp(app)).isFalse();
200    }
201
202    @Test
203    public void test_noThresholdFilter_oldAppRecentlyUsed_isValid() {
204        ApplicationsState.AppEntry app =
205                addPackageToPackageManager(PACKAGE_NAME, TimeUnit.DAYS.toMillis(800));
206        registerLastUse(PACKAGE_NAME, TimeUnit.DAYS.toMillis(999));
207
208        mBridge.updateExtraInfo(app, PACKAGE_NAME, 0);
209        UsageStatsState stats = (UsageStatsState) app.extraInfo;
210
211        assertThat(app.extraInfo).isNotNull();
212        assertThat(stats.daysSinceFirstInstall).isEqualTo(200);
213        assertThat(stats.daysSinceLastUse).isEqualTo(1);
214        assertThat(AppStateUsageStatsBridge.FILTER_NO_THRESHOLD.filterApp(app)).isTrue();
215    }
216
217    @Test
218    public void test_oldUnusedApp_isValid() {
219        ApplicationsState.AppEntry app =
220                addPackageToPackageManager(PACKAGE_NAME, TimeUnit.DAYS.toMillis(800));
221        registerLastUse(PACKAGE_NAME, TimeUnit.DAYS.toMillis(801));
222
223        mBridge.updateExtraInfo(app, PACKAGE_NAME, 0);
224        UsageStatsState stats = (UsageStatsState) app.extraInfo;
225
226        assertThat(app.extraInfo).isNotNull();
227        assertThat(stats.daysSinceFirstInstall).isEqualTo(200);
228        assertThat(stats.daysSinceLastUse).isEqualTo(199);
229        assertThat(AppStateUsageStatsBridge.FILTER_USAGE_STATS.filterApp(app)).isTrue();
230    }
231
232    @Test
233    public void test_noThresholdFilter_oldUnusedApp_isValid() {
234        ApplicationsState.AppEntry app =
235                addPackageToPackageManager(PACKAGE_NAME, TimeUnit.DAYS.toMillis(800));
236        registerLastUse(PACKAGE_NAME, TimeUnit.DAYS.toMillis(801));
237
238        mBridge.updateExtraInfo(app, PACKAGE_NAME, 0);
239        UsageStatsState stats = (UsageStatsState) app.extraInfo;
240
241        assertThat(app.extraInfo).isNotNull();
242        assertThat(stats.daysSinceFirstInstall).isEqualTo(200);
243        assertThat(stats.daysSinceLastUse).isEqualTo(199);
244        assertThat(AppStateUsageStatsBridge.FILTER_NO_THRESHOLD.filterApp(app)).isTrue();
245    }
246
247    @Test
248    public void test_systemApps_areInvalid() {
249        ApplicationsState.AppEntry app =
250                addPackageToPackageManager(PACKAGE_NAME, TimeUnit.DAYS.toMillis(800));
251        registerLastUse(PACKAGE_NAME, TimeUnit.DAYS.toMillis(800));
252        app.info.flags = ApplicationInfo.FLAG_SYSTEM;
253
254        mBridge.updateExtraInfo(app, PACKAGE_NAME, 0);
255        UsageStatsState stats = (UsageStatsState) app.extraInfo;
256
257        assertThat(app.extraInfo).isNotNull();
258        assertThat(stats.daysSinceFirstInstall).isEqualTo(200);
259        assertThat(stats.daysSinceLastUse).isEqualTo(200);
260        assertThat(AppStateUsageStatsBridge.FILTER_USAGE_STATS.filterApp(app)).isFalse();
261    }
262
263    @Test
264    public void test_noThresholdFilter_systemApps_areInvalid() {
265        ApplicationsState.AppEntry app =
266                addPackageToPackageManager(PACKAGE_NAME, TimeUnit.DAYS.toMillis(800));
267        registerLastUse(PACKAGE_NAME, TimeUnit.DAYS.toMillis(800));
268        app.info.flags = ApplicationInfo.FLAG_SYSTEM;
269
270        mBridge.updateExtraInfo(app, PACKAGE_NAME, 0);
271        UsageStatsState stats = (UsageStatsState) app.extraInfo;
272
273        assertThat(app.extraInfo).isNotNull();
274        assertThat(stats.daysSinceFirstInstall).isEqualTo(200);
275        assertThat(stats.daysSinceLastUse).isEqualTo(200);
276        assertThat(AppStateUsageStatsBridge.FILTER_NO_THRESHOLD.filterApp(app)).isFalse();
277    }
278
279    @Test
280    public void test_persistentProcessApps_areInvalid() {
281        ApplicationsState.AppEntry app =
282                addPackageToPackageManager(PACKAGE_NAME, TimeUnit.DAYS.toMillis(800));
283        registerLastUse(PACKAGE_NAME, TimeUnit.DAYS.toMillis(800));
284        app.info.flags = ApplicationInfo.FLAG_PERSISTENT;
285
286        mBridge.updateExtraInfo(app, PACKAGE_NAME, 0);
287        UsageStatsState stats = (UsageStatsState) app.extraInfo;
288
289        assertThat(app.extraInfo).isNotNull();
290        assertThat(stats.daysSinceFirstInstall).isEqualTo(200);
291        assertThat(stats.daysSinceLastUse).isEqualTo(200);
292        assertThat(AppStateUsageStatsBridge.FILTER_USAGE_STATS.filterApp(app)).isFalse();
293    }
294
295    @Test
296    public void test_noThresholdFilter_persistentProcessApps_areInvalid() {
297        ApplicationsState.AppEntry app =
298                addPackageToPackageManager(PACKAGE_NAME, TimeUnit.DAYS.toMillis(800));
299        registerLastUse(PACKAGE_NAME, TimeUnit.DAYS.toMillis(800));
300        app.info.flags = ApplicationInfo.FLAG_PERSISTENT;
301
302        mBridge.updateExtraInfo(app, PACKAGE_NAME, 0);
303        UsageStatsState stats = (UsageStatsState) app.extraInfo;
304
305        assertThat(app.extraInfo).isNotNull();
306        assertThat(stats.daysSinceFirstInstall).isEqualTo(200);
307        assertThat(stats.daysSinceLastUse).isEqualTo(200);
308        assertThat(AppStateUsageStatsBridge.FILTER_NO_THRESHOLD.filterApp(app)).isFalse();
309    }
310
311    @Test
312    public void test_multipleApps_processCorrectly() {
313        ApplicationsState.AppEntry clearable =
314                addPackageToPackageManager(PACKAGE_CLEARABLE, TimeUnit.DAYS.toMillis(800));
315        registerLastUse(PACKAGE_CLEARABLE, TimeUnit.DAYS.toMillis(800));
316        mApps.add(clearable);
317        ApplicationsState.AppEntry tooNewtoDelete =
318                addPackageToPackageManager(PACKAGE_TOO_NEW_TO_DELETE, TimeUnit.DAYS.toMillis(1000));
319        registerLastUse(PACKAGE_TOO_NEW_TO_DELETE, TimeUnit.DAYS.toMillis(1000));
320        mApps.add(tooNewtoDelete);
321        ApplicationsState.AppEntry systemApp =
322                addPackageToPackageManager(PACKAGE_SYSTEM, TimeUnit.DAYS.toMillis(800));
323        registerLastUse(PACKAGE_SYSTEM, TimeUnit.DAYS.toMillis(800));
324        systemApp.info.flags = ApplicationInfo.FLAG_SYSTEM;
325        mApps.add(systemApp);
326        ApplicationsState.AppEntry persistentApp =
327                addPackageToPackageManager(PACKAGE_NAME, TimeUnit.DAYS.toMillis(800));
328        registerLastUse(PACKAGE_NAME, TimeUnit.DAYS.toMillis(800));
329        persistentApp.info.flags = ApplicationInfo.FLAG_PERSISTENT;
330        mApps.add(persistentApp);
331
332        mBridge.loadAllExtraInfo();
333
334        assertThat(AppStateUsageStatsBridge.FILTER_USAGE_STATS.filterApp(clearable)).isTrue();
335        assertThat(AppStateUsageStatsBridge.FILTER_USAGE_STATS.filterApp(tooNewtoDelete)).isFalse();
336        assertThat(AppStateUsageStatsBridge.FILTER_USAGE_STATS.filterApp(systemApp)).isFalse();
337        assertThat(AppStateUsageStatsBridge.FILTER_USAGE_STATS.filterApp(persistentApp)).isFalse();
338    }
339
340    @Test
341    public void test_noThresholdFilter_ignoresUsageForFiltering() {
342        ApplicationsState.AppEntry clearable =
343                addPackageToPackageManager(PACKAGE_CLEARABLE, TimeUnit.DAYS.toMillis(800));
344        registerLastUse(PACKAGE_CLEARABLE, TimeUnit.DAYS.toMillis(800));
345        mApps.add(clearable);
346        ApplicationsState.AppEntry tooNewtoDelete =
347                addPackageToPackageManager(PACKAGE_TOO_NEW_TO_DELETE, TimeUnit.DAYS.toMillis(1000));
348        registerLastUse(PACKAGE_TOO_NEW_TO_DELETE, TimeUnit.DAYS.toMillis(1000));
349        mApps.add(tooNewtoDelete);
350        ApplicationsState.AppEntry systemApp =
351                addPackageToPackageManager(PACKAGE_SYSTEM, TimeUnit.DAYS.toMillis(800));
352        registerLastUse(PACKAGE_SYSTEM, TimeUnit.DAYS.toMillis(800));
353        systemApp.info.flags = ApplicationInfo.FLAG_SYSTEM;
354        mApps.add(systemApp);
355        ApplicationsState.AppEntry persistentApp =
356                addPackageToPackageManager(PACKAGE_NAME, TimeUnit.DAYS.toMillis(800));
357        registerLastUse(PACKAGE_NAME, TimeUnit.DAYS.toMillis(800));
358        persistentApp.info.flags = ApplicationInfo.FLAG_PERSISTENT;
359        mApps.add(persistentApp);
360
361        mBridge.loadAllExtraInfo();
362
363        assertThat(AppStateUsageStatsBridge.FILTER_NO_THRESHOLD.filterApp(clearable)).isTrue();
364        assertThat(AppStateUsageStatsBridge.FILTER_NO_THRESHOLD.filterApp(tooNewtoDelete)).isTrue();
365        assertThat(AppStateUsageStatsBridge.FILTER_NO_THRESHOLD.filterApp(systemApp)).isFalse();
366        assertThat(AppStateUsageStatsBridge.FILTER_NO_THRESHOLD.filterApp(persistentApp)).isFalse();
367    }
368
369    @Test
370    public void testAppUsedOverOneYearAgoIsValid() {
371        ApplicationsState.AppEntry app =
372                addPackageToPackageManager(PACKAGE_NAME, TimeUnit.DAYS.toMillis(600));
373        registerLastUse(PACKAGE_NAME, TimeUnit.DAYS.toMillis(1000 - 366));
374
375        mBridge.updateExtraInfo(app, PACKAGE_NAME, 0);
376        UsageStatsState stats = (UsageStatsState) app.extraInfo;
377
378        assertThat(app.extraInfo).isNotNull();
379        assertThat(stats.daysSinceFirstInstall).isEqualTo(400);
380        assertThat(stats.daysSinceLastUse).isEqualTo(AppStateUsageStatsBridge.NEVER_USED);
381        assertThat(AppStateUsageStatsBridge.FILTER_USAGE_STATS.filterApp(app)).isTrue();
382    }
383
384    @Test
385    public void testStartEndIsBeforeEndTimeInQuery() {
386        ApplicationsState.AppEntry app =
387                addPackageToPackageManager(PACKAGE_NAME, TimeUnit.DAYS.toMillis(600));
388        registerLastUse(PACKAGE_NAME, TimeUnit.DAYS.toMillis(1000 - 366));
389        ArgumentCaptor<Long> startTimeCaptor = ArgumentCaptor.forClass(Long.class);
390        ArgumentCaptor<Long> endTimeCaptor = ArgumentCaptor.forClass(Long.class);
391
392        mBridge.updateExtraInfo(app, PACKAGE_NAME, 0);
393
394        verify(mUsageStatsManager, atLeastOnce())
395                .queryAndAggregateUsageStats(startTimeCaptor.capture(), endTimeCaptor.capture());
396        assertThat(startTimeCaptor.getValue()).isLessThan(endTimeCaptor.getValue());
397    }
398
399    private ApplicationsState.AppEntry addPackageToPackageManager(String packageName,
400            long installTime) {
401        PackageInfo testPackage = new PackageInfo();
402        testPackage.packageName = packageName;
403        testPackage.firstInstallTime = installTime;
404        mPm.addPackage(testPackage);
405        ApplicationsState.AppEntry app = mock(ApplicationsState.AppEntry.class);
406        ApplicationInfo info = mock(ApplicationInfo.class);
407        info.packageName = packageName;
408        app.info = info;
409        return app;
410    }
411
412    private void registerLastUse(String packageName, long time) {
413        UsageStats usageStats = mock(UsageStats.class);
414        when(usageStats.getPackageName()).thenReturn(packageName);
415        when(usageStats.getLastTimeUsed()).thenReturn(time);
416        mUsageStats.put(packageName, usageStats);
417    }
418
419    private class FakeClock extends AppStateUsageStatsBridge.Clock {
420        public long time;
421
422        @Override
423        public long getCurrentTime() {
424            return time;
425        }
426    }
427}
428