OSDN Git Service

Add double-tap & lift gestures to display settings
[android-x86/packages-apps-Settings.git] / tests / robotests / src / com / android / settings / search2 / DatabaseIndexingManagerTest.java
1 /*
2  * Copyright (C) 2017 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
18 package com.android.settings.search2;
19
20 import android.annotation.NonNull;
21 import android.annotation.Nullable;
22 import android.content.ContentProvider;
23 import android.content.ContentValues;
24 import android.content.Context;
25 import android.content.Intent;
26 import android.content.pm.PackageManager;
27 import android.content.pm.ProviderInfo;
28 import android.content.pm.ResolveInfo;
29 import android.database.Cursor;
30 import android.database.MatrixCursor;
31 import android.database.sqlite.SQLiteDatabase;
32 import android.net.Uri;
33 import android.provider.SearchIndexableResource;
34 import android.provider.SearchIndexablesContract;
35 import android.util.ArrayMap;
36 import com.android.settings.R;
37 import com.android.settings.SettingsRobolectricTestRunner;
38 import com.android.settings.TestConfig;
39 import com.android.settings.search.IndexDatabaseHelper;
40 import com.android.settings.search.SearchIndexableRaw;
41 import com.android.settings.testutils.DatabaseTestUtils;
42 import com.android.settings.testutils.shadow.ShadowDatabaseIndexingUtils;
43 import com.android.settings.testutils.shadow.ShadowRunnableAsyncTask;
44 import org.junit.After;
45 import org.junit.Before;
46 import org.junit.Test;
47 import org.junit.runner.RunWith;
48 import org.mockito.Mock;
49 import org.mockito.MockitoAnnotations;
50 import org.robolectric.RuntimeEnvironment;
51 import org.robolectric.annotation.Config;
52 import org.robolectric.shadows.ShadowContentResolver;
53
54 import java.util.ArrayList;
55 import java.util.Arrays;
56 import java.util.HashMap;
57 import java.util.HashSet;
58 import java.util.List;
59 import java.util.Locale;
60 import java.util.Map;
61 import java.util.Set;
62
63 import static com.google.common.truth.Truth.assertThat;
64 import static org.mockito.Matchers.any;
65 import static org.mockito.Matchers.anyInt;
66 import static org.mockito.Matchers.anyList;
67 import static org.mockito.Matchers.anyMap;
68 import static org.mockito.Matchers.anyString;
69 import static org.mockito.Mockito.doReturn;
70 import static org.mockito.Mockito.spy;
71 import static org.mockito.Mockito.times;
72 import static org.mockito.Mockito.verify;
73 import static org.mockito.Mockito.when;
74
75 @RunWith(SettingsRobolectricTestRunner.class)
76 @Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION,
77         shadows={ShadowRunnableAsyncTask.class})
78 public class DatabaseIndexingManagerTest {
79     private final String localeStr = "en_US";
80
81     private final int rank = 8;
82     private final String title = "title\u2011title";
83     private final String updatedTitle = "title-title";
84     private final String normalizedTitle = "titletitle";
85     private final String summaryOn = "summary\u2011on";
86     private final String updatedSummaryOn = "summary-on";
87     private final String normalizedSummaryOn = "summaryon";
88     private final String summaryOff = "summary\u2011off";
89     private final String updatedSummaryOff = "summary-off";
90     private final String normalizedSummaryOff = "summaryoff";
91     private final String entries = "entries";
92     private final String keywords = "keywords, keywordss, keywordsss";
93     private final String spaceDelimittedKeywords = "keywords keywordss keywordsss";
94     private final String screenTitle = "screen title";
95     private final String className = "class name";
96     private final int iconResId = 0xff;
97     private final String action = "action";
98     private final String targetPackage = "target package";
99     private final String targetClass = "target class";
100     private final String packageName = "package name";
101     private final String key = "key";
102     private final int userId = -1;
103     private final boolean enabled = true;
104
105     private final String AUTHORITY_ONE = "authority";
106     private final String PACKAGE_ONE = "com.android.settings";
107
108     private final String TITLE_ONE = "title one";
109     private final String TITLE_TWO = "title two";
110     private final String KEY_ONE = "key one";
111     private final String KEY_TWO = "key two";
112
113     private Context mContext;
114
115     private DatabaseIndexingManager mManager;
116     private SQLiteDatabase mDb;
117
118     @Mock
119     private PackageManager mPackageManager;
120
121     @Before
122     public void setUp() {
123         MockitoAnnotations.initMocks(this);
124         mContext = spy(RuntimeEnvironment.application);
125         mManager = spy(new DatabaseIndexingManager(mContext,"com.android.settings"));
126         mDb = IndexDatabaseHelper.getInstance(mContext).getWritableDatabase();
127
128         doReturn(mPackageManager).when(mContext).getPackageManager();
129     }
130
131     @After
132     public void cleanUp() {
133         DatabaseTestUtils.clearDb();
134     }
135
136     @Test
137     public void testDatabaseSchema() {
138         Cursor dbCursor = mDb.query("prefs_index", null, null, null, null, null, null);
139         List<String> columnNames = new ArrayList<>(Arrays.asList(dbCursor.getColumnNames()));
140         // Note that docid is not included.
141         List<String> expColumnNames = new ArrayList<>(Arrays.asList(new String[]{
142                 "locale",
143                 "data_rank",
144                 "data_title",
145                 "data_title_normalized",
146                 "data_summary_on",
147                 "data_summary_on_normalized",
148                 "data_summary_off",
149                 "data_summary_off_normalized",
150                 "data_entries",
151                 "data_keywords",
152                 "class_name",
153                 "screen_title",
154                 "intent_action",
155                 "intent_target_package",
156                 "intent_target_class",
157                 "icon",
158                 "enabled",
159                 "data_key_reference",
160                 "user_id",
161                 "payload_type",
162                 "payload"
163         }));
164         // Prevent database schema regressions
165         assertThat(columnNames).containsAllIn(expColumnNames);
166     }
167
168     // Tests for the flow: IndexOneRaw -> UpdateOneRowWithFilteredData -> UpdateOneRow
169
170     @Test
171     public void testInsertRawColumn_rowInserted() {
172         SearchIndexableRaw raw = getFakeRaw();
173         mManager.indexOneSearchIndexableData(mDb, localeStr, raw, null /* Non-indexable keys */);
174         Cursor cursor = mDb.rawQuery("SELECT * FROM prefs_index", null);
175         assertThat(cursor.getCount()).isEqualTo(1);
176     }
177
178     @Test
179     public void testInsertRawColumn_rowMatches() {
180         SearchIndexableRaw raw = getFakeRaw();
181         mManager.indexOneSearchIndexableData(mDb, localeStr, raw, null /* Non-indexable keys */);
182         Cursor cursor = mDb.rawQuery("SELECT * FROM prefs_index", null);
183         cursor.moveToPosition(0);
184
185         // Locale
186         assertThat(cursor.getString(0)).isEqualTo(localeStr);
187         // Data Rank
188         assertThat(cursor.getInt(1)).isEqualTo(raw.rank);
189         // Data Title
190         assertThat(cursor.getString(2)).isEqualTo(updatedTitle);
191         // Normalized Title
192         assertThat(cursor.getString(3)).isEqualTo(normalizedTitle);
193         // Summary On
194         assertThat(cursor.getString(4)).isEqualTo(updatedSummaryOn);
195         // Summary On Normalized
196         assertThat(cursor.getString(5)).isEqualTo(normalizedSummaryOn);
197         // Summary Off
198         assertThat(cursor.getString(6)).isEqualTo(updatedSummaryOff);
199         // Summary off normalized
200         assertThat(cursor.getString(7)).isEqualTo(normalizedSummaryOff);
201         // Entries
202         assertThat(cursor.getString(8)).isEqualTo(raw.entries);
203         // Keywords
204         assertThat(cursor.getString(9)).isEqualTo(spaceDelimittedKeywords);
205         // Screen Title
206         assertThat(cursor.getString(10)).isEqualTo(raw.screenTitle);
207         // Class Name
208         assertThat(cursor.getString(11)).isEqualTo(raw.className);
209         // Icon
210         assertThat(cursor.getInt(12)).isEqualTo(raw.iconResId);
211         // Intent Action
212         assertThat(cursor.getString(13)).isEqualTo(raw.intentAction);
213         // Target Package
214         assertThat(cursor.getString(14)).isEqualTo(raw.intentTargetPackage);
215         // Target Class
216         assertThat(cursor.getString(15)).isEqualTo(raw.intentTargetClass);
217         // Enabled
218         assertThat(cursor.getInt(16) == 1).isEqualTo(raw.enabled);
219         // Data ref key
220         assertThat(cursor.getString(17)).isNotNull();
221         // User Id
222         assertThat(cursor.getInt(18)).isEqualTo(raw.userId);
223         // Payload Type - default is 0
224         assertThat(cursor.getInt(19)).isEqualTo(0);
225         // Payload
226         assertThat(cursor.getBlob(20)).isNull();
227     }
228
229     @Test
230     public void testInsertRawColumn_mismatchedLocale_noRowInserted() {
231         SearchIndexableRaw raw = getFakeRaw("ca-fr");
232         mManager.indexOneSearchIndexableData(mDb, localeStr, raw, null /* Non-indexable keys */);
233         Cursor cursor = mDb.rawQuery("SELECT * FROM prefs_index", null);
234         assertThat(cursor.getCount()).isEqualTo(0);
235     }
236
237     // Tests for the flow: IndexOneResource -> IndexFromResource ->
238     //                     UpdateOneRowWithFilteredData -> UpdateOneRow
239
240     @Test
241     public void testNullResource_NothingInserted() {
242         mManager.indexOneSearchIndexableData(mDb, localeStr, null /* searchIndexableResource */,
243                 new HashMap<>());
244         Cursor cursor = mDb.rawQuery("SELECT * FROM prefs_index", null);
245         assertThat(cursor.getCount()).isEqualTo(0);
246     }
247
248     @Test
249     public void testAddResource_RowsInserted() {
250         SearchIndexableResource resource = getFakeResource(R.xml.display_settings);
251         mManager.indexOneSearchIndexableData(mDb, localeStr, resource, new HashMap<>());
252         Cursor cursor = mDb.rawQuery("SELECT * FROM prefs_index", null);
253         assertThat(cursor.getCount()).isEqualTo(18);
254     }
255
256     @Test
257     public void testAddResource_withNIKs_rowsInsertedDisabled() {
258         SearchIndexableResource resource = getFakeResource(R.xml.display_settings);
259         // Only add 2 of 16 items to be disabled.
260         String[] keys = {"brightness", "wallpaper"};
261         Map<String, Set<String>> niks = getNonIndexableKeys(keys);
262
263         mManager.indexOneSearchIndexableData(mDb, localeStr, resource, niks);
264
265         Cursor cursor = mDb.rawQuery("SELECT * FROM prefs_index WHERE enabled = 0", null);
266         assertThat(cursor.getCount()).isEqualTo(2);
267         cursor = mDb.rawQuery("SELECT * FROM prefs_index WHERE enabled = 1", null);
268         assertThat(cursor.getCount()).isEqualTo(16);
269     }
270
271     @Test
272     public void testAddResourceHeader_rowsMatch() {
273         SearchIndexableResource resource = getFakeResource(R.xml.application_settings);
274         mManager.indexOneSearchIndexableData(mDb, localeStr, resource, new HashMap<>());
275
276         Cursor cursor = mDb.rawQuery("SELECT * FROM prefs_index ORDER BY data_title", null);
277         cursor.moveToPosition(1);
278
279         // Locale
280         assertThat(cursor.getString(0)).isEqualTo(localeStr);
281         // Data Rank
282         assertThat(cursor.getInt(1)).isEqualTo(rank);
283         // Data Title
284         assertThat(cursor.getString(2)).isEqualTo("App info");
285         // Normalized Title
286         assertThat(cursor.getString(3)).isEqualTo("app info");
287         // Summary On
288         assertThat(cursor.getString(4)).isEqualTo("Manage apps, set up quick launch shortcuts");
289         // Summary On Normalized
290         assertThat(cursor.getString(5)).isEqualTo("manage apps, set up quick launch shortcuts");
291         // Summary Off - only on for checkbox preferences
292         assertThat(cursor.getString(6)).isEmpty();
293         // Summary off normalized - only on for checkbox preferences
294         assertThat(cursor.getString(7)).isEmpty();
295         // Entries - only on for list preferences
296         assertThat(cursor.getString(8)).isNull();
297         // Keywords
298         assertThat(cursor.getString(9)).isEmpty();
299         // Screen Title
300         assertThat(cursor.getString(10)).isEqualTo("App info");
301         // Class Name
302         assertThat(cursor.getString(11)).isEqualTo(className);
303         // Icon
304         assertThat(cursor.getInt(12)).isEqualTo(iconResId);
305         // Intent Action
306         assertThat(cursor.getString(13)).isEqualTo(action);
307         // Target Package
308         assertThat(cursor.getString(14)).isEqualTo(targetPackage);
309         // Target Class
310         assertThat(cursor.getString(15)).isEqualTo(targetClass);
311         // Enabled
312         assertThat(cursor.getInt(16) == 1).isEqualTo(enabled);
313         // Data ref key
314         assertThat(cursor.getString(17)).isEqualTo("applications_settings");
315         // User Id
316         assertThat(cursor.getInt(18)).isEqualTo(userId);
317         // Payload Type - default is 0
318         assertThat(cursor.getInt(19)).isEqualTo(0);
319         // Payload - should be updated to real payloads as controllers are added
320         assertThat(cursor.getBlob(20)).isNull();
321     }
322
323     @Test
324     public void testAddResource_withChildFragment_shouldUpdateSiteMapDb() {
325         // FIXME: This test was failing. (count = 6 at the end)
326
327 //        SearchIndexableResource resource = getFakeResource(R.xml.network_and_internet);
328 //        mManager.indexOneSearchIndexableData(mDb, localeStr, resource,
329 //                new HashMap<>());
330 //        Cursor query = mDb.query(IndexDatabaseHelper.Tables.TABLE_SITE_MAP, SITE_MAP_COLUMNS,
331 //                null, null, null, null, null);
332 //        query.moveToPosition(-1);
333 //        int count = 0;
334 //        while (query.moveToNext()) {
335 //            count++;
336 //            assertThat(query.getString(query.getColumnIndex(SiteMapColumns.PARENT_CLASS)))
337 //                    .isEqualTo(className);
338 //            assertThat(query.getString(query.getColumnIndex(SiteMapColumns.PARENT_TITLE)))
339 //                    .isEqualTo(mContext.getString(R.string.network_dashboard_title));
340 //            assertThat(query.getString(query.getColumnIndex(SiteMapColumns.CHILD_CLASS)))
341 //                    .isNotEmpty();
342 //            assertThat(query.getString(query.getColumnIndex(SiteMapColumns.CHILD_TITLE)))
343 //                    .isNotEmpty();
344 //        }
345 //        assertThat(count).isEqualTo(5);
346     }
347
348     @Test
349     public void testAddResource_customSetting_rowsMatch() {
350         SearchIndexableResource resource = getFakeResource(R.xml.swipe_to_notification_settings);
351         mManager.indexOneSearchIndexableData(mDb, localeStr, resource, new HashMap<>());
352         final String prefTitle =
353                 mContext.getString(R.string.fingerprint_swipe_for_notifications_title);
354         final String prefSummary =
355                 mContext.getString(R.string.fingerprint_swipe_for_notifications_summary);
356         Cursor cursor = mDb.rawQuery(
357                 "SELECT * FROM prefs_index where data_title='" + prefTitle + "'", null);
358         cursor.moveToFirst();
359
360         // Locale
361         assertThat(cursor.getString(0)).isEqualTo(localeStr);
362         // Data Rank
363         assertThat(cursor.getInt(1)).isEqualTo(rank);
364         // Data Title
365         assertThat(cursor.getString(2)).isEqualTo(prefTitle);
366         // Normalized Title
367         assertThat(cursor.getString(3)).isEqualTo(prefTitle.toLowerCase());
368         // Summary On
369         assertThat(cursor.getString(4)).isEqualTo(prefSummary);
370         // Summary On Normalized
371         assertThat(cursor.getString(5)).isEqualTo(prefSummary.toLowerCase());
372         // Summary Off - only on for checkbox preferences
373         assertThat(cursor.getString(6)).isEmpty();
374         // Summary off normalized - only on for checkbox preferences
375         assertThat(cursor.getString(7)).isEmpty();
376         // Entries - only on for list preferences
377         assertThat(cursor.getString(8)).isNull();
378         // Keywords
379         assertThat(cursor.getString(9)).isEmpty();
380         // Screen Title
381         assertThat(cursor.getString(10)).isEqualTo(
382                 mContext.getString(R.string.fingerprint_swipe_for_notifications_title));
383         // Class Name
384         assertThat(cursor.getString(11)).isEqualTo(className);
385         // Icon
386         assertThat(cursor.getInt(12)).isEqualTo(iconResId);
387         // Intent Action
388         assertThat(cursor.getString(13)).isEqualTo(action);
389         // Target Package
390         assertThat(cursor.getString(14)).isEqualTo(targetPackage);
391         // Target Class
392         assertThat(cursor.getString(15)).isEqualTo(targetClass);
393         // Enabled
394         assertThat(cursor.getInt(16) == 1).isEqualTo(enabled);
395         // Data ref key
396         assertThat(cursor.getString(17)).isEqualTo("gesture_swipe_down_fingerprint");
397         // User Id
398         assertThat(cursor.getInt(18)).isEqualTo(userId);
399         // Payload Type - default is 0
400         assertThat(cursor.getInt(19)).isEqualTo(0);
401         // Payload - should be updated to real payloads as controllers are added
402         assertThat(cursor.getBlob(20)).isNull();
403     }
404
405     @Test
406     public void testAddResource_checkboxPreference_rowsMatch() {
407         SearchIndexableResource resource = getFakeResource(R.xml.application_settings);
408         mManager.indexOneSearchIndexableData(mDb, localeStr, resource, new HashMap<>());
409
410         /* Should return 6 results, with the following titles:
411          * Advanced Settings, Apps, Manage Apps, Preferred install location, Running Services
412          */
413         Cursor cursor = mDb.rawQuery("SELECT * FROM prefs_index ORDER BY data_title", null);
414         cursor.moveToPosition(0);
415         // Locale
416         assertThat(cursor.getString(0)).isEqualTo(localeStr);
417         // Data Rank
418         assertThat(cursor.getInt(1)).isEqualTo(rank);
419         // Data Title
420         assertThat(cursor.getString(2)).isEqualTo("Advanced settings");
421         // Normalized Title
422         assertThat(cursor.getString(3)).isEqualTo("advanced settings");
423         // Summary On
424         assertThat(cursor.getString(4)).isEqualTo("Enable more settings options");
425         // Summary On Normalized
426         assertThat(cursor.getString(5)).isEqualTo("enable more settings options");
427         // Summary Off
428         assertThat(cursor.getString(6)).isEqualTo("Enable more settings options");
429         // Summary Off
430         assertThat(cursor.getString(7)).isEqualTo("enable more settings options");
431         // Entries - only on for list preferences
432         assertThat(cursor.getString(8)).isNull();
433         // Keywords
434         assertThat(cursor.getString(9)).isEmpty();
435         // Screen Title
436         assertThat(cursor.getString(10)).isEqualTo("App info");
437         // Class Name
438         assertThat(cursor.getString(11)).isEqualTo(className);
439         // Icon
440         assertThat(cursor.getInt(12)).isEqualTo(iconResId);
441         // Intent Action
442         assertThat(cursor.getString(13)).isEqualTo(action);
443         // Target Package
444         assertThat(cursor.getString(14)).isEqualTo(targetPackage);
445         // Target Class
446         assertThat(cursor.getString(15)).isEqualTo(targetClass);
447         // Enabled
448         assertThat(cursor.getInt(16) == 1).isEqualTo(enabled);
449         // Data ref key
450         assertThat(cursor.getString(17)).isEqualTo("toggle_advanced_settings");
451         // User Id
452         assertThat(cursor.getInt(18)).isEqualTo(userId);
453         // Payload Type - default is 0
454         assertThat(cursor.getInt(19)).isEqualTo(0);
455         // Payload - should be updated to real payloads as controllers are added
456         assertThat(cursor.getBlob(20)).isNull();
457     }
458
459     @Test
460     public void testAddResource_listPreference_rowsMatch() {
461         SearchIndexableResource resource = getFakeResource(R.xml.application_settings);
462         mManager.indexOneSearchIndexableData(mDb, localeStr, resource, new HashMap<>());
463
464         Cursor cursor = mDb.rawQuery("SELECT * FROM prefs_index ORDER BY data_title", null);
465         cursor.moveToPosition(3);
466         // Locale
467         assertThat(cursor.getString(0)).isEqualTo(localeStr);
468         // Data Rank
469         assertThat(cursor.getInt(1)).isEqualTo(rank);
470         // Data Title
471         assertThat(cursor.getString(2)).isEqualTo("Preferred install location");
472         // Normalized Title
473         assertThat(cursor.getString(3)).isEqualTo("preferred install location");
474         // Summary On
475         assertThat(cursor.getString(4)).isEqualTo(
476                 "Change the preferred installation location for new apps");
477         // Summary On Normalized
478         assertThat(cursor.getString(5)).isEqualTo(
479                 "change the preferred installation location for new apps");
480         // Summary Off - only on for checkbox preferences
481         assertThat(cursor.getString(6)).isEmpty();
482         // Summary off normalized - only on for checkbox preferences
483         assertThat(cursor.getString(7)).isEmpty();
484         // Entries - only on for list preferences
485         assertThat(cursor.getString(8)).isEqualTo("Internal device storage|Removable SD card|" +
486                 "Let the system decide|");
487         // Keywords
488         assertThat(cursor.getString(9)).isEmpty();
489         // Screen Title
490         assertThat(cursor.getString(10)).isEqualTo("App info");
491         // Class Name
492         assertThat(cursor.getString(11)).isEqualTo(className);
493         // Icon
494         assertThat(cursor.getInt(12)).isEqualTo(iconResId);
495         // Intent Action
496         assertThat(cursor.getString(13)).isEqualTo(action);
497         // Target Package
498         assertThat(cursor.getString(14)).isEqualTo(targetPackage);
499         // Target Class
500         assertThat(cursor.getString(15)).isEqualTo(targetClass);
501         // Enabled
502         assertThat(cursor.getInt(16) == 1).isEqualTo(enabled);
503         // Data ref key
504         assertThat(cursor.getString(17)).isEqualTo("app_install_location");
505         // User Id
506         assertThat(cursor.getInt(18)).isEqualTo(userId);
507         // Payload Type - default is 0
508         assertThat(cursor.getInt(19)).isEqualTo(0);
509         // Payload - should be updated to real payloads as controllers are added
510         assertThat(cursor.getBlob(20)).isNull();
511     }
512
513     // Tests for the flow: IndexOneResource -> IndexFromProvider -> IndexFromResource ->
514     //                     UpdateOneRowWithFilteredData -> UpdateOneRow
515
516     @Test
517     public void testResourceProvider_rowInserted() {
518         SearchIndexableResource resource = getFakeResource(R.xml.swipe_to_notification_settings);
519         resource.xmlResId = 0;
520         resource.className = "com.android.settings.display.ScreenZoomSettings";
521
522         mManager.indexOneSearchIndexableData(mDb, localeStr, resource, new HashMap<>());
523         Cursor cursor = mDb.rawQuery("SELECT * FROM prefs_index", null);
524         assertThat(cursor.getCount()).isEqualTo(1);
525     }
526
527     @Test
528     public void testResourceProvider_rowMatches() {
529         SearchIndexableResource resource = getFakeResource(R.xml.swipe_to_notification_settings);
530         resource.xmlResId = 0;
531         resource.className = "com.android.settings.display.ScreenZoomSettings";
532
533         mManager.indexOneSearchIndexableData(mDb, localeStr, resource, new HashMap<>());
534         Cursor cursor = mDb.rawQuery("SELECT * FROM prefs_index", null);
535         cursor.moveToPosition(0);
536
537         // Locale
538         assertThat(cursor.getString(0)).isEqualTo(localeStr);
539         // Data Rank
540         assertThat(cursor.getInt(1)).isEqualTo(rank);
541         // Data Title
542         assertThat(cursor.getString(2)).isEqualTo("Display size");
543         // Normalized Title
544         assertThat(cursor.getString(3)).isEqualTo("display size");
545         // Summary On
546         assertThat(cursor.getString(4)).isEmpty();
547         // Summary On Normalized
548         assertThat(cursor.getString(5)).isEmpty();
549         // Summary Off - only on for checkbox preferences
550         assertThat(cursor.getString(6)).isEmpty();
551         // Summary off normalized - only on for checkbox preferences
552         assertThat(cursor.getString(7)).isEmpty();
553         // Entries - only on for list preferences
554         assertThat(cursor.getString(8)).isNull();
555         // Keywords
556         assertThat(cursor.getString(9)).isEqualTo("display density screen zoom scale scaling");
557         // Screen Title
558         assertThat(cursor.getString(10)).isEqualTo("Display size");
559         // Class Name
560         assertThat(cursor.getString(11))
561                 .isEqualTo("com.android.settings.display.ScreenZoomSettings");
562         // Icon
563         assertThat(cursor.getInt(12)).isEqualTo(iconResId);
564         // Intent Action
565         assertThat(cursor.getString(13)).isNull();
566         // Target Package
567         assertThat(cursor.getString(14)).isNull();
568         // Target Class
569         assertThat(cursor.getString(15)).isNull();
570         // Enabled
571         assertThat(cursor.getInt(16) == 1).isEqualTo(enabled);
572         // Data ref key
573         assertThat(cursor.getString(17)).isNull();
574         // User Id
575         assertThat(cursor.getInt(18)).isEqualTo(userId);
576         // Payload Type - default is 0
577         assertThat(cursor.getInt(19)).isEqualTo(0);
578         // Payload - should be updated to real payloads as controllers are added
579         assertThat(cursor.getBlob(20)).isNull();
580     }
581
582     @Test
583     public void testResourceProvider_resourceRowInserted() {
584         SearchIndexableResource resource = getFakeResource(0);
585         resource.className = "com.android.settings.LegalSettings";
586
587         mManager.indexOneSearchIndexableData(mDb, localeStr, resource, new HashMap<>());
588         Cursor cursor = mDb.rawQuery("SELECT * FROM prefs_index", null);
589         assertThat(cursor.getCount()).isEqualTo(6);
590     }
591
592     @Test
593     public void testResourceProvider_resourceRowMatches() {
594         SearchIndexableResource resource = getFakeResource(0);
595         resource.className = "com.android.settings.display.ScreenZoomSettings";
596
597         mManager.indexOneSearchIndexableData(mDb, localeStr, resource, new HashMap<>());
598         Cursor cursor = mDb.rawQuery("SELECT * FROM prefs_index ORDER BY data_title", null);
599         cursor.moveToPosition(0);
600
601         // Locale
602         assertThat(cursor.getString(0)).isEqualTo(localeStr);
603         // Data Rank
604         assertThat(cursor.getInt(1)).isEqualTo(rank);
605         // Data Title
606         assertThat(cursor.getString(2)).isEqualTo("Display size");
607         // Normalized Title
608         assertThat(cursor.getString(3)).isEqualTo("display size");
609         // Summary On
610         assertThat(cursor.getString(4)).isEmpty();
611         // Summary On Normalized
612         assertThat(cursor.getString(5)).isEmpty();
613         // Summary Off - only on for checkbox preferences
614         assertThat(cursor.getString(6)).isEmpty();
615         // Summary off normalized - only on for checkbox preferences
616         assertThat(cursor.getString(7)).isEmpty();
617         // Entries - only on for list preferences
618         assertThat(cursor.getString(8)).isNull();
619         // Keywords
620         assertThat(cursor.getString(9)).isEqualTo(
621                 "display density screen zoom scale scaling");
622         // Screen Title
623         assertThat(cursor.getString(10)).isEqualTo("Display size");
624         // Class Name
625         assertThat(cursor.getString(11))
626                 .isEqualTo("com.android.settings.display.ScreenZoomSettings");
627         // Icon
628         assertThat(cursor.getInt(12)).isEqualTo(iconResId);
629         // Intent Action
630         assertThat(cursor.getString(13)).isNull();
631         // Target Package
632         assertThat(cursor.getString(14)).isNull();
633         // Target Class
634         assertThat(cursor.getString(15)).isNull();
635         // Enabled
636         assertThat(cursor.getInt(16) == 1).isEqualTo(enabled);
637         // Data ref key
638         assertThat(cursor.getString(17)).isNull();
639         // User Id
640         assertThat(cursor.getInt(18)).isEqualTo(userId);
641         // Payload Type - default is 0
642         assertThat(cursor.getInt(19)).isEqualTo(0);
643         // Payload - should be updated to real payloads as controllers are added
644         assertThat(cursor.getBlob(20)).isNull();
645     }
646
647     @Test
648     public void testResourceProvider_disabledResource_rowsInserted() {
649         SearchIndexableResource resource = getFakeResource(0);
650         resource.className = "com.android.settings.LegalSettings";
651
652         mManager.indexOneSearchIndexableData(mDb, localeStr, resource,
653                 new HashMap<String, Set<String>>());
654
655         Cursor cursor = mDb.rawQuery("SELECT * FROM prefs_index WHERE enabled = 1", null);
656         assertThat(cursor.getCount()).isEqualTo(2);
657         cursor = mDb.rawQuery("SELECT * FROM prefs_index WHERE enabled = 0", null);
658         assertThat(cursor.getCount()).isEqualTo(4);
659     }
660
661     @Test
662     public void testResource_withTitleAndSettingName_titleNotInserted() {
663         SearchIndexableResource resource = getFakeResource(R.xml.swipe_to_notification_settings);
664         mManager.indexFromResource(mDb, localeStr, resource, new ArrayList<String>());
665
666         Cursor cursor = mDb.rawQuery("SELECT * FROM prefs_index WHERE" +
667                 " enabled = 1", null);
668         assertThat(cursor.getCount()).isEqualTo(1);
669     }
670
671     // Test new public indexing flow
672
673     @Test
674     @Config(shadows= {
675             ShadowDatabaseIndexingUtils.class,
676     })
677     public void testPerformIndexing_fullIndex_getsDataFromProviders() {
678         DummyProvider provider = new DummyProvider();
679         provider.onCreate();
680         ShadowContentResolver.registerProvider(
681                 AUTHORITY_ONE, provider
682         );
683
684         // Test that Indexables are added for Full indexing
685         when(mPackageManager.queryIntentContentProviders(any(Intent.class), anyInt()))
686                 .thenReturn(getDummyResolveInfo());
687
688         DatabaseIndexingManager manager =
689                 spy(new DatabaseIndexingManager(mContext, "com.android.settings"));
690         doReturn(false).when(manager).isLocaleIndexed();
691
692         manager.performIndexing();
693
694         verify(manager).updateDatabase(false, Locale.getDefault().toString());
695
696         Cursor cursor = mDb.rawQuery("SELECT * FROM prefs_index", null);
697         cursor.moveToPosition(0);
698
699         // Data Title
700         assertThat(cursor.getString(2)).isEqualTo(TITLE_ONE);
701     }
702
703     @Test
704     @Config(shadows= {
705             ShadowDatabaseIndexingUtils.class,
706     })
707     public void testPerformIndexing_incrementalIndex_noDataAdded() {
708         DummyProvider provider = new DummyProvider();
709         provider.onCreate();
710         ShadowContentResolver.registerProvider(
711                 AUTHORITY_ONE, provider
712         );
713
714         // Test that Indexables are added for Full indexing
715         when(mPackageManager.queryIntentContentProviders(any(Intent.class), anyInt()))
716                 .thenReturn(getDummyResolveInfo());
717
718         DatabaseIndexingManager manager =
719                 spy(new DatabaseIndexingManager(mContext, "com.android.settings"));
720         doReturn(true).when(manager).isLocaleIndexed();
721
722         manager.performIndexing();
723
724         final Cursor cursor = mDb.rawQuery("SELECT * FROM prefs_index", null);
725
726         assertThat(cursor.getCount()).isEqualTo(0);
727     }
728
729     @Test
730     public void testFullUpdatedDatabase_noData_addDataToDatabaseNotCalled() {
731         mManager.updateDatabase(false, localeStr);
732         mManager.mDataToProcess.dataToUpdate.clear();
733         verify(mManager, times(0)).addDataToDatabase(any(SQLiteDatabase.class), anyString(),
734                 anyList(), anyMap());
735     }
736
737     @Test
738     public void testFullUpdatedDatabase_updatedDataInDatabaseNotCalled() {
739         mManager.updateDatabase(false, localeStr);
740         verify(mManager, times(0)).updateDataInDatabase(any(SQLiteDatabase.class), anyMap());
741     }
742
743     @Test
744     public void testLocaleUpdated_afterIndexing_localeAdded() {
745         mManager.updateDatabase(false, localeStr);
746         assertThat(IndexDatabaseHelper.getInstance(mContext)
747                 .isLocaleAlreadyIndexed(mContext, localeStr)).isTrue();
748     }
749
750     @Test
751     public void testUpdateDatabase_newEligibleData_addedToDatabase() {
752         // Test that addDataToDatabase is called when dataToUpdate is non-empty
753         mManager.mDataToProcess.dataToUpdate.add(getFakeRaw());
754         mManager.updateDatabase(false, localeStr);
755
756         Cursor cursor = mDb.rawQuery("SELECT * FROM prefs_index", null);
757         cursor.moveToPosition(0);
758
759         // Locale
760         assertThat(cursor.getString(0)).isEqualTo(localeStr);
761         // Data Rank
762         assertThat(cursor.getInt(1)).isEqualTo(rank);
763         // Data Title
764         assertThat(cursor.getString(2)).isEqualTo(updatedTitle);
765         // Normalized Title
766         assertThat(cursor.getString(3)).isEqualTo(normalizedTitle);
767         // Summary On
768         assertThat(cursor.getString(4)).isEqualTo(updatedSummaryOn);
769         // Summary On Normalized
770         assertThat(cursor.getString(5)).isEqualTo(normalizedSummaryOn);
771         // Summary Off
772         assertThat(cursor.getString(6)).isEqualTo(updatedSummaryOff);
773         // Summary off normalized
774         assertThat(cursor.getString(7)).isEqualTo(normalizedSummaryOff);
775         // Entries
776         assertThat(cursor.getString(8)).isEqualTo(entries);
777         // Keywords
778         assertThat(cursor.getString(9)).isEqualTo(spaceDelimittedKeywords);
779         // Screen Title
780         assertThat(cursor.getString(10)).isEqualTo(screenTitle);
781         // Class Name
782         assertThat(cursor.getString(11)).isEqualTo(className);
783         // Icon
784         assertThat(cursor.getInt(12)).isEqualTo(iconResId);
785         // Intent Action
786         assertThat(cursor.getString(13)).isEqualTo(action);
787         // Target Package
788         assertThat(cursor.getString(14)).isEqualTo(targetPackage);
789         // Target Class
790         assertThat(cursor.getString(15)).isEqualTo(targetClass);
791         // Enabled
792         assertThat(cursor.getInt(16) == 1).isEqualTo(enabled);
793         // Data ref key
794         assertThat(cursor.getString(17)).isNotNull();
795         // User Id
796         assertThat(cursor.getInt(18)).isEqualTo(userId);
797         // Payload Type - default is 0
798         assertThat(cursor.getInt(19)).isEqualTo(0);
799         // Payload
800         assertThat(cursor.getBlob(20)).isNull();
801     }
802
803     @Test
804     public void testUpdateDataInDatabase_enabledResultsAreNonIndexable_becomeDisabled() {
805         // Both results are enabled, and then TITLE_ONE gets disabled.
806         final boolean enabled = true;
807         insertSpecialCase(TITLE_ONE, enabled, KEY_ONE);
808         insertSpecialCase(TITLE_TWO, enabled, KEY_TWO);
809         Map<String, Set<String>> niks = new ArrayMap<>();
810         Set<String> keys = new HashSet<>();
811         keys.add(KEY_ONE);
812         niks.put(targetPackage, keys);
813
814         mManager.updateDataInDatabase(mDb, niks);
815
816         Cursor cursor = mDb.rawQuery("SELECT * FROM prefs_index WHERE enabled = 0", null);
817         cursor.moveToPosition(0);
818
819         assertThat(cursor.getString(2)).isEqualTo(TITLE_ONE);
820     }
821
822     @Test
823     public void testUpdateDataInDatabase_DisabledResultsAreIndexable_BecomeEnabled() {
824         // Both results are initially disabled, and then TITLE_TWO gets enabled.
825         final boolean enabled = false;
826         insertSpecialCase(TITLE_ONE, enabled, KEY_ONE);
827         insertSpecialCase(TITLE_TWO, enabled, KEY_TWO);
828         Map<String, Set<String>> niks = new ArrayMap<>();
829         Set<String> keys = new HashSet<>();
830         keys.add(KEY_ONE);
831         niks.put(targetPackage, keys);
832
833         mManager.updateDataInDatabase(mDb, niks);
834
835         Cursor cursor = mDb.rawQuery("SELECT * FROM prefs_index WHERE enabled = 1", null);
836         cursor.moveToPosition(0);
837
838         assertThat(cursor.getString(2)).isEqualTo(TITLE_TWO);
839     }
840
841     // Util functions
842
843     private SearchIndexableRaw getFakeRaw() {
844         return getFakeRaw(localeStr);
845     }
846
847     private SearchIndexableRaw getFakeRaw(String localeStr) {
848         SearchIndexableRaw data = new SearchIndexableRaw(mContext);
849         data.locale = new Locale(localeStr);
850         data.rank = rank;
851         data.title = title;
852         data.summaryOn = summaryOn;
853         data.summaryOff = summaryOff;
854         data.entries = entries;
855         data.keywords = keywords;
856         data.screenTitle = screenTitle;
857         data.className = className;
858         data.packageName = packageName;
859         data.iconResId = iconResId;
860         data.intentAction = action;
861         data.intentTargetPackage = targetPackage;
862         data.intentTargetClass = targetClass;
863         data.key = key;
864         data.userId = userId;
865         data.enabled = enabled;
866         return data;
867     }
868
869     private SearchIndexableResource getFakeResource(int xml) {
870         SearchIndexableResource sir = new SearchIndexableResource(mContext);
871         sir.rank = rank;
872         sir.xmlResId = xml;
873         sir.className = className;
874         sir.packageName = packageName;
875         sir.iconResId = iconResId;
876         sir.intentAction = action;
877         sir.intentTargetPackage = targetPackage;
878         sir.intentTargetClass = targetClass;
879         sir.enabled = enabled;
880         return sir;
881     }
882
883     private Map<String, Set<String>> getNonIndexableKeys(String[] keys) {
884         Map<String, Set<String>> niks = new HashMap<>();
885         Set<String> keysList = new HashSet<>();
886         keysList.addAll(Arrays.asList(keys));
887         niks.put(packageName, keysList);
888         return niks;
889     }
890
891     private List<ResolveInfo> getDummyResolveInfo() {
892         List<ResolveInfo> infoList = new ArrayList<>();
893         ResolveInfo info = new ResolveInfo();
894         info.providerInfo = new ProviderInfo();
895         info.providerInfo.exported = true;
896         info.providerInfo.authority = AUTHORITY_ONE;
897         info.providerInfo.packageName = PACKAGE_ONE;
898         infoList.add(info);
899
900         return infoList;
901     }
902
903     // TODO move this method and its counterpart in CursorToSearchResultConverterTest into
904     // a util class with public fields to assert values.
905     private Cursor getDummyCursor() {
906         MatrixCursor cursor = new MatrixCursor(SearchIndexablesContract.INDEXABLES_RAW_COLUMNS);
907         final String BLANK = "";
908
909         ArrayList<String> item =
910                 new ArrayList<>(SearchIndexablesContract.INDEXABLES_RAW_COLUMNS.length);
911         item.add("42"); // Rank
912         item.add(TITLE_ONE); // Title
913         item.add(BLANK); // Summary on
914         item.add(BLANK); // summary off
915         item.add(BLANK); // entries
916         item.add(BLANK); // keywords
917         item.add(BLANK); // screen title
918         item.add(BLANK); // classname
919         item.add("123"); // Icon
920         item.add(BLANK); // Intent action
921         item.add(BLANK); // target package
922         item.add(BLANK); // target class
923         item.add(KEY_ONE); // Key
924         item.add("-1"); // userId
925         cursor.addRow(item);
926
927         return cursor;
928     }
929
930     private void insertSpecialCase(String specialCase, boolean enabled, String key) {
931
932         ContentValues values = new ContentValues();
933         values.put(IndexDatabaseHelper.IndexColumns.DOCID, specialCase.hashCode());
934         values.put(IndexDatabaseHelper.IndexColumns.LOCALE, localeStr);
935         values.put(IndexDatabaseHelper.IndexColumns.DATA_RANK, 1);
936         values.put(IndexDatabaseHelper.IndexColumns.DATA_TITLE, specialCase);
937         values.put(IndexDatabaseHelper.IndexColumns.DATA_TITLE_NORMALIZED, "");
938         values.put(IndexDatabaseHelper.IndexColumns.DATA_SUMMARY_ON, "");
939         values.put(IndexDatabaseHelper.IndexColumns.DATA_SUMMARY_ON_NORMALIZED, "");
940         values.put(IndexDatabaseHelper.IndexColumns.DATA_SUMMARY_OFF, "");
941         values.put(IndexDatabaseHelper.IndexColumns.DATA_SUMMARY_OFF_NORMALIZED, "");
942         values.put(IndexDatabaseHelper.IndexColumns.DATA_ENTRIES, "");
943         values.put(IndexDatabaseHelper.IndexColumns.DATA_KEYWORDS, "");
944         values.put(IndexDatabaseHelper.IndexColumns.CLASS_NAME, "");
945         values.put(IndexDatabaseHelper.IndexColumns.SCREEN_TITLE, "Moves");
946         values.put(IndexDatabaseHelper.IndexColumns.INTENT_ACTION, "");
947         values.put(IndexDatabaseHelper.IndexColumns.INTENT_TARGET_PACKAGE, targetPackage);
948         values.put(IndexDatabaseHelper.IndexColumns.INTENT_TARGET_CLASS, "");
949         values.put(IndexDatabaseHelper.IndexColumns.ICON, "");
950         values.put(IndexDatabaseHelper.IndexColumns.ENABLED, enabled);
951         values.put(IndexDatabaseHelper.IndexColumns.DATA_KEY_REF, key);
952         values.put(IndexDatabaseHelper.IndexColumns.USER_ID, 0);
953         values.put(IndexDatabaseHelper.IndexColumns.PAYLOAD_TYPE, 0);
954         values.put(IndexDatabaseHelper.IndexColumns.PAYLOAD, (String) null);
955
956         mDb.replaceOrThrow(IndexDatabaseHelper.Tables.TABLE_PREFS_INDEX, null, values);
957     }
958
959     private class DummyProvider extends ContentProvider {
960
961         @Override
962         public boolean onCreate() {
963             return false;
964         }
965
966         @Override
967         public Cursor query(@NonNull Uri uri, @Nullable String[] projection,
968                 @Nullable String selection, @Nullable String[] selectionArgs,
969                 @Nullable String sortOrder) {
970             if (uri.toString().contains("xml")) {
971                 return null;
972             }
973             return getDummyCursor();
974         }
975
976         @Override
977         public String getType(@NonNull Uri uri) {
978             return null;
979         }
980
981         @Override
982         public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {
983             return null;
984         }
985
986         @Override
987         public int delete(@NonNull Uri uri, @Nullable String selection,
988                 @Nullable String[] selectionArgs) {
989             return 0;
990         }
991
992         @Override
993         public int update(@NonNull Uri uri, @Nullable ContentValues values,
994                 @Nullable String selection, @Nullable String[] selectionArgs) {
995             return 0;
996         }
997     }
998 }