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