• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2010 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.providers.applications;
18 
19 import android.app.SearchManager;
20 import android.content.ComponentName;
21 import android.content.Context;
22 import android.content.pm.PackageManager;
23 import android.database.Cursor;
24 import android.net.Uri;
25 import android.provider.Applications;
26 import android.test.ProviderTestCase2;
27 import android.test.suitebuilder.annotation.SmallTest;
28 
29 import java.util.concurrent.FutureTask;
30 
31 
32 /**
33  * Instrumentation test for the ApplicationsProvider.
34  *
35  * The tests use an IsolatedContext, and are not affected by the real list of
36  * applications on the device. The ApplicationsProvider's persistent database
37  * is also created in an isolated context so it doesn't interfere with the
38  * database of the actual ApplicationsProvider installed on the device.
39  */
40 @SmallTest
41 public class ApplicationsProviderTest extends ProviderTestCase2<ApplicationsProviderForTesting> {
42 
43     private ApplicationsProviderForTesting mProvider;
44 
45     private MockActivityManager mMockActivityManager;
46 
ApplicationsProviderTest()47     public ApplicationsProviderTest() {
48         super(ApplicationsProviderForTesting.class, Applications.AUTHORITY);
49     }
50 
51     @Override
setUp()52     protected void setUp() throws Exception {
53         super.setUp();
54         mProvider = getProvider();
55         mMockActivityManager = new MockActivityManager();
56     }
57 
58     /**
59      * Ensures that the ApplicationsProvider is in a ready-to-test state.
60      */
initProvider(ApplicationsProviderForTesting provider)61     private void initProvider(ApplicationsProviderForTesting provider) throws Exception {
62         // Decouple the provider from Android's real list of applications.
63         MockPackageManager mockPackageManager = new MockPackageManager();
64         addDefaultTestPackages(mockPackageManager);
65 
66         initProvider(provider, mockPackageManager);
67     }
68 
initProvider(ApplicationsProviderForTesting provider, MockPackageManager mockPackageManager)69     private void initProvider(ApplicationsProviderForTesting provider,
70             MockPackageManager mockPackageManager) throws Exception {
71         provider.setMockPackageManager(mockPackageManager);
72         provider.setMockActivityManager(mMockActivityManager);
73 
74         assertTrue(provider.dispatchNextMessage());
75     }
76 
77     /**
78      * Register a few default applications with the ApplicationsProvider that
79      * tests can query.
80      */
addDefaultTestPackages(MockPackageManager mockPackageManager)81     private void addDefaultTestPackages(MockPackageManager mockPackageManager) {
82         mockPackageManager.addPackage(
83                 "Email", new ComponentName("com.android.email", "com.android.email.MainView"));
84         mockPackageManager.addPackage(
85                 "Ebay", new ComponentName("com.android.ebay", "com.android.ebay.Shopping"));
86         mockPackageManager.addPackage(
87                 "Fakeapp", new ComponentName("com.android.fakeapp", "com.android.fakeapp.FakeView"));
88 
89         // Apps that can be used to test ordering.
90         mockPackageManager.addPackage("AlphabeticA", new ComponentName("a", "a.AView"));
91         mockPackageManager.addPackage("AlphabeticB", new ComponentName("b", "b.BView"));
92         mockPackageManager.addPackage("AlphabeticC", new ComponentName("c", "c.CView"));
93         mockPackageManager.addPackage("AlphabeticD", new ComponentName("d", "d.DView"));
94         mockPackageManager.addPackage("AlphabeticD2", new ComponentName("d", "d.DView2"));
95     }
96 
testSearch_singleResult()97     public void testSearch_singleResult() throws Exception {
98         initProvider(mProvider);
99         testSearch("ema", "Email");
100     }
101 
testSearch_multipleResults()102     public void testSearch_multipleResults() throws Exception {
103         initProvider(mProvider);
104         testSearch("e", "Ebay", "Email");
105     }
106 
testSearch_noResults()107     public void testSearch_noResults() throws Exception {
108         initProvider(mProvider);
109         testSearch("nosuchapp");
110     }
111 
testSearch_orderingIsAlphabeticByDefault()112     public void testSearch_orderingIsAlphabeticByDefault() throws Exception {
113         initProvider(mProvider);
114         testSearch("alphabetic", "AlphabeticA", "AlphabeticB", "AlphabeticC", "AlphabeticD",
115                 "AlphabeticD2");
116     }
117 
testSearch_emptySearchQueryReturnsEverything()118     public void testSearch_emptySearchQueryReturnsEverything() throws Exception {
119         initProvider(mProvider);
120         testSearch("",
121                 "AlphabeticA", "AlphabeticB", "AlphabeticC", "AlphabeticD", "AlphabeticD2",
122                 "Ebay", "Email", "Fakeapp");
123     }
124 
testSearch_appsAreRankedByUsageTimeOnStartup()125     public void testSearch_appsAreRankedByUsageTimeOnStartup() throws Exception {
126         mMockActivityManager.addLastResumeTime("d", "d.DView", 3);
127         mMockActivityManager.addLastResumeTime("b", "b.BView", 1);
128         // Missing usage time for "a".
129         mMockActivityManager.addLastResumeTime("c", "c.CView", 0);
130 
131         // Launch count database is populated on startup.
132         mProvider.setHasGlobalSearchPermission(true);
133 
134         initProvider(mProvider);
135 
136         // New ranking: D, B, A, C (first by launch count, then
137         // - if the launch counts of two apps are equal - alphabetically)
138         testSearch("alphabetic", "AlphabeticD", "AlphabeticB", "AlphabeticA", "AlphabeticC",
139                 "AlphabeticD2");
140     }
141 
testSearch_appsAreRankedByResumeTimeAfterUpdate()142     public void testSearch_appsAreRankedByResumeTimeAfterUpdate() throws Exception {
143         initProvider(mProvider);
144         mProvider.setHasGlobalSearchPermission(true);
145 
146         mMockActivityManager.addLastResumeTime("d", "d.DView", 3);
147         mMockActivityManager.addLastResumeTime("b", "b.BView", 1);
148         // Missing launch count for "a".
149         mMockActivityManager.addLastResumeTime("c", "c.CView", 0);
150 
151         // Fetch new data from usage stat provider (in the real instance this
152         // is triggered by a zero-query from global search).
153         mProvider.updateUsageStats();
154 
155         // New ranking: D, B, A, C (first by launch count, then
156         // - if the launch counts of two apps are equal - alphabetically)
157         testSearch("alphabetic", "AlphabeticD", "AlphabeticB", "AlphabeticA", "AlphabeticC",
158                 "AlphabeticD2");
159     }
160 
testSearch_noLastAccessTimesWithoutPermission()161     public void testSearch_noLastAccessTimesWithoutPermission() throws Exception {
162         initProvider(mProvider);
163         mProvider.setHasGlobalSearchPermission(false);
164         mMockActivityManager.addLastResumeTime("d", "d.DView", 1);
165         mMockActivityManager.addLastResumeTime("b", "b.BView", 2);
166         mMockActivityManager.addLastResumeTime("c", "c.CView", 3);
167 
168         assertNull(getGlobalSearchCursor("", false));
169 
170         Cursor cursor = getGlobalSearchCursor("alphabetic", false);
171         assertEquals(-1, cursor.getColumnIndex(SearchManager.SUGGEST_COLUMN_LAST_ACCESS_HINT));
172     }
173 
testSearch_lastAccessTimes()174     public void testSearch_lastAccessTimes() throws Exception {
175         initProvider(mProvider);
176         mProvider.setHasGlobalSearchPermission(true);
177         mMockActivityManager.addLastResumeTime("d", "d.DView", 1);
178         mMockActivityManager.addLastResumeTime("b", "b.BView", 2);
179         mMockActivityManager.addLastResumeTime("c", "c.CView", 3);
180 
181         testLastAccessTimes("", true, 3, 2, 1, 0, 0, 0, 0, 0, 0, 0);
182 
183         testLastAccessTimes("alphabetic", true, 3, 2, 1, 0, 0);
184 
185         // Update the last resume time of "c".
186         mMockActivityManager.addLastResumeTime("c", "c.CView", 5);
187         // Without a refresh, we should see the same results as before.
188         testLastAccessTimes("alphabetic", false, 3, 2, 1, 0, 0);
189         // If we refresh, we should see the change.
190         testLastAccessTimes("alphabetic", true, 5, 2, 1, 0, 0);
191     }
192 
193     /**
194      * The ApplicationsProvider must only rank by launch count if the caller
195      * is a privileged application - ordering apps by launch count when asked
196      * by a regular application would leak information about user behavior.
197      */
testSearch_notAllowedToRankByLaunchCount()198     public void testSearch_notAllowedToRankByLaunchCount() throws Exception {
199         initProvider(mProvider);
200         // Simulate non-privileged calling application.
201         mProvider.setHasGlobalSearchPermission(false);
202 
203         mMockActivityManager.addLastResumeTime("d", "d.DView", 3);
204         mMockActivityManager.addLastResumeTime("b", "b.BView", 1);
205         mMockActivityManager.addLastResumeTime("a", "a.AView", 0);
206         mMockActivityManager.addLastResumeTime("c", "c.CView", 0);
207 
208         // Fetch new data from launch count provider.
209         mProvider.updateUsageStats();
210 
211         // Launch count information mustn't be leaked - ranking is still
212         // alphabetic.
213         testSearch("alphabetic", "AlphabeticA", "AlphabeticB", "AlphabeticC", "AlphabeticD",
214                 "AlphabeticD2");
215     }
216 
testSearch_disabledPackage()217     public void testSearch_disabledPackage() throws Exception {
218         MockPackageManager mockPackageManager = new MockPackageManager();
219         mockPackageManager.addPackage("DisabledPackageApp1",
220                 new ComponentName("dp", "dp.DisView1"));
221         mockPackageManager.addPackage("DisabledPackageApp2",
222                 new ComponentName("dp", "dp.DisView2"),
223                 PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
224                 PackageManager.COMPONENT_ENABLED_STATE_DEFAULT);
225         initProvider(mProvider, mockPackageManager);
226 
227         mProvider.setHasGlobalSearchPermission(true);
228         testSearch("dis");
229     }
230 
testSearch_disabledComponent()231     public void testSearch_disabledComponent() throws Exception {
232         MockPackageManager mockPackageManager = new MockPackageManager();
233         mockPackageManager.addPackage("DisabledApp1", new ComponentName("da", "da.DaView1"),
234                 PackageManager.COMPONENT_ENABLED_STATE_DEFAULT,
235                 PackageManager.COMPONENT_ENABLED_STATE_DISABLED);
236         mockPackageManager.addPackage("DisabledApp2", new ComponentName("da", "da.DaView2"),
237                 PackageManager.COMPONENT_ENABLED_STATE_DEFAULT,
238                 PackageManager.COMPONENT_ENABLED_STATE_DEFAULT);
239         initProvider(mProvider, mockPackageManager);
240 
241         mProvider.setHasGlobalSearchPermission(true);
242         testSearch("dis", "DisabledApp2");
243     }
244 
testSearch(String searchQuery, String... expectedResultsInOrder)245     private void testSearch(String searchQuery, String... expectedResultsInOrder) {
246         Cursor cursor = Applications.search(getMockContentResolver(), searchQuery);
247 
248         assertNotNull(cursor);
249         assertFalse(cursor.isClosed());
250 
251         verifySearchResults(cursor, expectedResultsInOrder);
252 
253         cursor.close();
254     }
255 
verifySearchResults(Cursor cursor, String... expectedResultsInOrder)256     private void verifySearchResults(Cursor cursor, String... expectedResultsInOrder) {
257         int expectedResultCount = expectedResultsInOrder.length;
258         assertEquals("Wrong number of app search results.",
259                 expectedResultCount, cursor.getCount());
260 
261         if (expectedResultCount > 0) {
262             cursor.moveToFirst();
263             int nameIndex = cursor.getColumnIndex(ApplicationsProvider.NAME);
264             // Verify that the actual results match the expected ones.
265             for (int i = 0; i < cursor.getCount(); i++) {
266                 assertEquals("Wrong search result at position " + i,
267                         expectedResultsInOrder[i], cursor.getString(nameIndex));
268                 cursor.moveToNext();
269             }
270         }
271     }
272 
getGlobalSearchCursor(String searchQuery, boolean refresh)273     private Cursor getGlobalSearchCursor(String searchQuery, boolean refresh) {
274         Uri.Builder uriBuilder = Applications.CONTENT_URI.buildUpon();
275         uriBuilder.appendPath(SearchManager.SUGGEST_URI_PATH_QUERY).appendPath(searchQuery);
276         if (refresh) {
277             uriBuilder.appendQueryParameter(ApplicationsProvider.REFRESH_STATS, "");
278         }
279         return getMockContentResolver().query(uriBuilder.build(), null, null, null, null);
280     }
281 
testLastAccessTimes(String searchQuery, boolean refresh, int... expectedLastAccessTimesInOrder)282     private void testLastAccessTimes(String searchQuery, boolean refresh,
283             int... expectedLastAccessTimesInOrder) {
284         Cursor cursor = getGlobalSearchCursor(searchQuery, refresh);
285 
286         assertNotNull(cursor);
287         assertFalse(cursor.isClosed());
288 
289         verifyLastAccessTimes(cursor, expectedLastAccessTimesInOrder);
290 
291         cursor.close();
292     }
293 
verifyLastAccessTimes(Cursor cursor, int... expectedLastAccessTimesInOrder)294     private void verifyLastAccessTimes(Cursor cursor, int... expectedLastAccessTimesInOrder) {
295         cursor.moveToFirst();
296         int lastAccessTimeIndex = cursor.getColumnIndex(
297                 SearchManager.SUGGEST_COLUMN_LAST_ACCESS_HINT);
298         // Verify that the actual results match the expected ones.
299         for (int i = 0; i < cursor.getCount(); i++) {
300             assertEquals("Wrong last-access time at position " + i,
301                     expectedLastAccessTimesInOrder[i], cursor.getInt(lastAccessTimeIndex));
302             cursor.moveToNext();
303         }
304     }
305 }
306