1 /* 2 * Copyright (C) 2018 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.slices; 19 20 import static com.google.common.truth.Truth.assertThat; 21 22 import static org.mockito.Mockito.spy; 23 24 import android.app.ApplicationPackageManager; 25 import android.content.ComponentName; 26 import android.content.ContentValues; 27 import android.content.Context; 28 import android.database.sqlite.SQLiteDatabase; 29 import android.net.Uri; 30 import android.view.accessibility.AccessibilityManager; 31 32 import com.android.settings.search.SearchFeatureProvider; 33 import com.android.settings.search.SearchFeatureProviderImpl; 34 import com.android.settings.testutils.DatabaseTestUtils; 35 import com.android.settings.testutils.FakeFeatureFactory; 36 import com.android.settings.testutils.FakeIndexProvider; 37 import com.android.settings.testutils.shadow.ShadowBluetoothAdapter; 38 import com.android.settings.testutils.shadow.ShadowLockPatternUtils; 39 import com.android.settings.testutils.shadow.ShadowUserManager; 40 import com.android.settings.testutils.shadow.ShadowUtils; 41 42 import org.junit.After; 43 import org.junit.Before; 44 import org.junit.Test; 45 import org.junit.runner.RunWith; 46 import org.robolectric.RobolectricTestRunner; 47 import org.robolectric.RuntimeEnvironment; 48 import org.robolectric.annotation.Config; 49 import org.robolectric.annotation.Implementation; 50 import org.robolectric.annotation.Implements; 51 import org.robolectric.shadow.api.Shadow; 52 import org.robolectric.shadows.ShadowAccessibilityManager; 53 54 import java.util.ArrayList; 55 import java.util.List; 56 import java.util.Locale; 57 58 @RunWith(RobolectricTestRunner.class) 59 @Config(shadows = {ShadowUserManager.class, ShadowUtils.class, 60 SlicesDatabaseAccessorTest.ShadowApplicationPackageManager.class, 61 ShadowBluetoothAdapter.class, ShadowLockPatternUtils.class}) 62 public class SlicesDatabaseAccessorTest { 63 64 private final String FAKE_TITLE = "title"; 65 private final String FAKE_SUMMARY = "summary"; 66 private final String FAKE_SCREEN_TITLE = "screen_title"; 67 private final String FAKE_KEYWORDS = "a, b, c"; 68 private final int FAKE_ICON = 1234; 69 private final String FAKE_FRAGMENT_NAME = FakeIndexProvider.class.getName(); 70 private final String FAKE_CONTROLLER_NAME = FakePreferenceController.class.getName(); 71 72 private Context mContext; 73 private SQLiteDatabase mDb; 74 private SlicesDatabaseAccessor mAccessor; 75 76 @Before setUp()77 public void setUp() { 78 mContext = RuntimeEnvironment.application; 79 ShadowUserManager.getShadow().setIsAdminUser(true); 80 mAccessor = spy(new SlicesDatabaseAccessor(mContext)); 81 mDb = SlicesDatabaseHelper.getInstance(mContext).getWritableDatabase(); 82 SlicesDatabaseHelper.getInstance(mContext).setIndexedState(); 83 84 // Register the fake a11y Service 85 ShadowAccessibilityManager shadowAccessibilityManager = Shadow.extract( 86 RuntimeEnvironment.application.getSystemService(AccessibilityManager.class)); 87 shadowAccessibilityManager.setInstalledAccessibilityServiceList(new ArrayList<>()); 88 } 89 90 @After cleanUp()91 public void cleanUp() { 92 DatabaseTestUtils.clearDb(mContext); 93 } 94 95 @Test testGetSliceDataFromKey_validKey_validSliceReturned()96 public void testGetSliceDataFromKey_validKey_validSliceReturned() { 97 String key = "key"; 98 insertSpecialCase(key); 99 100 SliceData data = mAccessor.getSliceDataFromKey(key); 101 102 assertThat(data.getKey()).isEqualTo(key); 103 assertThat(data.getTitle()).isEqualTo(FAKE_TITLE); 104 assertThat(data.getSummary()).isEqualTo(FAKE_SUMMARY); 105 assertThat(data.getScreenTitle()).isEqualTo(FAKE_SCREEN_TITLE); 106 assertThat(data.getKeywords()).isEqualTo(FAKE_KEYWORDS); 107 assertThat(data.getIconResource()).isEqualTo(FAKE_ICON); 108 assertThat(data.getFragmentClassName()).isEqualTo(FAKE_FRAGMENT_NAME); 109 assertThat(data.getUri()).isNull(); 110 assertThat(data.getPreferenceController()).isEqualTo(FAKE_CONTROLLER_NAME); 111 assertThat(data.getUnavailableSliceSubtitle()).isNull(); 112 } 113 114 @Test testGetSliceDataFromKey_allowDynamicSummary_validSliceReturned()115 public void testGetSliceDataFromKey_allowDynamicSummary_validSliceReturned() { 116 String key = "key"; 117 insertSpecialCase(key, true /* isPlatformSlice */, 118 null /* customizedUnavailableSliceSubtitle */); 119 120 SliceData data = mAccessor.getSliceDataFromKey(key); 121 122 assertThat(data.getKey()).isEqualTo(key); 123 assertThat(data.getTitle()).isEqualTo(FAKE_TITLE); 124 assertThat(data.getSummary()).isEqualTo(FAKE_SUMMARY); 125 assertThat(data.getScreenTitle()).isEqualTo(FAKE_SCREEN_TITLE); 126 assertThat(data.getKeywords()).isEqualTo(FAKE_KEYWORDS); 127 assertThat(data.getIconResource()).isEqualTo(FAKE_ICON); 128 assertThat(data.getFragmentClassName()).isEqualTo(FAKE_FRAGMENT_NAME); 129 assertThat(data.getUri()).isNull(); 130 assertThat(data.getPreferenceController()).isEqualTo(FAKE_CONTROLLER_NAME); 131 } 132 133 @Test(expected = IllegalStateException.class) testGetSliceDataFromKey_invalidKey_errorThrown()134 public void testGetSliceDataFromKey_invalidKey_errorThrown() { 135 String key = "key"; 136 137 mAccessor.getSliceDataFromKey(key); 138 } 139 140 @Test testGetSliceFromUri_validUri_validSliceReturned()141 public void testGetSliceFromUri_validUri_validSliceReturned() { 142 String key = "key"; 143 String path = "intent/" + key; 144 insertSpecialCase(key); 145 Uri uri = SliceBuilderUtils.getUri(path, false); 146 147 SliceData data = mAccessor.getSliceDataFromUri(uri); 148 149 assertThat(data.getKey()).isEqualTo(key); 150 assertThat(data.getTitle()).isEqualTo(FAKE_TITLE); 151 assertThat(data.getSummary()).isEqualTo(FAKE_SUMMARY); 152 assertThat(data.getScreenTitle()).isEqualTo(FAKE_SCREEN_TITLE); 153 assertThat(data.getKeywords()).isEqualTo(FAKE_KEYWORDS); 154 assertThat(data.getIconResource()).isEqualTo(FAKE_ICON); 155 assertThat(data.getFragmentClassName()).isEqualTo(FAKE_FRAGMENT_NAME); 156 assertThat(data.getUri()).isEqualTo(uri); 157 assertThat(data.getPreferenceController()).isEqualTo(FAKE_CONTROLLER_NAME); 158 } 159 160 @Test(expected = IllegalStateException.class) testGetSliceFromUri_invalidUri_errorThrown()161 public void testGetSliceFromUri_invalidUri_errorThrown() { 162 Uri uri = SliceBuilderUtils.getUri("intent/durr", false); 163 mAccessor.getSliceDataFromUri(uri); 164 } 165 166 @Test getDescendantUris_platformSlice_doesNotReturnOEMSlice()167 public void getDescendantUris_platformSlice_doesNotReturnOEMSlice() { 168 final String key = "oem_key"; 169 final boolean isPlatformSlice = false; 170 insertSpecialCase(key, isPlatformSlice); 171 final List<String> keys = mAccessor.getSliceKeys(!isPlatformSlice); 172 173 assertThat(keys).isEmpty(); 174 } 175 176 @Test getDescendantUris_oemSlice_doesNotReturnPlatformSlice()177 public void getDescendantUris_oemSlice_doesNotReturnPlatformSlice() { 178 final String key = "platform_key"; 179 final boolean isPlatformSlice = true; 180 insertSpecialCase(key, isPlatformSlice); 181 final List<String> keys = mAccessor.getSliceKeys(!isPlatformSlice); 182 183 assertThat(keys).isEmpty(); 184 } 185 186 @Test getDescendantUris_oemSlice_returnsOEMUriDescendant()187 public void getDescendantUris_oemSlice_returnsOEMUriDescendant() { 188 final String key = "oem_key"; 189 final boolean isPlatformSlice = false; 190 insertSpecialCase(key, isPlatformSlice); 191 final List<String> keys = mAccessor.getSliceKeys(isPlatformSlice); 192 193 assertThat(keys).containsExactly(key); 194 } 195 196 @Test getDescendantUris_platformSlice_returnsPlatformUriDescendant()197 public void getDescendantUris_platformSlice_returnsPlatformUriDescendant() { 198 final String key = "platform_key"; 199 final boolean isPlatformSlice = true; 200 insertSpecialCase(key, isPlatformSlice); 201 final List<String> keys = mAccessor.getSliceKeys(isPlatformSlice); 202 203 assertThat(keys).containsExactly(key); 204 } 205 206 @Test 207 @Config(qualifiers = "mcc999") getSliceKeys_indexesDatabase()208 public void getSliceKeys_indexesDatabase() { 209 // Force new indexing 210 Locale.setDefault(new Locale("ca")); 211 final SearchFeatureProvider provider = new SearchFeatureProviderImpl(); 212 final SlicesFeatureProvider sliceProvider = spy(new SlicesFeatureProviderImpl()); 213 final FakeFeatureFactory factory = FakeFeatureFactory.setupForTest(); 214 factory.searchFeatureProvider = provider; 215 factory.slicesFeatureProvider = sliceProvider; 216 // Fake the indexable list. 217 provider.getSearchIndexableResources().getProviderValues().clear(); 218 provider.getSearchIndexableResources().getProviderValues().add( 219 FakeIndexProvider.class); 220 221 final SlicesDatabaseAccessor accessor = new SlicesDatabaseAccessor(mContext); 222 final List<String> keys = accessor.getSliceKeys(true); 223 224 assertThat(keys).isNotEmpty(); 225 } 226 227 @Test testGetSliceDataFromKey_defaultUnavailableSlice_validSliceReturned()228 public void testGetSliceDataFromKey_defaultUnavailableSlice_validSliceReturned() { 229 String key = "key"; 230 insertSpecialCase(key, true /* isPlatformSlice */, 231 null /* customizedUnavailableSliceSubtitle */); 232 233 SliceData data = mAccessor.getSliceDataFromKey(key); 234 235 assertThat(data.getKey()).isEqualTo(key); 236 assertThat(data.getTitle()).isEqualTo(FAKE_TITLE); 237 assertThat(data.getSummary()).isEqualTo(FAKE_SUMMARY); 238 assertThat(data.getScreenTitle()).isEqualTo(FAKE_SCREEN_TITLE); 239 assertThat(data.getKeywords()).isEqualTo(FAKE_KEYWORDS); 240 assertThat(data.getIconResource()).isEqualTo(FAKE_ICON); 241 assertThat(data.getFragmentClassName()).isEqualTo(FAKE_FRAGMENT_NAME); 242 assertThat(data.getUri()).isNull(); 243 assertThat(data.getPreferenceController()).isEqualTo(FAKE_CONTROLLER_NAME); 244 assertThat(data.getUnavailableSliceSubtitle()).isNull(); 245 } 246 247 @Test testGetSliceDataFromKey_customizeSubtitleOfUnavailableSlice_validSliceReturned()248 public void testGetSliceDataFromKey_customizeSubtitleOfUnavailableSlice_validSliceReturned() { 249 String key = "key"; 250 String subtitle = "subtitle"; 251 insertSpecialCase(key, true /* isPlatformSlice */, subtitle); 252 253 SliceData data = mAccessor.getSliceDataFromKey(key); 254 255 assertThat(data.getKey()).isEqualTo(key); 256 assertThat(data.getTitle()).isEqualTo(FAKE_TITLE); 257 assertThat(data.getSummary()).isEqualTo(FAKE_SUMMARY); 258 assertThat(data.getScreenTitle()).isEqualTo(FAKE_SCREEN_TITLE); 259 assertThat(data.getKeywords()).isEqualTo(FAKE_KEYWORDS); 260 assertThat(data.getIconResource()).isEqualTo(FAKE_ICON); 261 assertThat(data.getFragmentClassName()).isEqualTo(FAKE_FRAGMENT_NAME); 262 assertThat(data.getUri()).isNull(); 263 assertThat(data.getPreferenceController()).isEqualTo(FAKE_CONTROLLER_NAME); 264 assertThat(data.getUnavailableSliceSubtitle()).isEqualTo(subtitle); 265 } 266 insertSpecialCase(String key)267 private void insertSpecialCase(String key) { 268 insertSpecialCase(key, true); 269 } 270 insertSpecialCase(String key, boolean isPlatformSlice)271 private void insertSpecialCase(String key, boolean isPlatformSlice) { 272 insertSpecialCase(key, isPlatformSlice, null /*customizedUnavailableSliceSubtitle*/); 273 } 274 insertSpecialCase(String key, boolean isPlatformSlice, String customizedUnavailableSliceSubtitle)275 private void insertSpecialCase(String key, boolean isPlatformSlice, 276 String customizedUnavailableSliceSubtitle) { 277 ContentValues values = new ContentValues(); 278 values.put(SlicesDatabaseHelper.IndexColumns.KEY, key); 279 values.put(SlicesDatabaseHelper.IndexColumns.TITLE, FAKE_TITLE); 280 values.put(SlicesDatabaseHelper.IndexColumns.SUMMARY, FAKE_SUMMARY); 281 values.put(SlicesDatabaseHelper.IndexColumns.SCREENTITLE, FAKE_SCREEN_TITLE); 282 values.put(SlicesDatabaseHelper.IndexColumns.KEYWORDS, FAKE_KEYWORDS); 283 values.put(SlicesDatabaseHelper.IndexColumns.ICON_RESOURCE, FAKE_ICON); 284 values.put(SlicesDatabaseHelper.IndexColumns.FRAGMENT, FAKE_FRAGMENT_NAME); 285 values.put(SlicesDatabaseHelper.IndexColumns.CONTROLLER, FAKE_CONTROLLER_NAME); 286 values.put(SlicesDatabaseHelper.IndexColumns.PLATFORM_SLICE, isPlatformSlice); 287 values.put(SlicesDatabaseHelper.IndexColumns.SLICE_TYPE, SliceData.SliceType.INTENT); 288 values.put(SlicesDatabaseHelper.IndexColumns.UNAVAILABLE_SLICE_SUBTITLE, 289 customizedUnavailableSliceSubtitle); 290 291 mDb.replaceOrThrow(SlicesDatabaseHelper.Tables.TABLE_SLICES_INDEX, null, values); 292 } 293 294 @Implements(ApplicationPackageManager.class) 295 public static class ShadowApplicationPackageManager extends 296 org.robolectric.shadows.ShadowApplicationPackageManager { 297 298 @Implementation getInstantAppResolverSettingsComponent()299 protected ComponentName getInstantAppResolverSettingsComponent() { 300 return null; 301 } 302 } 303 } 304