Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6fcc3897 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Reindex db when package w/ searchIndexProvider changes" into oc-dr1-dev

parents 4d7111b0 b4c40e5d
Loading
Loading
Loading
Loading
+12 −22
Original line number Diff line number Diff line
@@ -166,18 +166,22 @@ public class DatabaseIndexingManager {
     */
    public void performIndexing() {
        final Intent intent = new Intent(SearchIndexablesContract.PROVIDER_INTERFACE);
        final List<ResolveInfo> list =
        final List<ResolveInfo> providers =
                mContext.getPackageManager().queryIntentContentProviders(intent, 0);

        String localeStr = Locale.getDefault().toString();
        String fingerprint = Build.FINGERPRINT;
        final boolean isFullIndex = isFullIndex(localeStr, fingerprint);
        final String localeStr = Locale.getDefault().toString();
        final String fingerprint = Build.FINGERPRINT;
        final String providerVersionedNames =
                IndexDatabaseHelper.buildProviderVersionedNames(providers);

        final boolean isFullIndex = IndexDatabaseHelper.isFullIndex(mContext, localeStr,
                fingerprint, providerVersionedNames);

        if (isFullIndex) {
            rebuildDatabase();
        }

        for (final ResolveInfo info : list) {
        for (final ResolveInfo info : providers) {
            if (!DatabaseIndexingUtils.isWellKnownProvider(info, mContext)) {
                continue;
            }
@@ -192,24 +196,10 @@ public class DatabaseIndexingManager {

        updateDatabase(isFullIndex, localeStr);

        //TODO(63922686): Setting indexed should be a single method, not 3 separate setters.
        IndexDatabaseHelper.setLocaleIndexed(mContext, localeStr);
        IndexDatabaseHelper.setBuildIndexed(mContext, fingerprint);
    }

    /**
     * Perform a full index on an OTA or when the locale has changed
     *
     * @param locale is the default for the device
     * @param fingerprint id for the current build.
     * @return true when the locale or build has changed since last index.
     */
    @VisibleForTesting
    boolean isFullIndex(String locale, String fingerprint) {
        final boolean isLocaleIndexed = IndexDatabaseHelper.getInstance(mContext)
                .isLocaleAlreadyIndexed(mContext, locale);
        final boolean isBuildIndexed = IndexDatabaseHelper.getInstance(mContext)
                .isBuildIndexed(mContext, fingerprint);
        return !isLocaleIndexed || !isBuildIndexed;
        IndexDatabaseHelper.setProvidersIndexed(mContext, providerVersionedNames);
    }

    /**
+15 −15
Original line number Diff line number Diff line
@@ -174,7 +174,7 @@ public class DatabaseIndexingUtils {
     * - have read/write {@link Manifest.permission#READ_SEARCH_INDEXABLES}
     * - be from a privileged package
     */
    public static boolean isWellKnownProvider(ResolveInfo info, Context context) {
    static boolean isWellKnownProvider(ResolveInfo info, Context context) {
        final String authority = info.providerInfo.authority;
        final String packageName = info.providerInfo.applicationInfo.packageName;

@@ -197,29 +197,29 @@ public class DatabaseIndexingUtils {
        return isPrivilegedPackage(packageName, context);
    }

    public static boolean isPrivilegedPackage(String packageName, Context context) {
        final PackageManager pm = context.getPackageManager();
        try {
            PackageInfo packInfo = pm.getPackageInfo(packageName, 0);
            return ((packInfo.applicationInfo.privateFlags
                    & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0);
        } catch (PackageManager.NameNotFoundException e) {
            return false;
        }
    }

    public static String normalizeHyphen(String input) {
    static String normalizeHyphen(String input) {
        return (input != null) ? input.replaceAll(NON_BREAKING_HYPHEN, HYPHEN) : EMPTY;
    }

    public static String normalizeString(String input) {
    static String normalizeString(String input) {
        final String nohyphen = (input != null) ? input.replaceAll(HYPHEN, EMPTY) : EMPTY;
        final String normalized = Normalizer.normalize(nohyphen, Normalizer.Form.NFD);

        return REMOVE_DIACRITICALS_PATTERN.matcher(normalized).replaceAll("").toLowerCase();
    }

    public static String normalizeKeywords(String input) {
    static String normalizeKeywords(String input) {
        return (input != null) ? input.replaceAll(LIST_DELIMITERS, SPACE) : EMPTY;
    }

    private static boolean isPrivilegedPackage(String packageName, Context context) {
        final PackageManager pm = context.getPackageManager();
        try {
            PackageInfo packInfo = pm.getPackageInfo(packageName, 0);
            return ((packInfo.applicationInfo.privateFlags
                    & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0);
        } catch (PackageManager.NameNotFoundException e) {
            return false;
        }
    }
}
+62 −9
Original line number Diff line number Diff line
@@ -17,12 +17,17 @@
package com.android.settings.search;

import android.content.Context;
import android.content.pm.ResolveInfo;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.os.Build;
import android.support.annotation.VisibleForTesting;
import android.text.TextUtils;
import android.util.Log;

import java.util.List;

public class IndexDatabaseHelper extends SQLiteOpenHelper {

    private static final String TAG = "IndexDatabaseHelper";
@@ -32,6 +37,8 @@ public class IndexDatabaseHelper extends SQLiteOpenHelper {

    private static final String INDEX = "index";

    private static final String PREF_KEY_INDEXED_PROVIDERS = "indexed_providers";

    public interface Tables {
        String TABLE_PREFS_INDEX = "prefs_index";
        String TABLE_SITE_MAP = "site_map";
@@ -245,23 +252,69 @@ public class IndexDatabaseHelper extends SQLiteOpenHelper {
        return version;
    }

    public static void clearCachedIndexed(Context context) {
        context.getSharedPreferences(INDEX, 0).edit().clear().commit();
    /**
     * Perform a full index on an OTA or when the locale has changed
     *
     * @param locale      is the default for the device
     * @param fingerprint id for the current build.
     * @return true when the locale or build has changed since last index.
     */
    @VisibleForTesting
    static boolean isFullIndex(Context context, String locale, String fingerprint,
            String providerVersionedNames) {
        final boolean isLocaleIndexed = IndexDatabaseHelper.isLocaleAlreadyIndexed(context, locale);
        final boolean isBuildIndexed = IndexDatabaseHelper.isBuildIndexed(context, fingerprint);
        final boolean areProvidersIndexed = IndexDatabaseHelper
                .areProvidersIndexed(context, providerVersionedNames);

        return !(isLocaleIndexed && isBuildIndexed && areProvidersIndexed);
    }

    @VisibleForTesting
    static String buildProviderVersionedNames(List<ResolveInfo> providers) {
        StringBuilder sb = new StringBuilder();
        for (ResolveInfo info : providers) {
            sb.append(info.providerInfo.packageName)
                    .append(':')
                    .append(info.providerInfo.applicationInfo.versionCode)
                    .append(',');
        }
        return sb.toString();
    }

    static void clearCachedIndexed(Context context) {
        context.getSharedPreferences(INDEX, Context.MODE_PRIVATE).edit().clear().commit();
    }

    static void setLocaleIndexed(Context context, String locale) {
        context.getSharedPreferences(INDEX, Context.MODE_PRIVATE)
                .edit()
                .putBoolean(locale, true)
                .apply();
    }

    static void setProvidersIndexed(Context context, String providerVersionedNames) {
        context.getSharedPreferences(INDEX, Context.MODE_PRIVATE)
                .edit()
                .putString(PREF_KEY_INDEXED_PROVIDERS, providerVersionedNames)
                .apply();
    }

    public static void setLocaleIndexed(Context context, String locale) {
        context.getSharedPreferences(INDEX, 0).edit().putBoolean(locale, true).commit();
    static boolean isLocaleAlreadyIndexed(Context context, String locale) {
        return context.getSharedPreferences(INDEX, Context.MODE_PRIVATE).getBoolean(locale, false);
    }

    public static boolean isLocaleAlreadyIndexed(Context context, String locale) {
        return context.getSharedPreferences(INDEX, 0).getBoolean(locale, false);
    static boolean areProvidersIndexed(Context context, String providerVersionedNames) {
        final String indexedProviders = context.getSharedPreferences(INDEX, Context.MODE_PRIVATE)
                .getString(PREF_KEY_INDEXED_PROVIDERS, null);
        return TextUtils.equals(indexedProviders, providerVersionedNames);
    }

    public static boolean isBuildIndexed(Context context, String buildNo) {
        return context.getSharedPreferences(INDEX, 0).getBoolean(buildNo, false);
    static boolean isBuildIndexed(Context context, String buildNo) {
        return context.getSharedPreferences(INDEX, Context.MODE_PRIVATE).getBoolean(buildNo, false);
    }

    public static void setBuildIndexed(Context context, String buildNo) {
    static void setBuildIndexed(Context context, String buildNo) {
        context.getSharedPreferences(INDEX, 0).edit().putBoolean(buildNo, true).commit();
    }

+52 −25
Original line number Diff line number Diff line
@@ -17,12 +17,28 @@

package com.android.settings.search;

import static android.provider.SearchIndexablesContract.INDEXABLES_RAW_COLUMNS;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyList;
import static org.mockito.Matchers.anyMap;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.ProviderInfo;
import android.content.pm.ResolveInfo;
@@ -35,10 +51,10 @@ import android.provider.SearchIndexableResource;
import android.util.ArrayMap;

import com.android.settings.R;
import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settings.TestConfig;
import com.android.settings.testutils.DatabaseTestUtils;
import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settings.testutils.shadow.ShadowDatabaseIndexingUtils;
import com.android.settings.testutils.shadow.ShadowRunnableAsyncTask;

@@ -62,21 +78,6 @@ import java.util.Locale;
import java.util.Map;
import java.util.Set;

import static android.provider.SearchIndexablesContract.INDEXABLES_RAW_COLUMNS;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyList;
import static org.mockito.Matchers.anyMap;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

@RunWith(SettingsRobolectricTestRunner.class)
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION,
        shadows = {ShadowRunnableAsyncTask.class})
@@ -746,7 +747,7 @@ public class DatabaseIndexingManagerTest {
    // Test new public indexing flow

    @Test
    @Config(shadows = {ShadowDatabaseIndexingUtils.class,})
    @Config(shadows = {ShadowDatabaseIndexingUtils.class})
    public void testPerformIndexing_fullIndex_getsDataFromProviders() {
        DummyProvider provider = new DummyProvider();
        provider.onCreate();
@@ -758,7 +759,6 @@ public class DatabaseIndexingManagerTest {

        DatabaseIndexingManager manager =
                spy(new DatabaseIndexingManager(mContext, PACKAGE_ONE));
        doReturn(true).when(manager).isFullIndex(anyString(), anyString());

        manager.performIndexing();

@@ -769,17 +769,17 @@ public class DatabaseIndexingManagerTest {
    @Test
    @Config(shadows = {ShadowDatabaseIndexingUtils.class,})
    public void testPerformIndexing_incrementalIndex_noDataAdded() {
        final List<ResolveInfo> providerInfo = getDummyResolveInfo();
        skipFullIndex(providerInfo);
        DummyProvider provider = new DummyProvider();
        provider.onCreate();
        ShadowContentResolver.registerProvider(AUTHORITY_ONE, provider);

        // Test that Indexables are added for Full indexing
        when(mPackageManager.queryIntentContentProviders(any(Intent.class), anyInt()))
                .thenReturn(getDummyResolveInfo());
                .thenReturn(providerInfo);

        DatabaseIndexingManager manager =
                spy(new DatabaseIndexingManager(mContext, PACKAGE_ONE));
        doReturn(false).when(manager).isFullIndex(anyString(), anyString());

        manager.mDataToProcess.dataToUpdate.clear();

@@ -805,7 +805,6 @@ public class DatabaseIndexingManagerTest {
        // Initialize the Manager
        DatabaseIndexingManager manager =
                spy(new DatabaseIndexingManager(mContext, PACKAGE_ONE));
        doReturn(true).when(manager).isFullIndex(anyString(), anyString());

        // Insert data point which will be dropped
        final String oldTitle = "This is French";
@@ -845,13 +844,34 @@ public class DatabaseIndexingManagerTest {

        DatabaseIndexingManager manager =
                spy(new DatabaseIndexingManager(mContext, PACKAGE_ONE));
        doReturn(true).when(manager).isFullIndex(anyString(), anyString());

        manager.performIndexing();

        verify(manager).updateDatabase(true /* isFullIndex */, Locale.getDefault().toString());
    }

    @Test
    @Config(shadows = {ShadowDatabaseIndexingUtils.class,})
    public void testPerformIndexing_onPackageChange_shouldFullIndex() {
        final List<ResolveInfo> providers = getDummyResolveInfo();
        final String buildNumber = Build.FINGERPRINT;
        final String locale = Locale.getDefault().toString();
        skipFullIndex(providers);

        // This snapshot is already indexed. Should return false
        assertThat(IndexDatabaseHelper.isFullIndex(
                mContext, locale, buildNumber,
                IndexDatabaseHelper.buildProviderVersionedNames(providers)))
                .isFalse();

        // Change provider version number, this should trigger full index.
        providers.get(0).providerInfo.applicationInfo.versionCode++;

        assertThat(IndexDatabaseHelper.isFullIndex(mContext, locale, buildNumber,
                IndexDatabaseHelper.buildProviderVersionedNames(providers)))
                .isTrue();
    }

    @Test
    @Config(shadows = {ShadowDatabaseIndexingUtils.class,})
    public void testPerformIndexing_onOta_buildNumberIsCached() {
@@ -867,7 +887,6 @@ public class DatabaseIndexingManagerTest {

        DatabaseIndexingManager manager =
                spy(new DatabaseIndexingManager(mContext, PACKAGE_ONE));
        doReturn(true).when(manager).isFullIndex(anyString(), anyString());

        manager.performIndexing();

@@ -1037,6 +1056,13 @@ public class DatabaseIndexingManagerTest {

    // Util functions

    private void skipFullIndex(List<ResolveInfo> providers) {
        IndexDatabaseHelper.setLocaleIndexed(mContext, Locale.getDefault().toString());
        IndexDatabaseHelper.setBuildIndexed(mContext, Build.FINGERPRINT);
        IndexDatabaseHelper.setProvidersIndexed(mContext,
                IndexDatabaseHelper.buildProviderVersionedNames(providers));
    }

    private SearchIndexableRaw getFakeRaw() {
        return getFakeRaw(localeStr);
    }
@@ -1092,6 +1118,7 @@ public class DatabaseIndexingManagerTest {
        info.providerInfo.exported = true;
        info.providerInfo.authority = AUTHORITY_ONE;
        info.providerInfo.packageName = PACKAGE_ONE;
        info.providerInfo.applicationInfo = new ApplicationInfo();
        infoList.add(info);

        return infoList;