1 /* 2 * Copyright (C) 2016 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 package com.android.settings.dashboard; 18 19 import static com.google.common.truth.Truth.assertThat; 20 import static org.mockito.Matchers.any; 21 import static org.mockito.Matchers.anyInt; 22 import static org.mockito.Matchers.eq; 23 import static org.mockito.Mockito.doReturn; 24 import static org.mockito.Mockito.mock; 25 import static org.mockito.Mockito.spy; 26 import static org.mockito.Mockito.verify; 27 import static org.mockito.Mockito.verifyZeroInteractions; 28 import static org.mockito.Mockito.when; 29 import static org.robolectric.Shadows.shadowOf; 30 31 import android.app.Activity; 32 import android.content.ComponentName; 33 import android.content.Context; 34 import android.content.Intent; 35 import android.content.pm.PackageManager; 36 import android.content.pm.ResolveInfo; 37 import android.graphics.Bitmap; 38 import android.graphics.drawable.Icon; 39 import android.os.Bundle; 40 import android.os.UserHandle; 41 import android.os.UserManager; 42 import android.support.v7.preference.Preference; 43 44 import com.android.internal.logging.nano.MetricsProto; 45 import com.android.settings.R; 46 import com.android.settings.SettingsActivity; 47 import com.android.settings.testutils.FakeFeatureFactory; 48 import com.android.settings.testutils.SettingsRobolectricTestRunner; 49 import com.android.settings.testutils.shadow.ShadowThreadUtils; 50 import com.android.settings.testutils.shadow.ShadowTileUtils; 51 import com.android.settings.testutils.shadow.ShadowUserManager; 52 import com.android.settingslib.core.instrumentation.VisibilityLoggerMixin; 53 import com.android.settingslib.drawer.CategoryKey; 54 import com.android.settingslib.drawer.CategoryManager; 55 import com.android.settingslib.drawer.DashboardCategory; 56 import com.android.settingslib.drawer.Tile; 57 import com.android.settingslib.drawer.TileUtils; 58 59 import org.junit.Before; 60 import org.junit.Test; 61 import org.junit.runner.RunWith; 62 import org.mockito.Answers; 63 import org.mockito.Mock; 64 import org.mockito.MockitoAnnotations; 65 import org.robolectric.Robolectric; 66 import org.robolectric.RuntimeEnvironment; 67 import org.robolectric.annotation.Config; 68 import org.robolectric.shadows.ShadowActivity; 69 import org.robolectric.shadows.ShadowApplication; 70 import org.robolectric.util.ReflectionHelpers; 71 72 import java.util.ArrayList; 73 74 @RunWith(SettingsRobolectricTestRunner.class) 75 @Config(shadows = ShadowUserManager.class) 76 public class DashboardFeatureProviderImplTest { 77 78 @Mock(answer = Answers.RETURNS_DEEP_STUBS) 79 private Activity mActivity; 80 @Mock(answer = Answers.RETURNS_DEEP_STUBS) 81 private UserManager mUserManager; 82 @Mock 83 private CategoryManager mCategoryManager; 84 @Mock 85 private PackageManager mPackageManager; 86 private FakeFeatureFactory mFeatureFactory; 87 88 private Context mContext; 89 private DashboardFeatureProviderImpl mImpl; 90 91 @Before 92 public void setUp() { 93 MockitoAnnotations.initMocks(this); 94 mContext = spy(RuntimeEnvironment.application); 95 doReturn(mPackageManager).when(mContext).getPackageManager(); 96 when(mPackageManager.resolveActivity(any(Intent.class), anyInt())) 97 .thenReturn(new ResolveInfo()); 98 mFeatureFactory = FakeFeatureFactory.setupForTest(); 99 mImpl = new DashboardFeatureProviderImpl(mContext); 100 } 101 102 @Test 103 public void shouldHoldAppContext() { 104 assertThat(mImpl.mContext).isEqualTo(mContext.getApplicationContext()); 105 } 106 107 @Test 108 public void bindPreference_shouldBindAllData() { 109 final Preference preference = new Preference(RuntimeEnvironment.application); 110 final Tile tile = new Tile(); 111 tile.title = "title"; 112 tile.summary = "summary"; 113 tile.icon = Icon.createWithBitmap(Bitmap.createBitmap(1, 1, Bitmap.Config.RGB_565)); 114 tile.metaData = new Bundle(); 115 tile.metaData.putString(SettingsActivity.META_DATA_KEY_FRAGMENT_CLASS, "HI"); 116 tile.priority = 10; 117 mImpl.bindPreferenceToTile(mActivity, MetricsProto.MetricsEvent.SETTINGS_GESTURES, 118 preference, tile, "123", Preference.DEFAULT_ORDER); 119 120 assertThat(preference.getTitle()).isEqualTo(tile.title); 121 assertThat(preference.getSummary()).isEqualTo(tile.summary); 122 assertThat(preference.getIcon()).isNotNull(); 123 assertThat(preference.getFragment()) 124 .isEqualTo(tile.metaData.getString(SettingsActivity.META_DATA_KEY_FRAGMENT_CLASS)); 125 assertThat(preference.getOrder()).isEqualTo(-tile.priority); 126 } 127 128 @Test 129 public void bindPreference_noFragmentMetadata_shouldBindIntent() { 130 final Preference preference = new Preference(RuntimeEnvironment.application); 131 final Tile tile = new Tile(); 132 tile.metaData = new Bundle(); 133 tile.priority = 10; 134 tile.intent = new Intent(); 135 tile.intent.setComponent(new ComponentName("pkg", "class")); 136 137 mImpl.bindPreferenceToTile(mActivity, MetricsProto.MetricsEvent.SETTINGS_GESTURES, 138 preference, tile, "123", Preference.DEFAULT_ORDER); 139 140 assertThat(preference.getFragment()).isNull(); 141 assertThat(preference.getOnPreferenceClickListener()).isNotNull(); 142 assertThat(preference.getOrder()).isEqualTo(-tile.priority); 143 } 144 145 @Test 146 public void bindPreference_noFragmentMetadata_shouldBindToProfileSelector() { 147 final Preference preference = new Preference(RuntimeEnvironment.application); 148 final Tile tile = new Tile(); 149 tile.metaData = new Bundle(); 150 tile.userHandle = new ArrayList<>(); 151 tile.userHandle.add(mock(UserHandle.class)); 152 tile.userHandle.add(mock(UserHandle.class)); 153 tile.intent = new Intent(); 154 tile.intent.setComponent(new ComponentName("pkg", "class")); 155 156 when(mActivity.getApplicationContext().getSystemService(Context.USER_SERVICE)) 157 .thenReturn(mUserManager); 158 159 mImpl.bindPreferenceToTile(mActivity, MetricsProto.MetricsEvent.SETTINGS_GESTURES, 160 preference, tile, "123", Preference.DEFAULT_ORDER); 161 preference.getOnPreferenceClickListener().onPreferenceClick(null); 162 163 verify(mActivity).getFragmentManager(); 164 } 165 166 @Test 167 public void bindPreference_noFragmentMetadataSingleUser_shouldBindToDirectLaunchIntent() { 168 final Preference preference = new Preference(RuntimeEnvironment.application); 169 final Tile tile = new Tile(); 170 tile.metaData = new Bundle(); 171 tile.userHandle = new ArrayList<>(); 172 tile.userHandle.add(mock(UserHandle.class)); 173 tile.intent = new Intent(); 174 tile.intent.setComponent(new ComponentName("pkg", "class")); 175 176 when(mActivity.getSystemService(Context.USER_SERVICE)) 177 .thenReturn(mUserManager); 178 179 mImpl.bindPreferenceToTile(mActivity, MetricsProto.MetricsEvent.SETTINGS_GESTURES, 180 preference, tile, "123", Preference.DEFAULT_ORDER); 181 preference.getOnPreferenceClickListener().onPreferenceClick(null); 182 183 verify(mFeatureFactory.metricsFeatureProvider).logDashboardStartIntent( 184 any(Context.class), 185 any(Intent.class), 186 eq(MetricsProto.MetricsEvent.SETTINGS_GESTURES)); 187 verify(mActivity) 188 .startActivityForResultAsUser(any(Intent.class), anyInt(), any(UserHandle.class)); 189 } 190 191 @Test 192 public void bindPreference_toInternalSettingActivity_shouldBindToDirectLaunchIntentAndNotLog() { 193 final Preference preference = new Preference(RuntimeEnvironment.application); 194 final Tile tile = new Tile(); 195 tile.metaData = new Bundle(); 196 tile.userHandle = new ArrayList<>(); 197 tile.userHandle.add(mock(UserHandle.class)); 198 tile.intent = new Intent(); 199 tile.intent.setComponent( 200 new ComponentName(RuntimeEnvironment.application.getPackageName(), "class")); 201 202 when(mActivity.getSystemService(Context.USER_SERVICE)) 203 .thenReturn(mUserManager); 204 when(mActivity.getApplicationContext().getPackageName()) 205 .thenReturn(RuntimeEnvironment.application.getPackageName()); 206 207 mImpl.bindPreferenceToTile(mActivity, MetricsProto.MetricsEvent.SETTINGS_GESTURES, 208 preference, tile, "123", Preference.DEFAULT_ORDER); 209 preference.getOnPreferenceClickListener().onPreferenceClick(null); 210 verify(mFeatureFactory.metricsFeatureProvider).logDashboardStartIntent( 211 any(Context.class), 212 any(Intent.class), 213 anyInt()); 214 verify(mActivity) 215 .startActivityForResultAsUser(any(Intent.class), anyInt(), any(UserHandle.class)); 216 } 217 218 @Test 219 public void bindPreference_nullPreference_shouldIgnore() { 220 final Tile tile = mock(Tile.class); 221 mImpl.bindPreferenceToTile(mActivity, MetricsProto.MetricsEvent.VIEW_UNKNOWN, 222 null, tile, "123", Preference.DEFAULT_ORDER); 223 224 verifyZeroInteractions(tile); 225 } 226 227 @Test 228 public void bindPreference_withNullKeyNullPriority_shouldGenerateKeyAndPriority() { 229 final Preference preference = new Preference(RuntimeEnvironment.application); 230 final Tile tile = new Tile(); 231 tile.intent = new Intent(); 232 tile.intent.setComponent(new ComponentName("pkg", "class")); 233 mImpl.bindPreferenceToTile(mActivity, MetricsProto.MetricsEvent.VIEW_UNKNOWN, 234 preference, tile, null /*key */, Preference.DEFAULT_ORDER); 235 236 assertThat(preference.getKey()).isNotNull(); 237 assertThat(preference.getOrder()).isEqualTo(Preference.DEFAULT_ORDER); 238 } 239 240 @Test 241 public void bindPreference_noSummary_shouldSetSummaryToPlaceholder() { 242 final Preference preference = new Preference(RuntimeEnvironment.application); 243 final Tile tile = new Tile(); 244 tile.intent = new Intent(); 245 tile.intent.setComponent(new ComponentName("pkg", "class")); 246 mImpl.bindPreferenceToTile(mActivity, MetricsProto.MetricsEvent.VIEW_UNKNOWN, 247 preference, tile, null /*key */, Preference.DEFAULT_ORDER); 248 249 assertThat(preference.getSummary()) 250 .isEqualTo(RuntimeEnvironment.application.getString(R.string.summary_placeholder)); 251 } 252 253 @Test 254 public void bindPreference_hasSummary_shouldSetSummary() { 255 final Preference preference = new Preference(RuntimeEnvironment.application); 256 final Tile tile = new Tile(); 257 tile.summary = "test"; 258 tile.intent = new Intent(); 259 tile.intent.setComponent(new ComponentName("pkg", "class")); 260 mImpl.bindPreferenceToTile(mActivity, MetricsProto.MetricsEvent.VIEW_UNKNOWN, 261 preference, tile, null /*key */, Preference.DEFAULT_ORDER); 262 263 assertThat(preference.getSummary()).isEqualTo(tile.summary); 264 } 265 266 @Test 267 @Config(shadows = {ShadowTileUtils.class, ShadowThreadUtils.class}) 268 public void bindPreference_hasSummaryUri_shouldLoadSummaryFromContentProvider() { 269 final Preference preference = new Preference(RuntimeEnvironment.application); 270 final Tile tile = new Tile(); 271 tile.intent = new Intent(); 272 tile.intent.setComponent(new ComponentName("pkg", "class")); 273 tile.metaData = new Bundle(); 274 tile.metaData.putString(TileUtils.META_DATA_PREFERENCE_SUMMARY_URI, 275 "content://com.android.settings/tile_summary"); 276 277 mImpl.bindPreferenceToTile(mActivity, MetricsProto.MetricsEvent.VIEW_UNKNOWN, 278 preference, tile, null /*key */, Preference.DEFAULT_ORDER); 279 280 assertThat(preference.getSummary()).isEqualTo(ShadowTileUtils.MOCK_SUMMARY); 281 } 282 283 @Test 284 public void bindPreference_withNullKeyTileKey_shouldUseTileKey() { 285 final Preference preference = new Preference(RuntimeEnvironment.application); 286 final Tile tile = new Tile(); 287 tile.key = "key"; 288 tile.intent = new Intent(); 289 tile.intent.setComponent(new ComponentName("pkg", "class")); 290 mImpl.bindPreferenceToTile(mActivity, MetricsProto.MetricsEvent.VIEW_UNKNOWN, 291 preference, tile, null /* key */, Preference.DEFAULT_ORDER); 292 293 assertThat(preference.getKey()).isEqualTo(tile.key); 294 } 295 296 @Test 297 @Config(shadows = {ShadowTileUtils.class, ShadowThreadUtils.class}) 298 public void bindPreference_withIconUri_shouldLoadIconFromContentProvider() { 299 final Preference preference = new Preference(RuntimeEnvironment.application); 300 final Tile tile = new Tile(); 301 tile.key = "key"; 302 tile.intent = new Intent(); 303 tile.intent.setComponent( 304 new ComponentName(RuntimeEnvironment.application.getPackageName(), "class")); 305 tile.metaData = new Bundle(); 306 tile.metaData.putString(TileUtils.META_DATA_PREFERENCE_ICON_URI, 307 "content://com.android.settings/tile_icon"); 308 mImpl.bindIcon(preference, tile); 309 310 assertThat(preference.getIcon()).isNotNull(); 311 } 312 313 @Test 314 public void bindPreference_withBaseOrder_shouldOffsetPriority() { 315 final int baseOrder = 100; 316 final Preference preference = new Preference(RuntimeEnvironment.application); 317 final Tile tile = new Tile(); 318 tile.metaData = new Bundle(); 319 tile.priority = 10; 320 mImpl.bindPreferenceToTile(mActivity, MetricsProto.MetricsEvent.VIEW_UNKNOWN, 321 preference, tile, "123", baseOrder); 322 323 assertThat(preference.getOrder()).isEqualTo(-tile.priority + baseOrder); 324 } 325 326 @Test 327 public void bindPreference_withOrderMetadata_shouldUseOrderInMetadata() { 328 final Preference preference = new Preference(RuntimeEnvironment.application); 329 final int testOrder = -30; 330 final Tile tile = new Tile(); 331 tile.metaData = new Bundle(); 332 tile.metaData.putInt(mImpl.META_DATA_KEY_ORDER, testOrder); 333 tile.priority = 10; 334 mImpl.bindPreferenceToTile(mActivity, MetricsProto.MetricsEvent.VIEW_UNKNOWN, 335 preference, tile, "123", Preference.DEFAULT_ORDER); 336 337 assertThat(preference.getOrder()).isEqualTo(testOrder); 338 } 339 340 @Test 341 public void bindPreference_invalidOrderMetadata_shouldIgnore() { 342 final Preference preference = new Preference(RuntimeEnvironment.application); 343 final Tile tile = new Tile(); 344 tile.metaData = new Bundle(); 345 tile.metaData.putString(mImpl.META_DATA_KEY_ORDER, "hello"); 346 tile.priority = 10; 347 mImpl.bindPreferenceToTile(mActivity, MetricsProto.MetricsEvent.VIEW_UNKNOWN, 348 preference, tile, "123", Preference.DEFAULT_ORDER); 349 350 assertThat(preference.getOrder()).isEqualTo(-tile.priority); 351 } 352 353 @Test 354 public void bindPreference_withIntentActionMetadata_shouldSetLaunchAction() { 355 Activity activity = Robolectric.buildActivity(Activity.class).get(); 356 final Preference preference = new Preference(RuntimeEnvironment.application); 357 final Tile tile = new Tile(); 358 tile.key = "key"; 359 tile.intent = new Intent(); 360 tile.intent.setComponent(new ComponentName("pkg", "class")); 361 tile.metaData = new Bundle(); 362 tile.metaData.putString("com.android.settings.intent.action", "TestAction"); 363 tile.userHandle = null; 364 mImpl.bindPreferenceToTile(activity, MetricsProto.MetricsEvent.SETTINGS_GESTURES, 365 preference, tile, "123", Preference.DEFAULT_ORDER); 366 preference.performClick(); 367 ShadowActivity shadowActivity = shadowOf(activity); 368 369 final Intent launchIntent = shadowActivity.getNextStartedActivityForResult().intent; 370 assertThat(launchIntent.getAction()) 371 .isEqualTo("TestAction"); 372 assertThat(launchIntent.getIntExtra(VisibilityLoggerMixin.EXTRA_SOURCE_METRICS_CATEGORY, 0)) 373 .isEqualTo(MetricsProto.MetricsEvent.SETTINGS_GESTURES); 374 } 375 376 @Test 377 public void clickPreference_withUnresolvableIntent_shouldNotLaunchAnything() { 378 ReflectionHelpers.setField( 379 mImpl, "mPackageManager", RuntimeEnvironment.application.getPackageManager()); 380 Activity activity = Robolectric.buildActivity(Activity.class).get(); 381 final ShadowApplication application = ShadowApplication.getInstance(); 382 final Preference preference = new Preference(application.getApplicationContext()); 383 final Tile tile = new Tile(); 384 tile.key = "key"; 385 tile.intent = new Intent(); 386 tile.intent.setComponent(new ComponentName("pkg", "class")); 387 tile.metaData = new Bundle(); 388 tile.metaData.putString("com.android.settings.intent.action", "TestAction"); 389 tile.userHandle = null; 390 391 mImpl.bindPreferenceToTile(activity, MetricsProto.MetricsEvent.SETTINGS_GESTURES, 392 preference, tile, "123", Preference.DEFAULT_ORDER); 393 preference.performClick(); 394 395 final ShadowActivity.IntentForResult launchIntent = 396 shadowOf(activity).getNextStartedActivityForResult(); 397 398 assertThat(launchIntent).isNull(); 399 } 400 401 @Test 402 public void getPreferences_noCategory_shouldReturnNull() { 403 mImpl = new DashboardFeatureProviderImpl(mActivity); 404 ReflectionHelpers.setField(mImpl, "mCategoryManager", mCategoryManager); 405 when(mCategoryManager.getTilesByCategory(mActivity, CategoryKey.CATEGORY_HOMEPAGE)) 406 .thenReturn(null); 407 408 assertThat(mImpl.getPreferencesForCategory(null, null, 409 MetricsProto.MetricsEvent.SETTINGS_GESTURES, CategoryKey.CATEGORY_HOMEPAGE)) 410 .isNull(); 411 } 412 413 @Test 414 public void getPreferences_noTileForCategory_shouldReturnNull() { 415 mImpl = new DashboardFeatureProviderImpl(mActivity); 416 ReflectionHelpers.setField(mImpl, "mCategoryManager", mCategoryManager); 417 when(mCategoryManager.getTilesByCategory(mActivity, CategoryKey.CATEGORY_HOMEPAGE)) 418 .thenReturn(new DashboardCategory()); 419 420 assertThat(mImpl.getPreferencesForCategory(null, null, 421 MetricsProto.MetricsEvent.SETTINGS_GESTURES, CategoryKey.CATEGORY_HOMEPAGE)) 422 .isNull(); 423 } 424 425 @Test 426 public void getPreferences_hasTileForCategory_shouldReturnPrefList() { 427 mImpl = new DashboardFeatureProviderImpl(mActivity); 428 ReflectionHelpers.setField(mImpl, "mCategoryManager", mCategoryManager); 429 final DashboardCategory category = new DashboardCategory(); 430 category.addTile(new Tile()); 431 when(mCategoryManager 432 .getTilesByCategory(any(Context.class), eq(CategoryKey.CATEGORY_HOMEPAGE))) 433 .thenReturn(category); 434 435 assertThat(mImpl.getPreferencesForCategory(mActivity, 436 ShadowApplication.getInstance().getApplicationContext(), 437 MetricsProto.MetricsEvent.SETTINGS_GESTURES, 438 CategoryKey.CATEGORY_HOMEPAGE).isEmpty()) 439 .isFalse(); 440 } 441 442 @Test 443 public void testGetExtraIntentAction_shouldReturnNull() { 444 assertThat(mImpl.getExtraIntentAction()).isNull(); 445 } 446 447 @Test 448 public void testShouldTintIcon_enabledInResources_shouldBeTrue() { 449 assertThat(mImpl.shouldTintIcon()).isTrue(); 450 } 451 452 @Test 453 @Config(qualifiers = "mcc999") 454 public void testShouldTintIcon_disabledInResources_shouldBeFalse() { 455 assertThat(mImpl.shouldTintIcon()).isFalse(); 456 } 457 } 458