From aa08a2cc0e84b91a7f3f351569f73c653e748232 Mon Sep 17 00:00:00 2001 From: Fan Zhang Date: Fri, 31 May 2019 12:37:27 -0700 Subject: [PATCH] Use slice uri from slice index db directly. During SettingsSliceProvider#onGetSliceDescendants, use the uris from database directly instead of getting the key and construct the uris manually. Bug: 126222433 Test: robotest Change-Id: Iad4e9fc28ec4442b6bb323878503d743582b35ac --- .../slices/SettingsSliceProvider.java | 171 +++++++----------- .../slices/SlicesDatabaseAccessor.java | 34 ++-- .../slices/SettingsSliceProviderTest.java | 125 +++++-------- .../settings/slices/SliceTestUtils.java | 77 ++++++++ .../slices/SlicesDatabaseAccessorTest.java | 147 ++++++--------- 5 files changed, 264 insertions(+), 290 deletions(-) create mode 100644 tests/robotests/src/com/android/settings/slices/SliceTestUtils.java diff --git a/src/com/android/settings/slices/SettingsSliceProvider.java b/src/com/android/settings/slices/SettingsSliceProvider.java index 9b5fbd86253..82c8cc4b73b 100644 --- a/src/com/android/settings/slices/SettingsSliceProvider.java +++ b/src/com/android/settings/slices/SettingsSliceProvider.java @@ -20,7 +20,6 @@ import static android.Manifest.permission.READ_SEARCH_INDEXABLES; import android.app.PendingIntent; import android.app.slice.SliceManager; -import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; @@ -57,6 +56,7 @@ import java.util.List; import java.util.Map; import java.util.Set; import java.util.WeakHashMap; +import java.util.stream.Collectors; /** * A {@link SliceProvider} for Settings to enabled inline results in system apps. @@ -118,6 +118,22 @@ public class SettingsSliceProvider extends SliceProvider { public static final String EXTRA_SLICE_PLATFORM_DEFINED = "com.android.settings.slice.extra.platform"; + + /** + * A list of custom slice uris that are supported publicly. This is a subset of slices defined + * in {@link CustomSliceRegistry}. Things here are exposed publicly so all clients with proper + * permission can use them. + */ + private static final List PUBLICLY_SUPPORTED_CUSTOM_SLICE_URIS = + Arrays.asList( + CustomSliceRegistry.BLUETOOTH_URI, + CustomSliceRegistry.FLASHLIGHT_SLICE_URI, + CustomSliceRegistry.LOCATION_SLICE_URI, + CustomSliceRegistry.MOBILE_DATA_SLICE_URI, + CustomSliceRegistry.WIFI_SLICE_URI, + CustomSliceRegistry.ZEN_MODE_SLICE_URI + ); + private static final KeyValueListParser KEY_VALUE_LIST_PARSER = new KeyValueListParser(','); @VisibleForTesting @@ -264,37 +280,30 @@ public class SettingsSliceProvider extends SliceProvider { } final String authority = uri.getAuthority(); - final String pathPrefix = uri.getPath(); - final boolean isPathEmpty = pathPrefix.isEmpty(); - - // No path nor authority. Return all possible Uris. - if (isPathEmpty && TextUtils.isEmpty(authority)) { - final List platformKeys = mSlicesDatabaseAccessor.getSliceKeys( - true /* isPlatformSlice */); - final List oemKeys = mSlicesDatabaseAccessor.getSliceKeys( - false /* isPlatformSlice */); - descendants.addAll(buildUrisFromKeys(platformKeys, SettingsSlicesContract.AUTHORITY)); - descendants.addAll(buildUrisFromKeys(oemKeys, SettingsSliceProvider.SLICE_AUTHORITY)); - descendants.addAll(getSpecialCaseUris(true /* isPlatformSlice */)); - descendants.addAll(getSpecialCaseUris(false /* isPlatformSlice */)); - - return descendants; - } + final String path = uri.getPath(); + final boolean isPathEmpty = path.isEmpty(); // Path is anything but empty, "action", or "intent". Return empty list. if (!isPathEmpty - && !TextUtils.equals(pathPrefix, "/" + SettingsSlicesContract.PATH_SETTING_ACTION) - && !TextUtils.equals(pathPrefix, - "/" + SettingsSlicesContract.PATH_SETTING_INTENT)) { + && !TextUtils.equals(path, "/" + SettingsSlicesContract.PATH_SETTING_ACTION) + && !TextUtils.equals(path, "/" + SettingsSlicesContract.PATH_SETTING_INTENT)) { // Invalid path prefix, there are no valid Uri descendants. return descendants; } - // Can assume authority belongs to the provider. Return all Uris for the authority. - final boolean isPlatformUri = TextUtils.equals(authority, SettingsSlicesContract.AUTHORITY); - final List keys = mSlicesDatabaseAccessor.getSliceKeys(isPlatformUri); - descendants.addAll(buildUrisFromKeys(keys, authority)); - descendants.addAll(getSpecialCaseUris(isPlatformUri)); + // Add all descendants from db with matching authority. + descendants.addAll(mSlicesDatabaseAccessor.getSliceUris(authority)); + + if (isPathEmpty && TextUtils.isEmpty(authority)) { + // No path nor authority. Return all possible Uris by adding all special slice uri + descendants.addAll(PUBLICLY_SUPPORTED_CUSTOM_SLICE_URIS); + } else { + // Can assume authority belongs to the provider. Return all Uris for the authority. + final List customSlices = PUBLICLY_SUPPORTED_CUSTOM_SLICE_URIS.stream() + .filter(sliceUri -> TextUtils.equals(authority, sliceUri.getAuthority())) + .collect(Collectors.toList()); + descendants.addAll(customSlices); + } grantWhitelistedPackagePermissions(getContext(), descendants); return descendants; } @@ -332,32 +341,6 @@ public class SettingsSliceProvider extends SliceProvider { } } - private void startBackgroundWorker(Sliceable sliceable, Uri uri) { - final Class workerClass = sliceable.getBackgroundWorkerClass(); - if (workerClass == null) { - return; - } - - if (mPinnedWorkers.containsKey(uri)) { - return; - } - - Log.d(TAG, "Starting background worker for: " + uri); - final SliceBackgroundWorker worker = SliceBackgroundWorker.getInstance( - getContext(), sliceable, uri); - mPinnedWorkers.put(uri, worker); - worker.onSlicePinned(); - } - - private void stopBackgroundWorker(Uri uri) { - final SliceBackgroundWorker worker = mPinnedWorkers.get(uri); - if (worker != null) { - Log.d(TAG, "Stopping background worker for: " + uri); - worker.onSliceUnpinned(); - mPinnedWorkers.remove(uri); - } - } - @Override public void shutdown() { ThreadUtils.postOnMainThread(() -> { @@ -365,23 +348,6 @@ public class SettingsSliceProvider extends SliceProvider { }); } - private List buildUrisFromKeys(List keys, String authority) { - final List descendants = new ArrayList<>(); - - final Uri.Builder builder = new Uri.Builder() - .scheme(ContentResolver.SCHEME_CONTENT) - .authority(authority) - .appendPath(SettingsSlicesContract.PATH_SETTING_ACTION); - - final String newUriPathPrefix = SettingsSlicesContract.PATH_SETTING_ACTION + "/"; - for (String key : keys) { - builder.path(newUriPathPrefix + key); - descendants.add(builder.build()); - } - - return descendants; - } - @VisibleForTesting void loadSlice(Uri uri) { long startBuildTime = System.currentTimeMillis(); @@ -416,38 +382,6 @@ public class SettingsSliceProvider extends SliceProvider { ThreadUtils.postOnBackgroundThread(() -> loadSlice(uri)); } - /** - * @return an empty {@link Slice} with {@param uri} to be used as a stub while the real - * {@link SliceData} is loaded from {@link SlicesDatabaseHelper.Tables#TABLE_SLICES_INDEX}. - */ - private Slice getSliceStub(Uri uri) { - // TODO: Switch back to ListBuilder when slice loading states are fixed. - return new Slice.Builder(uri).build(); - } - - private List getSpecialCaseUris(boolean isPlatformUri) { - if (isPlatformUri) { - return getSpecialCasePlatformUris(); - } - return getSpecialCaseOemUris(); - } - - private List getSpecialCasePlatformUris() { - return Arrays.asList( - CustomSliceRegistry.WIFI_SLICE_URI, - CustomSliceRegistry.BLUETOOTH_URI, - CustomSliceRegistry.LOCATION_SLICE_URI - ); - } - - private List getSpecialCaseOemUris() { - return Arrays.asList( - CustomSliceRegistry.FLASHLIGHT_SLICE_URI, - CustomSliceRegistry.MOBILE_DATA_SLICE_URI, - CustomSliceRegistry.ZEN_MODE_SLICE_URI - ); - } - @VisibleForTesting /** * Registers an IntentFilter in SysUI to notify changes to {@param sliceUri} when broadcasts to @@ -476,7 +410,42 @@ public class SettingsSliceProvider extends SliceProvider { return set; } - private String[] parseStringArray(String value) { + private void startBackgroundWorker(Sliceable sliceable, Uri uri) { + final Class workerClass = sliceable.getBackgroundWorkerClass(); + if (workerClass == null) { + return; + } + + if (mPinnedWorkers.containsKey(uri)) { + return; + } + + Log.d(TAG, "Starting background worker for: " + uri); + final SliceBackgroundWorker worker = SliceBackgroundWorker.getInstance( + getContext(), sliceable, uri); + mPinnedWorkers.put(uri, worker); + worker.onSlicePinned(); + } + + private void stopBackgroundWorker(Uri uri) { + final SliceBackgroundWorker worker = mPinnedWorkers.get(uri); + if (worker != null) { + Log.d(TAG, "Stopping background worker for: " + uri); + worker.onSliceUnpinned(); + mPinnedWorkers.remove(uri); + } + } + + /** + * @return an empty {@link Slice} with {@param uri} to be used as a stub while the real + * {@link SliceData} is loaded from {@link SlicesDatabaseHelper.Tables#TABLE_SLICES_INDEX}. + */ + private static Slice getSliceStub(Uri uri) { + // TODO: Switch back to ListBuilder when slice loading states are fixed. + return new Slice.Builder(uri).build(); + } + + private static String[] parseStringArray(String value) { if (value != null) { String[] parts = value.split(":"); if (parts.length > 0) { diff --git a/src/com/android/settings/slices/SlicesDatabaseAccessor.java b/src/com/android/settings/slices/SlicesDatabaseAccessor.java index 8b63773eafc..453fea6fb1c 100644 --- a/src/com/android/settings/slices/SlicesDatabaseAccessor.java +++ b/src/com/android/settings/slices/SlicesDatabaseAccessor.java @@ -23,6 +23,7 @@ import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.net.Uri; import android.os.Binder; +import android.text.TextUtils; import android.util.Pair; import androidx.slice.Slice; @@ -91,34 +92,29 @@ public class SlicesDatabaseAccessor { } /** - * @return a list of keys in the Slices database matching on {@param isPlatformSlice}. + * @return a list of Slice {@link Uri}s matching {@param authority}. */ - public List getSliceKeys(boolean isPlatformSlice) { + public List getSliceUris(String authority) { verifyIndexing(); - final String whereClause; - - if (isPlatformSlice) { - whereClause = IndexColumns.PLATFORM_SLICE + " = 1"; - } else { - whereClause = IndexColumns.PLATFORM_SLICE + " = 0"; - } - + final List uris = new ArrayList<>(); final SQLiteDatabase database = mHelper.getReadableDatabase(); - final String[] columns = new String[]{IndexColumns.KEY}; - final List keys = new ArrayList<>(); - - try (final Cursor resultCursor = database.query(TABLE_SLICES_INDEX, columns, whereClause, - null /* selection */, null /* groupBy */, null /* having */, null /* orderBy */)) { + final String[] columns = new String[]{IndexColumns.SLICE_URI}; + try (final Cursor resultCursor = database.query(TABLE_SLICES_INDEX, columns, + null /* where */, null /* selection */, null /* groupBy */, null /* having */, + null /* orderBy */)) { if (!resultCursor.moveToFirst()) { - return keys; + return uris; } do { - keys.add(resultCursor.getString(0 /* key index */)); + final Uri uri = Uri.parse(resultCursor.getString(0 /* SLICE_URI */)); + if (TextUtils.isEmpty(authority) + || TextUtils.equals(authority, uri.getAuthority())) { + uris.add(uri); + } } while (resultCursor.moveToNext()); } - - return keys; + return uris; } private Cursor getIndexedSliceData(String path) { diff --git a/tests/robotests/src/com/android/settings/slices/SettingsSliceProviderTest.java b/tests/robotests/src/com/android/settings/slices/SettingsSliceProviderTest.java index 8431dc3cc5d..4d7a100cb61 100644 --- a/tests/robotests/src/com/android/settings/slices/SettingsSliceProviderTest.java +++ b/tests/robotests/src/com/android/settings/slices/SettingsSliceProviderTest.java @@ -108,13 +108,8 @@ public class SettingsSliceProviderTest { .appendPath(SettingsSlicesContract.PATH_SETTING_ACTION) .appendPath(KEY) .build(); - private static final String TITLE = "title"; - private static final String SUMMARY = "summary"; - private static final String SCREEN_TITLE = "screen title"; - private static final String FRAGMENT_NAME = "fragment name"; - private static final int ICON = R.drawable.ic_settings_accent; + private static final Uri URI = Uri.parse("content://com.android.settings.slices/test"); - private static final String PREF_CONTROLLER = FakeToggleController.class.getName(); private Context mContext; private SettingsSliceProvider mProvider; @@ -164,7 +159,7 @@ public class SettingsSliceProviderTest { @Test public void testInitialSliceReturned_emptySlice() { - insertSpecialCase(KEY); + SliceTestUtils.insertSliceToDb(mContext, KEY); Slice slice = mProvider.onBindSlice(INTENT_SLICE_URI); assertThat(slice.getUri()).isEqualTo(INTENT_SLICE_URI); @@ -173,18 +168,18 @@ public class SettingsSliceProviderTest { @Test public void testLoadSlice_returnsSliceFromAccessor() { - insertSpecialCase(KEY); + SliceTestUtils.insertSliceToDb(mContext, KEY); mProvider.loadSlice(INTENT_SLICE_URI); SliceData data = mProvider.mSliceWeakDataCache.get(INTENT_SLICE_URI); assertThat(data.getKey()).isEqualTo(KEY); - assertThat(data.getTitle()).isEqualTo(TITLE); + assertThat(data.getTitle()).isEqualTo(SliceTestUtils.FAKE_TITLE); } @Test public void loadSlice_registersIntentFilter() { - insertSpecialCase(KEY); + SliceTestUtils.insertSliceToDb(mContext, KEY); mProvider.loadSlice(INTENT_SLICE_URI); @@ -194,7 +189,7 @@ public class SettingsSliceProviderTest { @Test public void loadSlice_registersBackgroundListener() { - insertSpecialCase(KEY); + SliceTestUtils.insertSliceToDb(mContext, KEY); mProvider.loadSlice(INTENT_SLICE_URI); @@ -210,7 +205,7 @@ public class SettingsSliceProviderTest { SliceData data = getDummyData(); mProvider.mSliceWeakDataCache.put(data.getUri(), data); mProvider.onBindSlice(data.getUri()); - insertSpecialCase(data.getKey()); + SliceTestUtils.insertSliceToDb(mContext, data.getKey()); SliceData cachedData = mProvider.mSliceWeakDataCache.get(data.getUri()); @@ -291,7 +286,7 @@ public class SettingsSliceProviderTest { @Test public void getDescendantUris_invalidPath_returnsEmpty() { final String key = "platform_key"; - insertSpecialCase(key, true /* isPlatformSlice */); + SliceTestUtils.insertSliceToDb(mContext, key, true /* isPlatformSlice */); final Uri uri = new Uri.Builder() .scheme(SCHEME_CONTENT) .authority(SettingsSlicesContract.AUTHORITY) @@ -306,7 +301,7 @@ public class SettingsSliceProviderTest { @Test public void getDescendantUris_platformSlice_doesNotReturnOEMSlice() { - insertSpecialCase("oem_key", false /* isPlatformSlice */); + SliceTestUtils.insertSliceToDb(mContext, "oem_key", false /* isPlatformSlice */); final Uri uri = new Uri.Builder() .scheme(SCHEME_CONTENT) .authority(SettingsSlicesContract.AUTHORITY) @@ -320,7 +315,7 @@ public class SettingsSliceProviderTest { @Test public void getDescendantUris_oemSlice_doesNotReturnPlatformSlice() { - insertSpecialCase("platform_key", true /* isPlatformSlice */); + SliceTestUtils.insertSliceToDb(mContext, "platform_key", true /* isPlatformSlice */); final Uri uri = new Uri.Builder() .scheme(SCHEME_CONTENT) .authority(SettingsSliceProvider.SLICE_AUTHORITY) @@ -335,7 +330,7 @@ public class SettingsSliceProviderTest { @Test public void getDescendantUris_oemSlice_returnsOEMUriDescendant() { final String key = "oem_key"; - insertSpecialCase(key, false /* isPlatformSlice */); + SliceTestUtils.insertSliceToDb(mContext, key, false /* isPlatformSlice */); final Uri uri = new Uri.Builder() .scheme(SCHEME_CONTENT) .authority(SettingsSliceProvider.SLICE_AUTHORITY) @@ -358,7 +353,7 @@ public class SettingsSliceProviderTest { @Test public void getDescendantUris_oemSliceNoPath_returnsOEMUriDescendant() { final String key = "oem_key"; - insertSpecialCase(key, false /* isPlatformSlice */); + SliceTestUtils.insertSliceToDb(mContext, key, false /* isPlatformSlice */); final Uri uri = new Uri.Builder() .scheme(SCHEME_CONTENT) .authority(SettingsSliceProvider.SLICE_AUTHORITY) @@ -380,7 +375,7 @@ public class SettingsSliceProviderTest { @Test public void getDescendantUris_platformSlice_returnsPlatformUriDescendant() { final String key = "platform_key"; - insertSpecialCase(key, true /* isPlatformSlice */); + SliceTestUtils.insertSliceToDb(mContext, key, true /* isPlatformSlice */); final Uri uri = new Uri.Builder() .scheme(SCHEME_CONTENT) .authority(SettingsSlicesContract.AUTHORITY) @@ -403,7 +398,7 @@ public class SettingsSliceProviderTest { @Test public void getDescendantUris_platformSliceNoPath_returnsPlatformUriDescendant() { final String key = "platform_key"; - insertSpecialCase(key, true /* isPlatformSlice */); + SliceTestUtils.insertSliceToDb(mContext, key, true /* isPlatformSlice */); final Uri uri = new Uri.Builder() .scheme(SCHEME_CONTENT) .authority(SettingsSlicesContract.AUTHORITY) @@ -426,8 +421,8 @@ public class SettingsSliceProviderTest { public void getDescendantUris_noAuthorityNorPath_returnsAllUris() { final String platformKey = "platform_key"; final String oemKey = "oemKey"; - insertSpecialCase(platformKey, true /* isPlatformSlice */); - insertSpecialCase(oemKey, false /* isPlatformSlice */); + SliceTestUtils.insertSliceToDb(mContext, platformKey, true /* isPlatformSlice */); + SliceTestUtils.insertSliceToDb(mContext, oemKey, false /* isPlatformSlice */); final Uri uri = new Uri.Builder() .scheme(SCHEME_CONTENT) .build(); @@ -492,31 +487,6 @@ public class SettingsSliceProviderTest { mProvider.onSlicePinned(uri); } - @Implements(WifiScanWorker.class) - public static class ShadowWifiScanWorker { - private static WifiTracker mWifiTracker; - - @Implementation - protected void onSlicePinned() { - mWifiTracker = mock(WifiTracker.class); - mWifiTracker.onStart(); - } - - @Implementation - protected void onSliceUnpinned() { - mWifiTracker.onStop(); - } - - @Implementation - protected void close() { - mWifiTracker.onDestroy(); - } - - static WifiTracker getWifiTracker() { - return mWifiTracker; - } - } - @Test public void onSlicePinned_backgroundWorker_started() { mProvider.onSlicePinned(CustomSliceRegistry.WIFI_SLICE_URI); @@ -563,45 +533,44 @@ public class SettingsSliceProviderTest { .grantSlicePermission("com.android.settings.slice_whitelist_package", uris.get(0)); } - private void insertSpecialCase(String key) { - insertSpecialCase(key, true); - } - - private void insertSpecialCase(String key, boolean isPlatformSlice) { - final ContentValues values = new ContentValues(); - values.put(SlicesDatabaseHelper.IndexColumns.KEY, key); - values.put(SlicesDatabaseHelper.IndexColumns.TITLE, TITLE); - values.put(SlicesDatabaseHelper.IndexColumns.SUMMARY, "s"); - values.put(SlicesDatabaseHelper.IndexColumns.SCREENTITLE, "s"); - values.put(SlicesDatabaseHelper.IndexColumns.ICON_RESOURCE, R.drawable.ic_settings_accent); - values.put(SlicesDatabaseHelper.IndexColumns.FRAGMENT, "test"); - values.put(SlicesDatabaseHelper.IndexColumns.CONTROLLER, PREF_CONTROLLER); - values.put(SlicesDatabaseHelper.IndexColumns.PLATFORM_SLICE, isPlatformSlice); - values.put(SlicesDatabaseHelper.IndexColumns.SLICE_TYPE, SliceData.SliceType.INTENT); - final SQLiteDatabase db = SlicesDatabaseHelper.getInstance(mContext).getWritableDatabase(); - db.beginTransaction(); - try { - db.replaceOrThrow(SlicesDatabaseHelper.Tables.TABLE_SLICES_INDEX, null, values); - db.setTransactionSuccessful(); - } finally { - db.endTransaction(); - } - db.close(); - } - private static SliceData getDummyData() { return new SliceData.Builder() .setKey(KEY) - .setTitle(TITLE) - .setSummary(SUMMARY) - .setScreenTitle(SCREEN_TITLE) - .setIcon(ICON) - .setFragmentName(FRAGMENT_NAME) .setUri(URI) - .setPreferenceControllerClassName(PREF_CONTROLLER) + .setTitle(SliceTestUtils.FAKE_TITLE) + .setSummary(SliceTestUtils.FAKE_SUMMARY) + .setScreenTitle(SliceTestUtils.FAKE_SCREEN_TITLE) + .setIcon(SliceTestUtils.FAKE_ICON) + .setFragmentName(SliceTestUtils.FAKE_FRAGMENT_NAME) + .setPreferenceControllerClassName(SliceTestUtils.FAKE_CONTROLLER_NAME) .build(); } + @Implements(WifiScanWorker.class) + public static class ShadowWifiScanWorker { + private static WifiTracker mWifiTracker; + + @Implementation + protected void onSlicePinned() { + mWifiTracker = mock(WifiTracker.class); + mWifiTracker.onStart(); + } + + @Implementation + protected void onSliceUnpinned() { + mWifiTracker.onStop(); + } + + @Implementation + protected void close() { + mWifiTracker.onDestroy(); + } + + static WifiTracker getWifiTracker() { + return mWifiTracker; + } + } + @Implements(value = StrictMode.class) public static class ShadowStrictMode { diff --git a/tests/robotests/src/com/android/settings/slices/SliceTestUtils.java b/tests/robotests/src/com/android/settings/slices/SliceTestUtils.java new file mode 100644 index 00000000000..56db3a9d210 --- /dev/null +++ b/tests/robotests/src/com/android/settings/slices/SliceTestUtils.java @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.slices; + +import android.content.ContentResolver; +import android.content.ContentValues; +import android.content.Context; +import android.database.sqlite.SQLiteDatabase; +import android.net.Uri; +import android.provider.SettingsSlicesContract; + +import com.android.settings.testutils.FakeIndexProvider; +import com.android.settings.testutils.FakeToggleController; + +class SliceTestUtils { + + public static final String FAKE_TITLE = "title"; + public static final String FAKE_SUMMARY = "summary"; + public static final String FAKE_SCREEN_TITLE = "screen_title"; + public static final String FAKE_KEYWORDS = "a, b, c"; + public static final int FAKE_ICON = 1234; + public static final String FAKE_FRAGMENT_NAME = FakeIndexProvider.class.getName(); + public static final String FAKE_CONTROLLER_NAME = FakeToggleController.class.getName(); + + + public static void insertSliceToDb(Context context, String key) { + insertSliceToDb(context, key, true /* isPlatformSlice */); + } + + public static void insertSliceToDb(Context context, String key, boolean isPlatformSlice) { + insertSliceToDb(context, key, isPlatformSlice, null /*customizedUnavailableSliceSubtitle*/); + } + + public static void insertSliceToDb(Context context, String key, boolean isPlatformSlice, + String customizedUnavailableSliceSubtitle) { + final SQLiteDatabase db = SlicesDatabaseHelper.getInstance(context).getWritableDatabase(); + ContentValues values = new ContentValues(); + values.put(SlicesDatabaseHelper.IndexColumns.KEY, key); + values.put(SlicesDatabaseHelper.IndexColumns.SLICE_URI, + new Uri.Builder() + .scheme(ContentResolver.SCHEME_CONTENT) + .authority(isPlatformSlice + ? SettingsSlicesContract.AUTHORITY + : SettingsSliceProvider.SLICE_AUTHORITY) + .appendPath(SettingsSlicesContract.PATH_SETTING_ACTION) + .appendPath(key) + .build().toSafeString()); + values.put(SlicesDatabaseHelper.IndexColumns.TITLE, FAKE_TITLE); + values.put(SlicesDatabaseHelper.IndexColumns.SUMMARY, FAKE_SUMMARY); + values.put(SlicesDatabaseHelper.IndexColumns.SCREENTITLE, FAKE_SCREEN_TITLE); + values.put(SlicesDatabaseHelper.IndexColumns.KEYWORDS, FAKE_KEYWORDS); + values.put(SlicesDatabaseHelper.IndexColumns.ICON_RESOURCE, FAKE_ICON); + values.put(SlicesDatabaseHelper.IndexColumns.FRAGMENT, FAKE_FRAGMENT_NAME); + values.put(SlicesDatabaseHelper.IndexColumns.CONTROLLER, FAKE_CONTROLLER_NAME); + values.put(SlicesDatabaseHelper.IndexColumns.SLICE_TYPE, SliceData.SliceType.INTENT); + values.put(SlicesDatabaseHelper.IndexColumns.UNAVAILABLE_SLICE_SUBTITLE, + customizedUnavailableSliceSubtitle); + + db.replaceOrThrow(SlicesDatabaseHelper.Tables.TABLE_SLICES_INDEX, null, values); + db.close(); + } + +} diff --git a/tests/robotests/src/com/android/settings/slices/SlicesDatabaseAccessorTest.java b/tests/robotests/src/com/android/settings/slices/SlicesDatabaseAccessorTest.java index 15221bd47c5..bed5a27b1c1 100644 --- a/tests/robotests/src/com/android/settings/slices/SlicesDatabaseAccessorTest.java +++ b/tests/robotests/src/com/android/settings/slices/SlicesDatabaseAccessorTest.java @@ -28,6 +28,7 @@ import android.content.ContentValues; import android.content.Context; import android.database.sqlite.SQLiteDatabase; import android.net.Uri; +import android.provider.SettingsSlicesContract; import android.view.accessibility.AccessibilityManager; import com.android.settings.search.SearchFeatureProvider; @@ -62,16 +63,8 @@ import java.util.Locale; ShadowBluetoothAdapter.class, ShadowLockPatternUtils.class}) public class SlicesDatabaseAccessorTest { - private final String FAKE_TITLE = "title"; - private final String FAKE_SUMMARY = "summary"; - private final String FAKE_SCREEN_TITLE = "screen_title"; - private final String FAKE_KEYWORDS = "a, b, c"; - private final int FAKE_ICON = 1234; - private final String FAKE_FRAGMENT_NAME = FakeIndexProvider.class.getName(); - private final String FAKE_CONTROLLER_NAME = FakePreferenceController.class.getName(); private Context mContext; - private SQLiteDatabase mDb; private SlicesDatabaseAccessor mAccessor; @Before @@ -79,7 +72,6 @@ public class SlicesDatabaseAccessorTest { mContext = RuntimeEnvironment.application; ShadowUserManager.getShadow().setIsAdminUser(true); mAccessor = spy(new SlicesDatabaseAccessor(mContext)); - mDb = SlicesDatabaseHelper.getInstance(mContext).getWritableDatabase(); SlicesDatabaseHelper.getInstance(mContext).setIndexedState(); // Register the fake a11y Service @@ -96,39 +88,39 @@ public class SlicesDatabaseAccessorTest { @Test public void testGetSliceDataFromKey_validKey_validSliceReturned() { String key = "key"; - insertSpecialCase(key); + SliceTestUtils.insertSliceToDb(mContext, key); SliceData data = mAccessor.getSliceDataFromKey(key); assertThat(data.getKey()).isEqualTo(key); - assertThat(data.getTitle()).isEqualTo(FAKE_TITLE); - assertThat(data.getSummary()).isEqualTo(FAKE_SUMMARY); - assertThat(data.getScreenTitle()).isEqualTo(FAKE_SCREEN_TITLE); - assertThat(data.getKeywords()).isEqualTo(FAKE_KEYWORDS); - assertThat(data.getIconResource()).isEqualTo(FAKE_ICON); - assertThat(data.getFragmentClassName()).isEqualTo(FAKE_FRAGMENT_NAME); + assertThat(data.getTitle()).isEqualTo(SliceTestUtils.FAKE_TITLE); + assertThat(data.getSummary()).isEqualTo(SliceTestUtils.FAKE_SUMMARY); + assertThat(data.getScreenTitle()).isEqualTo(SliceTestUtils.FAKE_SCREEN_TITLE); + assertThat(data.getKeywords()).isEqualTo(SliceTestUtils.FAKE_KEYWORDS); + assertThat(data.getIconResource()).isEqualTo(SliceTestUtils.FAKE_ICON); + assertThat(data.getFragmentClassName()).isEqualTo(SliceTestUtils.FAKE_FRAGMENT_NAME); assertThat(data.getUri()).isNull(); - assertThat(data.getPreferenceController()).isEqualTo(FAKE_CONTROLLER_NAME); + assertThat(data.getPreferenceController()).isEqualTo(SliceTestUtils.FAKE_CONTROLLER_NAME); assertThat(data.getUnavailableSliceSubtitle()).isNull(); } @Test public void testGetSliceDataFromKey_allowDynamicSummary_validSliceReturned() { String key = "key"; - insertSpecialCase(key, true /* isPlatformSlice */, + SliceTestUtils.insertSliceToDb(mContext, key, true /* isPlatformSlice */, null /* customizedUnavailableSliceSubtitle */); SliceData data = mAccessor.getSliceDataFromKey(key); assertThat(data.getKey()).isEqualTo(key); - assertThat(data.getTitle()).isEqualTo(FAKE_TITLE); - assertThat(data.getSummary()).isEqualTo(FAKE_SUMMARY); - assertThat(data.getScreenTitle()).isEqualTo(FAKE_SCREEN_TITLE); - assertThat(data.getKeywords()).isEqualTo(FAKE_KEYWORDS); - assertThat(data.getIconResource()).isEqualTo(FAKE_ICON); - assertThat(data.getFragmentClassName()).isEqualTo(FAKE_FRAGMENT_NAME); + assertThat(data.getTitle()).isEqualTo(SliceTestUtils.FAKE_TITLE); + assertThat(data.getSummary()).isEqualTo(SliceTestUtils.FAKE_SUMMARY); + assertThat(data.getScreenTitle()).isEqualTo(SliceTestUtils.FAKE_SCREEN_TITLE); + assertThat(data.getKeywords()).isEqualTo(SliceTestUtils.FAKE_KEYWORDS); + assertThat(data.getIconResource()).isEqualTo(SliceTestUtils.FAKE_ICON); + assertThat(data.getFragmentClassName()).isEqualTo(SliceTestUtils.FAKE_FRAGMENT_NAME); assertThat(data.getUri()).isNull(); - assertThat(data.getPreferenceController()).isEqualTo(FAKE_CONTROLLER_NAME); + assertThat(data.getPreferenceController()).isEqualTo(SliceTestUtils.FAKE_CONTROLLER_NAME); } @Test(expected = IllegalStateException.class) @@ -141,7 +133,7 @@ public class SlicesDatabaseAccessorTest { @Test public void testGetSliceFromUri_validUri_validSliceReturned() { final String key = "key"; - insertSpecialCase(key); + SliceTestUtils.insertSliceToDb(mContext, key); final Uri uri = new Uri.Builder() .scheme(ContentResolver.SCHEME_CONTENT) @@ -153,14 +145,14 @@ public class SlicesDatabaseAccessorTest { SliceData data = mAccessor.getSliceDataFromUri(uri); assertThat(data.getKey()).isEqualTo(key); - assertThat(data.getTitle()).isEqualTo(FAKE_TITLE); - assertThat(data.getSummary()).isEqualTo(FAKE_SUMMARY); - assertThat(data.getScreenTitle()).isEqualTo(FAKE_SCREEN_TITLE); - assertThat(data.getKeywords()).isEqualTo(FAKE_KEYWORDS); - assertThat(data.getIconResource()).isEqualTo(FAKE_ICON); - assertThat(data.getFragmentClassName()).isEqualTo(FAKE_FRAGMENT_NAME); + assertThat(data.getTitle()).isEqualTo(SliceTestUtils.FAKE_TITLE); + assertThat(data.getSummary()).isEqualTo(SliceTestUtils.FAKE_SUMMARY); + assertThat(data.getScreenTitle()).isEqualTo(SliceTestUtils.FAKE_SCREEN_TITLE); + assertThat(data.getKeywords()).isEqualTo(SliceTestUtils.FAKE_KEYWORDS); + assertThat(data.getIconResource()).isEqualTo(SliceTestUtils.FAKE_ICON); + assertThat(data.getFragmentClassName()).isEqualTo(SliceTestUtils.FAKE_FRAGMENT_NAME); assertThat(data.getUri()).isEqualTo(uri); - assertThat(data.getPreferenceController()).isEqualTo(FAKE_CONTROLLER_NAME); + assertThat(data.getPreferenceController()).isEqualTo(SliceTestUtils.FAKE_CONTROLLER_NAME); } @Test(expected = IllegalStateException.class) @@ -177,9 +169,8 @@ public class SlicesDatabaseAccessorTest { @Test public void getDescendantUris_platformSlice_doesNotReturnOEMSlice() { final String key = "oem_key"; - final boolean isPlatformSlice = false; - insertSpecialCase(key, isPlatformSlice); - final List keys = mAccessor.getSliceKeys(!isPlatformSlice); + SliceTestUtils.insertSliceToDb(mContext, key, false /* isPlatformSlice */); + final List keys = mAccessor.getSliceUris(SettingsSlicesContract.AUTHORITY); assertThat(keys).isEmpty(); } @@ -187,9 +178,8 @@ public class SlicesDatabaseAccessorTest { @Test public void getDescendantUris_oemSlice_doesNotReturnPlatformSlice() { final String key = "platform_key"; - final boolean isPlatformSlice = true; - insertSpecialCase(key, isPlatformSlice); - final List keys = mAccessor.getSliceKeys(!isPlatformSlice); + SliceTestUtils.insertSliceToDb(mContext, key, true /* isPlatformSlice */); + final List keys = mAccessor.getSliceUris(SettingsSliceProvider.SLICE_AUTHORITY); assertThat(keys).isEmpty(); } @@ -197,21 +187,21 @@ public class SlicesDatabaseAccessorTest { @Test public void getDescendantUris_oemSlice_returnsOEMUriDescendant() { final String key = "oem_key"; - final boolean isPlatformSlice = false; - insertSpecialCase(key, isPlatformSlice); - final List keys = mAccessor.getSliceKeys(isPlatformSlice); + SliceTestUtils.insertSliceToDb(mContext, key, false /* isPlatformSlice */); + final List keys = mAccessor.getSliceUris(SettingsSliceProvider.SLICE_AUTHORITY); - assertThat(keys).containsExactly(key); + assertThat(keys).containsExactly( + Uri.parse("content://com.android.settings.slices/action/oem_key")); } @Test public void getDescendantUris_platformSlice_returnsPlatformUriDescendant() { final String key = "platform_key"; - final boolean isPlatformSlice = true; - insertSpecialCase(key, isPlatformSlice); - final List keys = mAccessor.getSliceKeys(isPlatformSlice); + SliceTestUtils.insertSliceToDb(mContext, key, true /* isPlatformSlice */); + final List keys = mAccessor.getSliceUris(SettingsSlicesContract.AUTHORITY); - assertThat(keys).containsExactly(key); + assertThat(keys).containsExactly( + Uri.parse("content://android.settings.slices/action/platform_key")); } @Test @@ -220,7 +210,7 @@ public class SlicesDatabaseAccessorTest { // Force new indexing Locale.setDefault(new Locale("ca")); final SearchFeatureProvider provider = new SearchFeatureProviderImpl(); - final SlicesFeatureProvider sliceProvider = spy(new SlicesFeatureProviderImpl()); + final SlicesFeatureProvider sliceProvider = new SlicesFeatureProviderImpl(); final FakeFeatureFactory factory = FakeFeatureFactory.setupForTest(); factory.searchFeatureProvider = provider; factory.slicesFeatureProvider = sliceProvider; @@ -230,7 +220,7 @@ public class SlicesDatabaseAccessorTest { FakeIndexProvider.class); final SlicesDatabaseAccessor accessor = new SlicesDatabaseAccessor(mContext); - final List keys = accessor.getSliceKeys(true); + final List keys = accessor.getSliceUris(SettingsSliceProvider.SLICE_AUTHORITY); assertThat(keys).isNotEmpty(); } @@ -238,20 +228,20 @@ public class SlicesDatabaseAccessorTest { @Test public void testGetSliceDataFromKey_defaultUnavailableSlice_validSliceReturned() { String key = "key"; - insertSpecialCase(key, true /* isPlatformSlice */, + SliceTestUtils.insertSliceToDb(mContext, key, true /* isPlatformSlice */, null /* customizedUnavailableSliceSubtitle */); SliceData data = mAccessor.getSliceDataFromKey(key); assertThat(data.getKey()).isEqualTo(key); - assertThat(data.getTitle()).isEqualTo(FAKE_TITLE); - assertThat(data.getSummary()).isEqualTo(FAKE_SUMMARY); - assertThat(data.getScreenTitle()).isEqualTo(FAKE_SCREEN_TITLE); - assertThat(data.getKeywords()).isEqualTo(FAKE_KEYWORDS); - assertThat(data.getIconResource()).isEqualTo(FAKE_ICON); - assertThat(data.getFragmentClassName()).isEqualTo(FAKE_FRAGMENT_NAME); + assertThat(data.getTitle()).isEqualTo(SliceTestUtils.FAKE_TITLE); + assertThat(data.getSummary()).isEqualTo(SliceTestUtils.FAKE_SUMMARY); + assertThat(data.getScreenTitle()).isEqualTo(SliceTestUtils.FAKE_SCREEN_TITLE); + assertThat(data.getKeywords()).isEqualTo(SliceTestUtils.FAKE_KEYWORDS); + assertThat(data.getIconResource()).isEqualTo(SliceTestUtils.FAKE_ICON); + assertThat(data.getFragmentClassName()).isEqualTo(SliceTestUtils.FAKE_FRAGMENT_NAME); assertThat(data.getUri()).isNull(); - assertThat(data.getPreferenceController()).isEqualTo(FAKE_CONTROLLER_NAME); + assertThat(data.getPreferenceController()).isEqualTo(SliceTestUtils.FAKE_CONTROLLER_NAME); assertThat(data.getUnavailableSliceSubtitle()).isNull(); } @@ -259,49 +249,22 @@ public class SlicesDatabaseAccessorTest { public void testGetSliceDataFromKey_customizeSubtitleOfUnavailableSlice_validSliceReturned() { String key = "key"; String subtitle = "subtitle"; - insertSpecialCase(key, true /* isPlatformSlice */, subtitle); + SliceTestUtils.insertSliceToDb(mContext, key, true /* isPlatformSlice */, subtitle); SliceData data = mAccessor.getSliceDataFromKey(key); assertThat(data.getKey()).isEqualTo(key); - assertThat(data.getTitle()).isEqualTo(FAKE_TITLE); - assertThat(data.getSummary()).isEqualTo(FAKE_SUMMARY); - assertThat(data.getScreenTitle()).isEqualTo(FAKE_SCREEN_TITLE); - assertThat(data.getKeywords()).isEqualTo(FAKE_KEYWORDS); - assertThat(data.getIconResource()).isEqualTo(FAKE_ICON); - assertThat(data.getFragmentClassName()).isEqualTo(FAKE_FRAGMENT_NAME); + assertThat(data.getTitle()).isEqualTo(SliceTestUtils.FAKE_TITLE); + assertThat(data.getSummary()).isEqualTo(SliceTestUtils.FAKE_SUMMARY); + assertThat(data.getScreenTitle()).isEqualTo(SliceTestUtils.FAKE_SCREEN_TITLE); + assertThat(data.getKeywords()).isEqualTo(SliceTestUtils.FAKE_KEYWORDS); + assertThat(data.getIconResource()).isEqualTo(SliceTestUtils.FAKE_ICON); + assertThat(data.getFragmentClassName()).isEqualTo(SliceTestUtils.FAKE_FRAGMENT_NAME); assertThat(data.getUri()).isNull(); - assertThat(data.getPreferenceController()).isEqualTo(FAKE_CONTROLLER_NAME); + assertThat(data.getPreferenceController()).isEqualTo(SliceTestUtils.FAKE_CONTROLLER_NAME); assertThat(data.getUnavailableSliceSubtitle()).isEqualTo(subtitle); } - private void insertSpecialCase(String key) { - insertSpecialCase(key, true); - } - - private void insertSpecialCase(String key, boolean isPlatformSlice) { - insertSpecialCase(key, isPlatformSlice, null /*customizedUnavailableSliceSubtitle*/); - } - - private void insertSpecialCase(String key, boolean isPlatformSlice, - String customizedUnavailableSliceSubtitle) { - ContentValues values = new ContentValues(); - values.put(SlicesDatabaseHelper.IndexColumns.KEY, key); - values.put(SlicesDatabaseHelper.IndexColumns.TITLE, FAKE_TITLE); - values.put(SlicesDatabaseHelper.IndexColumns.SUMMARY, FAKE_SUMMARY); - values.put(SlicesDatabaseHelper.IndexColumns.SCREENTITLE, FAKE_SCREEN_TITLE); - values.put(SlicesDatabaseHelper.IndexColumns.KEYWORDS, FAKE_KEYWORDS); - values.put(SlicesDatabaseHelper.IndexColumns.ICON_RESOURCE, FAKE_ICON); - values.put(SlicesDatabaseHelper.IndexColumns.FRAGMENT, FAKE_FRAGMENT_NAME); - values.put(SlicesDatabaseHelper.IndexColumns.CONTROLLER, FAKE_CONTROLLER_NAME); - values.put(SlicesDatabaseHelper.IndexColumns.PLATFORM_SLICE, isPlatformSlice); - values.put(SlicesDatabaseHelper.IndexColumns.SLICE_TYPE, SliceData.SliceType.INTENT); - values.put(SlicesDatabaseHelper.IndexColumns.UNAVAILABLE_SLICE_SUBTITLE, - customizedUnavailableSliceSubtitle); - - mDb.replaceOrThrow(SlicesDatabaseHelper.Tables.TABLE_SLICES_INDEX, null, values); - } - @Implements(ApplicationPackageManager.class) public static class ShadowApplicationPackageManager extends org.robolectric.shadows.ShadowApplicationPackageManager {