2 * Copyright (C) 2017 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 package com.android.settings.search2;
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;
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;
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;
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";
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;
105 private final String AUTHORITY_ONE = "authority";
106 private final String PACKAGE_ONE = "com.android.settings";
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";
113 private Context mContext;
115 private DatabaseIndexingManager mManager;
116 private SQLiteDatabase mDb;
119 private PackageManager mPackageManager;
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();
128 doReturn(mPackageManager).when(mContext).getPackageManager();
132 public void cleanUp() {
133 DatabaseTestUtils.clearDb();
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[]{
145 "data_title_normalized",
147 "data_summary_on_normalized",
149 "data_summary_off_normalized",
155 "intent_target_package",
156 "intent_target_class",
159 "data_key_reference",
164 // Prevent database schema regressions
165 assertThat(columnNames).containsAllIn(expColumnNames);
168 // Tests for the flow: IndexOneRaw -> UpdateOneRowWithFilteredData -> UpdateOneRow
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);
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);
186 assertThat(cursor.getString(0)).isEqualTo(localeStr);
188 assertThat(cursor.getInt(1)).isEqualTo(raw.rank);
190 assertThat(cursor.getString(2)).isEqualTo(updatedTitle);
192 assertThat(cursor.getString(3)).isEqualTo(normalizedTitle);
194 assertThat(cursor.getString(4)).isEqualTo(updatedSummaryOn);
195 // Summary On Normalized
196 assertThat(cursor.getString(5)).isEqualTo(normalizedSummaryOn);
198 assertThat(cursor.getString(6)).isEqualTo(updatedSummaryOff);
199 // Summary off normalized
200 assertThat(cursor.getString(7)).isEqualTo(normalizedSummaryOff);
202 assertThat(cursor.getString(8)).isEqualTo(raw.entries);
204 assertThat(cursor.getString(9)).isEqualTo(spaceDelimittedKeywords);
206 assertThat(cursor.getString(10)).isEqualTo(raw.screenTitle);
208 assertThat(cursor.getString(11)).isEqualTo(raw.className);
210 assertThat(cursor.getInt(12)).isEqualTo(raw.iconResId);
212 assertThat(cursor.getString(13)).isEqualTo(raw.intentAction);
214 assertThat(cursor.getString(14)).isEqualTo(raw.intentTargetPackage);
216 assertThat(cursor.getString(15)).isEqualTo(raw.intentTargetClass);
218 assertThat(cursor.getInt(16) == 1).isEqualTo(raw.enabled);
220 assertThat(cursor.getString(17)).isNotNull();
222 assertThat(cursor.getInt(18)).isEqualTo(raw.userId);
223 // Payload Type - default is 0
224 assertThat(cursor.getInt(19)).isEqualTo(0);
226 assertThat(cursor.getBlob(20)).isNull();
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);
237 // Tests for the flow: IndexOneResource -> IndexFromResource ->
238 // UpdateOneRowWithFilteredData -> UpdateOneRow
241 public void testNullResource_NothingInserted() {
242 mManager.indexOneSearchIndexableData(mDb, localeStr, null /* searchIndexableResource */,
244 Cursor cursor = mDb.rawQuery("SELECT * FROM prefs_index", null);
245 assertThat(cursor.getCount()).isEqualTo(0);
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);
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);
263 mManager.indexOneSearchIndexableData(mDb, localeStr, resource, niks);
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);
272 public void testAddResourceHeader_rowsMatch() {
273 SearchIndexableResource resource = getFakeResource(R.xml.application_settings);
274 mManager.indexOneSearchIndexableData(mDb, localeStr, resource, new HashMap<>());
276 Cursor cursor = mDb.rawQuery("SELECT * FROM prefs_index ORDER BY data_title", null);
277 cursor.moveToPosition(1);
280 assertThat(cursor.getString(0)).isEqualTo(localeStr);
282 assertThat(cursor.getInt(1)).isEqualTo(rank);
284 assertThat(cursor.getString(2)).isEqualTo("App info");
286 assertThat(cursor.getString(3)).isEqualTo("app info");
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();
298 assertThat(cursor.getString(9)).isEmpty();
300 assertThat(cursor.getString(10)).isEqualTo("App info");
302 assertThat(cursor.getString(11)).isEqualTo(className);
304 assertThat(cursor.getInt(12)).isEqualTo(iconResId);
306 assertThat(cursor.getString(13)).isEqualTo(action);
308 assertThat(cursor.getString(14)).isEqualTo(targetPackage);
310 assertThat(cursor.getString(15)).isEqualTo(targetClass);
312 assertThat(cursor.getInt(16) == 1).isEqualTo(enabled);
314 assertThat(cursor.getString(17)).isEqualTo("applications_settings");
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();
324 public void testAddResource_withChildFragment_shouldUpdateSiteMapDb() {
325 // FIXME: This test was failing. (count = 6 at the end)
327 // SearchIndexableResource resource = getFakeResource(R.xml.network_and_internet);
328 // mManager.indexOneSearchIndexableData(mDb, localeStr, resource,
330 // Cursor query = mDb.query(IndexDatabaseHelper.Tables.TABLE_SITE_MAP, SITE_MAP_COLUMNS,
331 // null, null, null, null, null);
332 // query.moveToPosition(-1);
334 // while (query.moveToNext()) {
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)))
342 // assertThat(query.getString(query.getColumnIndex(SiteMapColumns.CHILD_TITLE)))
345 // assertThat(count).isEqualTo(5);
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();
361 assertThat(cursor.getString(0)).isEqualTo(localeStr);
363 assertThat(cursor.getInt(1)).isEqualTo(rank);
365 assertThat(cursor.getString(2)).isEqualTo(prefTitle);
367 assertThat(cursor.getString(3)).isEqualTo(prefTitle.toLowerCase());
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();
379 assertThat(cursor.getString(9)).isEmpty();
381 assertThat(cursor.getString(10)).isEqualTo(
382 mContext.getString(R.string.fingerprint_swipe_for_notifications_title));
384 assertThat(cursor.getString(11)).isEqualTo(className);
386 assertThat(cursor.getInt(12)).isEqualTo(iconResId);
388 assertThat(cursor.getString(13)).isEqualTo(action);
390 assertThat(cursor.getString(14)).isEqualTo(targetPackage);
392 assertThat(cursor.getString(15)).isEqualTo(targetClass);
394 assertThat(cursor.getInt(16) == 1).isEqualTo(enabled);
396 assertThat(cursor.getString(17)).isEqualTo("gesture_swipe_down_fingerprint");
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();
406 public void testAddResource_checkboxPreference_rowsMatch() {
407 SearchIndexableResource resource = getFakeResource(R.xml.application_settings);
408 mManager.indexOneSearchIndexableData(mDb, localeStr, resource, new HashMap<>());
410 /* Should return 6 results, with the following titles:
411 * Advanced Settings, Apps, Manage Apps, Preferred install location, Running Services
413 Cursor cursor = mDb.rawQuery("SELECT * FROM prefs_index ORDER BY data_title", null);
414 cursor.moveToPosition(0);
416 assertThat(cursor.getString(0)).isEqualTo(localeStr);
418 assertThat(cursor.getInt(1)).isEqualTo(rank);
420 assertThat(cursor.getString(2)).isEqualTo("Advanced settings");
422 assertThat(cursor.getString(3)).isEqualTo("advanced settings");
424 assertThat(cursor.getString(4)).isEqualTo("Enable more settings options");
425 // Summary On Normalized
426 assertThat(cursor.getString(5)).isEqualTo("enable more settings options");
428 assertThat(cursor.getString(6)).isEqualTo("Enable more settings options");
430 assertThat(cursor.getString(7)).isEqualTo("enable more settings options");
431 // Entries - only on for list preferences
432 assertThat(cursor.getString(8)).isNull();
434 assertThat(cursor.getString(9)).isEmpty();
436 assertThat(cursor.getString(10)).isEqualTo("App info");
438 assertThat(cursor.getString(11)).isEqualTo(className);
440 assertThat(cursor.getInt(12)).isEqualTo(iconResId);
442 assertThat(cursor.getString(13)).isEqualTo(action);
444 assertThat(cursor.getString(14)).isEqualTo(targetPackage);
446 assertThat(cursor.getString(15)).isEqualTo(targetClass);
448 assertThat(cursor.getInt(16) == 1).isEqualTo(enabled);
450 assertThat(cursor.getString(17)).isEqualTo("toggle_advanced_settings");
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();
460 public void testAddResource_listPreference_rowsMatch() {
461 SearchIndexableResource resource = getFakeResource(R.xml.application_settings);
462 mManager.indexOneSearchIndexableData(mDb, localeStr, resource, new HashMap<>());
464 Cursor cursor = mDb.rawQuery("SELECT * FROM prefs_index ORDER BY data_title", null);
465 cursor.moveToPosition(3);
467 assertThat(cursor.getString(0)).isEqualTo(localeStr);
469 assertThat(cursor.getInt(1)).isEqualTo(rank);
471 assertThat(cursor.getString(2)).isEqualTo("Preferred install location");
473 assertThat(cursor.getString(3)).isEqualTo("preferred install location");
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|");
488 assertThat(cursor.getString(9)).isEmpty();
490 assertThat(cursor.getString(10)).isEqualTo("App info");
492 assertThat(cursor.getString(11)).isEqualTo(className);
494 assertThat(cursor.getInt(12)).isEqualTo(iconResId);
496 assertThat(cursor.getString(13)).isEqualTo(action);
498 assertThat(cursor.getString(14)).isEqualTo(targetPackage);
500 assertThat(cursor.getString(15)).isEqualTo(targetClass);
502 assertThat(cursor.getInt(16) == 1).isEqualTo(enabled);
504 assertThat(cursor.getString(17)).isEqualTo("app_install_location");
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();
513 // Tests for the flow: IndexOneResource -> IndexFromProvider -> IndexFromResource ->
514 // UpdateOneRowWithFilteredData -> UpdateOneRow
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";
522 mManager.indexOneSearchIndexableData(mDb, localeStr, resource, new HashMap<>());
523 Cursor cursor = mDb.rawQuery("SELECT * FROM prefs_index", null);
524 assertThat(cursor.getCount()).isEqualTo(1);
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";
533 mManager.indexOneSearchIndexableData(mDb, localeStr, resource, new HashMap<>());
534 Cursor cursor = mDb.rawQuery("SELECT * FROM prefs_index", null);
535 cursor.moveToPosition(0);
538 assertThat(cursor.getString(0)).isEqualTo(localeStr);
540 assertThat(cursor.getInt(1)).isEqualTo(rank);
542 assertThat(cursor.getString(2)).isEqualTo("Display size");
544 assertThat(cursor.getString(3)).isEqualTo("display size");
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();
556 assertThat(cursor.getString(9)).isEqualTo("display density screen zoom scale scaling");
558 assertThat(cursor.getString(10)).isEqualTo("Display size");
560 assertThat(cursor.getString(11))
561 .isEqualTo("com.android.settings.display.ScreenZoomSettings");
563 assertThat(cursor.getInt(12)).isEqualTo(iconResId);
565 assertThat(cursor.getString(13)).isNull();
567 assertThat(cursor.getString(14)).isNull();
569 assertThat(cursor.getString(15)).isNull();
571 assertThat(cursor.getInt(16) == 1).isEqualTo(enabled);
573 assertThat(cursor.getString(17)).isNull();
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();
583 public void testResourceProvider_resourceRowInserted() {
584 SearchIndexableResource resource = getFakeResource(0);
585 resource.className = "com.android.settings.LegalSettings";
587 mManager.indexOneSearchIndexableData(mDb, localeStr, resource, new HashMap<>());
588 Cursor cursor = mDb.rawQuery("SELECT * FROM prefs_index", null);
589 assertThat(cursor.getCount()).isEqualTo(6);
593 public void testResourceProvider_resourceRowMatches() {
594 SearchIndexableResource resource = getFakeResource(0);
595 resource.className = "com.android.settings.display.ScreenZoomSettings";
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);
602 assertThat(cursor.getString(0)).isEqualTo(localeStr);
604 assertThat(cursor.getInt(1)).isEqualTo(rank);
606 assertThat(cursor.getString(2)).isEqualTo("Display size");
608 assertThat(cursor.getString(3)).isEqualTo("display size");
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();
620 assertThat(cursor.getString(9)).isEqualTo(
621 "display density screen zoom scale scaling");
623 assertThat(cursor.getString(10)).isEqualTo("Display size");
625 assertThat(cursor.getString(11))
626 .isEqualTo("com.android.settings.display.ScreenZoomSettings");
628 assertThat(cursor.getInt(12)).isEqualTo(iconResId);
630 assertThat(cursor.getString(13)).isNull();
632 assertThat(cursor.getString(14)).isNull();
634 assertThat(cursor.getString(15)).isNull();
636 assertThat(cursor.getInt(16) == 1).isEqualTo(enabled);
638 assertThat(cursor.getString(17)).isNull();
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();
648 public void testResourceProvider_disabledResource_rowsInserted() {
649 SearchIndexableResource resource = getFakeResource(0);
650 resource.className = "com.android.settings.LegalSettings";
652 mManager.indexOneSearchIndexableData(mDb, localeStr, resource,
653 new HashMap<String, Set<String>>());
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);
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>());
666 Cursor cursor = mDb.rawQuery("SELECT * FROM prefs_index WHERE" +
667 " enabled = 1", null);
668 assertThat(cursor.getCount()).isEqualTo(1);
671 // Test new public indexing flow
675 ShadowDatabaseIndexingUtils.class,
677 public void testPerformIndexing_fullIndex_getsDataFromProviders() {
678 DummyProvider provider = new DummyProvider();
680 ShadowContentResolver.registerProvider(
681 AUTHORITY_ONE, provider
684 // Test that Indexables are added for Full indexing
685 when(mPackageManager.queryIntentContentProviders(any(Intent.class), anyInt()))
686 .thenReturn(getDummyResolveInfo());
688 DatabaseIndexingManager manager =
689 spy(new DatabaseIndexingManager(mContext, "com.android.settings"));
690 doReturn(false).when(manager).isLocaleIndexed();
692 manager.performIndexing();
694 verify(manager).updateDatabase(false, Locale.getDefault().toString());
696 Cursor cursor = mDb.rawQuery("SELECT * FROM prefs_index", null);
697 cursor.moveToPosition(0);
700 assertThat(cursor.getString(2)).isEqualTo(TITLE_ONE);
705 ShadowDatabaseIndexingUtils.class,
707 public void testPerformIndexing_incrementalIndex_noDataAdded() {
708 DummyProvider provider = new DummyProvider();
710 ShadowContentResolver.registerProvider(
711 AUTHORITY_ONE, provider
714 // Test that Indexables are added for Full indexing
715 when(mPackageManager.queryIntentContentProviders(any(Intent.class), anyInt()))
716 .thenReturn(getDummyResolveInfo());
718 DatabaseIndexingManager manager =
719 spy(new DatabaseIndexingManager(mContext, "com.android.settings"));
720 doReturn(true).when(manager).isLocaleIndexed();
722 manager.performIndexing();
724 final Cursor cursor = mDb.rawQuery("SELECT * FROM prefs_index", null);
726 assertThat(cursor.getCount()).isEqualTo(0);
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());
738 public void testFullUpdatedDatabase_updatedDataInDatabaseNotCalled() {
739 mManager.updateDatabase(false, localeStr);
740 verify(mManager, times(0)).updateDataInDatabase(any(SQLiteDatabase.class), anyMap());
744 public void testLocaleUpdated_afterIndexing_localeAdded() {
745 mManager.updateDatabase(false, localeStr);
746 assertThat(IndexDatabaseHelper.getInstance(mContext)
747 .isLocaleAlreadyIndexed(mContext, localeStr)).isTrue();
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);
756 Cursor cursor = mDb.rawQuery("SELECT * FROM prefs_index", null);
757 cursor.moveToPosition(0);
760 assertThat(cursor.getString(0)).isEqualTo(localeStr);
762 assertThat(cursor.getInt(1)).isEqualTo(rank);
764 assertThat(cursor.getString(2)).isEqualTo(updatedTitle);
766 assertThat(cursor.getString(3)).isEqualTo(normalizedTitle);
768 assertThat(cursor.getString(4)).isEqualTo(updatedSummaryOn);
769 // Summary On Normalized
770 assertThat(cursor.getString(5)).isEqualTo(normalizedSummaryOn);
772 assertThat(cursor.getString(6)).isEqualTo(updatedSummaryOff);
773 // Summary off normalized
774 assertThat(cursor.getString(7)).isEqualTo(normalizedSummaryOff);
776 assertThat(cursor.getString(8)).isEqualTo(entries);
778 assertThat(cursor.getString(9)).isEqualTo(spaceDelimittedKeywords);
780 assertThat(cursor.getString(10)).isEqualTo(screenTitle);
782 assertThat(cursor.getString(11)).isEqualTo(className);
784 assertThat(cursor.getInt(12)).isEqualTo(iconResId);
786 assertThat(cursor.getString(13)).isEqualTo(action);
788 assertThat(cursor.getString(14)).isEqualTo(targetPackage);
790 assertThat(cursor.getString(15)).isEqualTo(targetClass);
792 assertThat(cursor.getInt(16) == 1).isEqualTo(enabled);
794 assertThat(cursor.getString(17)).isNotNull();
796 assertThat(cursor.getInt(18)).isEqualTo(userId);
797 // Payload Type - default is 0
798 assertThat(cursor.getInt(19)).isEqualTo(0);
800 assertThat(cursor.getBlob(20)).isNull();
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<>();
812 niks.put(targetPackage, keys);
814 mManager.updateDataInDatabase(mDb, niks);
816 Cursor cursor = mDb.rawQuery("SELECT * FROM prefs_index WHERE enabled = 0", null);
817 cursor.moveToPosition(0);
819 assertThat(cursor.getString(2)).isEqualTo(TITLE_ONE);
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<>();
831 niks.put(targetPackage, keys);
833 mManager.updateDataInDatabase(mDb, niks);
835 Cursor cursor = mDb.rawQuery("SELECT * FROM prefs_index WHERE enabled = 1", null);
836 cursor.moveToPosition(0);
838 assertThat(cursor.getString(2)).isEqualTo(TITLE_TWO);
843 private SearchIndexableRaw getFakeRaw() {
844 return getFakeRaw(localeStr);
847 private SearchIndexableRaw getFakeRaw(String localeStr) {
848 SearchIndexableRaw data = new SearchIndexableRaw(mContext);
849 data.locale = new Locale(localeStr);
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;
864 data.userId = userId;
865 data.enabled = enabled;
869 private SearchIndexableResource getFakeResource(int xml) {
870 SearchIndexableResource sir = new SearchIndexableResource(mContext);
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;
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);
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;
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 = "";
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
930 private void insertSpecialCase(String specialCase, boolean enabled, String key) {
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);
956 mDb.replaceOrThrow(IndexDatabaseHelper.Tables.TABLE_PREFS_INDEX, null, values);
959 private class DummyProvider extends ContentProvider {
962 public boolean onCreate() {
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")) {
973 return getDummyCursor();
977 public String getType(@NonNull Uri uri) {
982 public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {
987 public int delete(@NonNull Uri uri, @Nullable String selection,
988 @Nullable String[] selectionArgs) {
993 public int update(@NonNull Uri uri, @Nullable ContentValues values,
994 @Nullable String selection, @Nullable String[] selectionArgs) {