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 android.content.Intent.EXTRA_USER;
20 
21 import static com.android.settingslib.drawer.SwitchesProvider.EXTRA_SWITCH_SET_CHECKED_ERROR;
22 import static com.android.settingslib.drawer.TileUtils.META_DATA_KEY_ORDER;
23 import static com.android.settingslib.drawer.TileUtils.META_DATA_KEY_PROFILE;
24 import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_KEYHINT;
25 import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_SUMMARY;
26 import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_SWITCH_URI;
27 import static com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_TITLE;
28 import static com.android.settingslib.drawer.TileUtils.PROFILE_ALL;
29 import static com.android.settingslib.drawer.TileUtils.PROFILE_PRIMARY;
30 
31 import static com.google.common.truth.Truth.assertThat;
32 
33 import static org.mockito.ArgumentMatchers.any;
34 import static org.mockito.ArgumentMatchers.anyInt;
35 import static org.mockito.ArgumentMatchers.eq;
36 import static org.mockito.Mockito.doReturn;
37 import static org.mockito.Mockito.mock;
38 import static org.mockito.Mockito.never;
39 import static org.mockito.Mockito.spy;
40 import static org.mockito.Mockito.verify;
41 import static org.mockito.Mockito.verifyZeroInteractions;
42 import static org.mockito.Mockito.when;
43 
44 import android.content.Context;
45 import android.content.Intent;
46 import android.content.pm.ActivityInfo;
47 import android.content.pm.PackageManager;
48 import android.content.pm.ProviderInfo;
49 import android.content.pm.ResolveInfo;
50 import android.graphics.Bitmap;
51 import android.graphics.drawable.Icon;
52 import android.os.Bundle;
53 import android.os.UserHandle;
54 import android.os.UserManager;
55 
56 import androidx.fragment.app.FragmentActivity;
57 import androidx.preference.Preference;
58 import androidx.preference.SwitchPreference;
59 
60 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
61 import com.android.settings.R;
62 import com.android.settings.SettingsActivity;
63 import com.android.settings.testutils.FakeFeatureFactory;
64 import com.android.settings.testutils.shadow.ShadowTileUtils;
65 import com.android.settings.testutils.shadow.ShadowUserManager;
66 import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
67 import com.android.settingslib.drawer.ActivityTile;
68 import com.android.settingslib.drawer.CategoryKey;
69 import com.android.settingslib.drawer.ProviderTile;
70 import com.android.settingslib.drawer.Tile;
71 import com.android.settingslib.drawer.TileUtils;
72 
73 import org.junit.Before;
74 import org.junit.Test;
75 import org.junit.runner.RunWith;
76 import org.mockito.Answers;
77 import org.mockito.ArgumentCaptor;
78 import org.mockito.Mock;
79 import org.mockito.MockitoAnnotations;
80 import org.robolectric.Robolectric;
81 import org.robolectric.RobolectricTestRunner;
82 import org.robolectric.RuntimeEnvironment;
83 import org.robolectric.Shadows;
84 import org.robolectric.annotation.Config;
85 import org.robolectric.shadows.ShadowActivity;
86 import org.robolectric.util.ReflectionHelpers;
87 
88 import java.util.ArrayList;
89 import java.util.List;
90 
91 @RunWith(RobolectricTestRunner.class)
92 @Config(shadows = ShadowUserManager.class)
93 public class DashboardFeatureProviderImplTest {
94 
95     private static final String KEY = "key";
96     private static final String SWITCH_URI = "content://com.android.settings/tile_switch";
97 
98     @Mock(answer = Answers.RETURNS_DEEP_STUBS)
99     private FragmentActivity mActivity;
100     @Mock(answer = Answers.RETURNS_DEEP_STUBS)
101     private UserManager mUserManager;
102     @Mock
103     private PackageManager mPackageManager;
104     private FakeFeatureFactory mFeatureFactory;
105 
106     private Context mContext;
107     private ActivityInfo mActivityInfo;
108     private ProviderInfo mProviderInfo;
109     private Bundle mSwitchMetaData;
110     private DashboardFeatureProviderImpl mImpl;
111     private boolean mForceRoundedIcon;
112 
113     @Before
setUp()114     public void setUp() {
115         MockitoAnnotations.initMocks(this);
116         mContext = spy(RuntimeEnvironment.application);
117         doReturn(RuntimeEnvironment.application).when(mActivity).getApplicationContext();
118         mForceRoundedIcon = false;
119         mActivityInfo = new ActivityInfo();
120         mActivityInfo.packageName = mContext.getPackageName();
121         mActivityInfo.name = "class";
122         mActivityInfo.metaData = new Bundle();
123         mActivityInfo.metaData.putInt(META_DATA_PREFERENCE_TITLE, R.string.settings_label);
124         mActivityInfo.metaData.putInt(META_DATA_PREFERENCE_SUMMARY,
125                 R.string.about_settings_summary);
126 
127         mProviderInfo = new ProviderInfo();
128         mProviderInfo.packageName = mContext.getPackageName();
129         mProviderInfo.name = "provider";
130         mProviderInfo.authority = "com.android.settings";
131         mSwitchMetaData = new Bundle();
132         mSwitchMetaData.putInt(META_DATA_PREFERENCE_TITLE, R.string.settings_label);
133         mSwitchMetaData.putInt(META_DATA_PREFERENCE_SUMMARY, R.string.about_settings_summary);
134         mSwitchMetaData.putString(META_DATA_PREFERENCE_KEYHINT, KEY);
135         mSwitchMetaData.putString(META_DATA_PREFERENCE_SWITCH_URI, SWITCH_URI);
136 
137         doReturn(mPackageManager).when(mContext).getPackageManager();
138         when(mPackageManager.resolveActivity(any(Intent.class), anyInt()))
139                 .thenReturn(new ResolveInfo());
140         mFeatureFactory = FakeFeatureFactory.setupForTest();
141         mImpl = new DashboardFeatureProviderImpl(mContext);
142     }
143 
144     @Test
shouldHoldAppContext()145     public void shouldHoldAppContext() {
146         assertThat(mImpl.mContext).isEqualTo(mContext.getApplicationContext());
147     }
148 
149     @Test
bindPreference_shouldBindAllData()150     public void bindPreference_shouldBindAllData() {
151         final Preference preference = new Preference(RuntimeEnvironment.application);
152         final Tile tile = spy(new ActivityTile(mActivityInfo, CategoryKey.CATEGORY_HOMEPAGE));
153         mActivityInfo.metaData.putInt(META_DATA_KEY_ORDER, 10);
154         doReturn(Icon.createWithBitmap(Bitmap.createBitmap(1, 1, Bitmap.Config.RGB_565)))
155                 .when(tile).getIcon(any(Context.class));
156         mActivityInfo.metaData.putString(SettingsActivity.META_DATA_KEY_FRAGMENT_CLASS, "HI");
157         mImpl.bindPreferenceToTileAndGetObservers(mActivity, mForceRoundedIcon,
158                 MetricsEvent.SETTINGS_GESTURES, preference, tile, "123", Preference.DEFAULT_ORDER);
159 
160         assertThat(preference.getTitle()).isEqualTo(mContext.getText(R.string.settings_label));
161         assertThat(preference.getSummary())
162                 .isEqualTo(mContext.getText(R.string.about_settings_summary));
163         assertThat(preference.getIcon()).isNotNull();
164         assertThat(preference.getFragment()).isEqualTo(
165                 mActivityInfo.metaData.getString(SettingsActivity.META_DATA_KEY_FRAGMENT_CLASS));
166         assertThat(preference.getOrder()).isEqualTo(tile.getOrder());
167     }
168 
169     @Test
bindPreference_shouldBindAllSwitchData()170     public void bindPreference_shouldBindAllSwitchData() {
171         final Preference preference = new SwitchPreference(RuntimeEnvironment.application);
172         final Tile tile = spy(new ProviderTile(mProviderInfo, CategoryKey.CATEGORY_HOMEPAGE,
173                 mSwitchMetaData));
174         mSwitchMetaData.putInt(META_DATA_KEY_ORDER, 10);
175         doReturn(Icon.createWithBitmap(Bitmap.createBitmap(1, 1, Bitmap.Config.RGB_565)))
176                 .when(tile).getIcon(any(Context.class));
177         final List<DynamicDataObserver> observers = mImpl.bindPreferenceToTileAndGetObservers(
178                 mActivity, mForceRoundedIcon, MetricsEvent.SETTINGS_GESTURES, preference, tile,
179                 null /* key*/, Preference.DEFAULT_ORDER);
180 
181         assertThat(preference.getTitle()).isEqualTo(mContext.getText(R.string.settings_label));
182         assertThat(preference.getSummary())
183                 .isEqualTo(mContext.getText(R.string.about_settings_summary));
184         assertThat(preference.getKey()).isEqualTo(KEY);
185         assertThat(preference.getIcon()).isNotNull();
186         assertThat(preference.getOrder()).isEqualTo(tile.getOrder());
187         assertThat(observers.get(0).getUri().toString()).isEqualTo(SWITCH_URI);
188     }
189 
190     @Test
bindPreference_noFragmentMetadata_shouldBindIntent()191     public void bindPreference_noFragmentMetadata_shouldBindIntent() {
192         final Preference preference = new Preference(RuntimeEnvironment.application);
193         mActivityInfo.metaData.putInt(META_DATA_KEY_ORDER, 10);
194         final Tile tile = new ActivityTile(mActivityInfo, CategoryKey.CATEGORY_HOMEPAGE);
195 
196         mImpl.bindPreferenceToTileAndGetObservers(mActivity, mForceRoundedIcon,
197                 MetricsEvent.SETTINGS_GESTURES, preference, tile, "123", Preference.DEFAULT_ORDER);
198 
199         assertThat(preference.getFragment()).isNull();
200         assertThat(preference.getOnPreferenceClickListener()).isNotNull();
201         assertThat(preference.getOrder()).isEqualTo(tile.getOrder());
202     }
203 
204     @Test
bindPreference_noFragmentMetadata_shouldBindToProfileSelector()205     public void bindPreference_noFragmentMetadata_shouldBindToProfileSelector() {
206         final Preference preference = new Preference(RuntimeEnvironment.application);
207         final Tile tile = new ActivityTile(mActivityInfo, CategoryKey.CATEGORY_HOMEPAGE);
208         tile.userHandle = new ArrayList<>();
209         tile.userHandle.add(mock(UserHandle.class));
210         tile.userHandle.add(mock(UserHandle.class));
211 
212         mImpl.bindPreferenceToTileAndGetObservers(mActivity, mForceRoundedIcon,
213                 MetricsEvent.SETTINGS_GESTURES, preference, tile, "123", Preference.DEFAULT_ORDER);
214         preference.getOnPreferenceClickListener().onPreferenceClick(null);
215 
216         verify(mActivity).getSupportFragmentManager();
217     }
218 
219     @Test
bindPreference_noFragmentMetadataSingleUser_shouldBindToDirectLaunchIntent()220     public void bindPreference_noFragmentMetadataSingleUser_shouldBindToDirectLaunchIntent() {
221         final Preference preference = new Preference(RuntimeEnvironment.application);
222         final Tile tile = new ActivityTile(mActivityInfo, CategoryKey.CATEGORY_HOMEPAGE);
223         tile.userHandle = new ArrayList<>();
224         tile.userHandle.add(mock(UserHandle.class));
225 
226         when(mActivity.getSystemService(Context.USER_SERVICE))
227                 .thenReturn(mUserManager);
228 
229         mImpl.bindPreferenceToTileAndGetObservers(mActivity, mForceRoundedIcon,
230                 MetricsEvent.SETTINGS_GESTURES, preference, tile, "123", Preference.DEFAULT_ORDER);
231         preference.getOnPreferenceClickListener().onPreferenceClick(null);
232 
233         verify(mFeatureFactory.metricsFeatureProvider).logStartedIntent(
234                 any(Intent.class),
235                 eq(MetricsEvent.SETTINGS_GESTURES));
236         verify(mActivity)
237                 .startActivityForResultAsUser(any(Intent.class), anyInt(), any(UserHandle.class));
238     }
239 
240     @Test
bindPreference_toInternalSettingActivity_shouldBindToDirectLaunchIntentAndNotLog()241     public void bindPreference_toInternalSettingActivity_shouldBindToDirectLaunchIntentAndNotLog() {
242         final Preference preference = new Preference(RuntimeEnvironment.application);
243         mActivityInfo.packageName = RuntimeEnvironment.application.getPackageName();
244         final Tile tile = new ActivityTile(mActivityInfo, CategoryKey.CATEGORY_HOMEPAGE);
245         tile.userHandle = new ArrayList<>();
246         tile.userHandle.add(mock(UserHandle.class));
247 
248         mImpl.bindPreferenceToTileAndGetObservers(mActivity, mForceRoundedIcon,
249                 MetricsEvent.SETTINGS_GESTURES, preference, tile, "123", Preference.DEFAULT_ORDER);
250         preference.getOnPreferenceClickListener().onPreferenceClick(null);
251         verify(mFeatureFactory.metricsFeatureProvider).logStartedIntent(
252                 any(Intent.class),
253                 anyInt());
254         verify(mActivity)
255                 .startActivityForResultAsUser(any(Intent.class), anyInt(), any(UserHandle.class));
256     }
257 
258     @Test
bindPreference_nullPreference_shouldIgnore()259     public void bindPreference_nullPreference_shouldIgnore() {
260         final Tile tile = mock(Tile.class);
261         mImpl.bindPreferenceToTileAndGetObservers(mActivity, mForceRoundedIcon,
262                 MetricsEvent.VIEW_UNKNOWN, null, tile, "123", Preference.DEFAULT_ORDER);
263 
264         verifyZeroInteractions(tile);
265     }
266 
267     @Test
bindPreference_withNullKeyNullPriority_shouldGenerateKeyAndPriority()268     public void bindPreference_withNullKeyNullPriority_shouldGenerateKeyAndPriority() {
269         final Preference preference = new Preference(RuntimeEnvironment.application);
270         final Tile tile = new ActivityTile(mActivityInfo, CategoryKey.CATEGORY_HOMEPAGE);
271         mImpl.bindPreferenceToTileAndGetObservers(mActivity, mForceRoundedIcon,
272                 MetricsEvent.VIEW_UNKNOWN, preference, tile, null /*key */,
273                 Preference.DEFAULT_ORDER);
274 
275         assertThat(preference.getKey()).isNotNull();
276         assertThat(preference.getOrder()).isEqualTo(Preference.DEFAULT_ORDER);
277     }
278 
279     @Test
bindPreference_noSummary_shouldSetSummaryToPlaceholder()280     public void bindPreference_noSummary_shouldSetSummaryToPlaceholder() {
281         final Preference preference = new Preference(RuntimeEnvironment.application);
282         mActivityInfo.metaData.remove(META_DATA_PREFERENCE_SUMMARY);
283 
284         final Tile tile = new ActivityTile(mActivityInfo, CategoryKey.CATEGORY_HOMEPAGE);
285 
286         mImpl.bindPreferenceToTileAndGetObservers(mActivity, mForceRoundedIcon,
287                 MetricsEvent.VIEW_UNKNOWN, preference, tile, null /*key */,
288                 Preference.DEFAULT_ORDER);
289 
290         assertThat(preference.getSummary())
291                 .isEqualTo(RuntimeEnvironment.application.getString(R.string.summary_placeholder));
292     }
293 
294     @Test
295     @Config(shadows = {ShadowTileUtils.class})
bindPreference_hasSummaryUri_shouldLoadSummaryFromContentProviderAndHaveObserver()296     public void bindPreference_hasSummaryUri_shouldLoadSummaryFromContentProviderAndHaveObserver() {
297         final Preference preference = new Preference(RuntimeEnvironment.application);
298         final Tile tile = new ActivityTile(mActivityInfo, CategoryKey.CATEGORY_HOMEPAGE);
299         final String uriString = "content://com.android.settings/tile_summary";
300         mActivityInfo.metaData.putString(TileUtils.META_DATA_PREFERENCE_SUMMARY_URI, uriString);
301 
302         final List<DynamicDataObserver> observers = mImpl.bindPreferenceToTileAndGetObservers(
303                 mActivity, mForceRoundedIcon, MetricsEvent.VIEW_UNKNOWN, preference, tile,
304                 null /*key */, Preference.DEFAULT_ORDER);
305 
306         assertThat(preference.getSummary()).isEqualTo(ShadowTileUtils.MOCK_SUMMARY);
307         assertThat(observers.get(0).getUri().toString()).isEqualTo(uriString);
308     }
309 
310     @Test
311     @Config(shadows = {ShadowTileUtils.class})
bindPreference_hasTitleUri_shouldLoadFromContentProviderAndHaveObserver()312     public void bindPreference_hasTitleUri_shouldLoadFromContentProviderAndHaveObserver() {
313         final Preference preference = new Preference(RuntimeEnvironment.application);
314         final Tile tile = new ActivityTile(mActivityInfo, CategoryKey.CATEGORY_HOMEPAGE);
315         final String uriString =  "content://com.android.settings/tile_title";
316         mActivityInfo.metaData.putString(TileUtils.META_DATA_PREFERENCE_TITLE_URI, uriString);
317 
318         final List<DynamicDataObserver> observers = mImpl.bindPreferenceToTileAndGetObservers(
319                 mActivity, mForceRoundedIcon, MetricsEvent.VIEW_UNKNOWN, preference, tile,
320                 null /*key */, Preference.DEFAULT_ORDER);
321 
322         assertThat(preference.getTitle()).isEqualTo(ShadowTileUtils.MOCK_SUMMARY);
323         assertThat(observers.get(0).getUri().toString()).isEqualTo(uriString);
324     }
325 
326     @Test
327     @Config(shadows = {ShadowTileUtils.class})
bindPreference_onCheckedChanged_shouldPutStateToContentProvider()328     public void bindPreference_onCheckedChanged_shouldPutStateToContentProvider() {
329         final SwitchPreference preference = new SwitchPreference(RuntimeEnvironment.application);
330         final Tile tile = new ProviderTile(mProviderInfo, CategoryKey.CATEGORY_HOMEPAGE,
331                 mSwitchMetaData);
332         final Bundle bundle = new Bundle();
333         bundle.putBoolean(EXTRA_SWITCH_SET_CHECKED_ERROR, false);
334         ShadowTileUtils.setResultBundle(bundle);
335         mImpl.bindPreferenceToTileAndGetObservers(mActivity, mForceRoundedIcon,
336                 MetricsEvent.VIEW_UNKNOWN, preference, tile, null /*key */,
337                 Preference.DEFAULT_ORDER);
338 
339         preference.callChangeListener(false);
340 
341         assertThat(ShadowTileUtils.getProviderChecked()).isFalse();
342 
343         preference.callChangeListener(true);
344 
345         assertThat(ShadowTileUtils.getProviderChecked()).isTrue();
346     }
347 
348     @Test
349     @Config(shadows = {ShadowTileUtils.class})
bindPreference_onCheckedChangedError_shouldRevertCheckedState()350     public void bindPreference_onCheckedChangedError_shouldRevertCheckedState() {
351         final SwitchPreference preference = new SwitchPreference(RuntimeEnvironment.application);
352         final Tile tile = new ProviderTile(mProviderInfo, CategoryKey.CATEGORY_HOMEPAGE,
353                 mSwitchMetaData);
354         final Bundle bundle = new Bundle();
355         bundle.putBoolean(EXTRA_SWITCH_SET_CHECKED_ERROR, true);
356         ShadowTileUtils.setResultBundle(bundle);
357         mImpl.bindPreferenceToTileAndGetObservers(mActivity, mForceRoundedIcon,
358                 MetricsEvent.VIEW_UNKNOWN, preference, tile, null /*key */,
359                 Preference.DEFAULT_ORDER);
360 
361         preference.callChangeListener(true);
362 
363         assertThat(preference.isChecked()).isFalse();
364 
365         preference.callChangeListener(false);
366 
367         assertThat(preference.isChecked()).isTrue();
368     }
369 
370     @Test
371     @Config(shadows = {ShadowTileUtils.class})
bindPreference_callbackOnChanged_shouldLoadFromContentProvider()372     public void bindPreference_callbackOnChanged_shouldLoadFromContentProvider() {
373         final SwitchPreference preference = new SwitchPreference(RuntimeEnvironment.application);
374         final Tile tile = new ProviderTile(mProviderInfo, CategoryKey.CATEGORY_HOMEPAGE,
375                 mSwitchMetaData);
376         final List<DynamicDataObserver> observers = mImpl.bindPreferenceToTileAndGetObservers(
377                 mActivity, mForceRoundedIcon, MetricsEvent.VIEW_UNKNOWN, preference, tile,
378                 null /*key */, Preference.DEFAULT_ORDER);
379 
380         ShadowTileUtils.setProviderChecked(false);
381         observers.get(0).onDataChanged();
382 
383         assertThat(preference.isChecked()).isFalse();
384 
385         ShadowTileUtils.setProviderChecked(true);
386         observers.get(0).onDataChanged();
387 
388         assertThat(preference.isChecked()).isTrue();
389     }
390 
391     @Test
bindPreference_withNullKeyTileKey_shouldUseTileKey()392     public void bindPreference_withNullKeyTileKey_shouldUseTileKey() {
393         final Preference preference = new Preference(RuntimeEnvironment.application);
394         mActivityInfo.metaData.putString(META_DATA_PREFERENCE_KEYHINT, "key");
395         final Tile tile = new ActivityTile(mActivityInfo, CategoryKey.CATEGORY_HOMEPAGE);
396         mImpl.bindPreferenceToTileAndGetObservers(mActivity, mForceRoundedIcon,
397                 MetricsEvent.VIEW_UNKNOWN, preference, tile, null /* key */,
398                 Preference.DEFAULT_ORDER);
399 
400         assertThat(preference.getKey()).isEqualTo(tile.getKey(mContext));
401     }
402 
403     @Test
404     @Config(shadows = {ShadowTileUtils.class})
bindPreference_withIconUri_shouldLoadIconFromContentProvider()405     public void bindPreference_withIconUri_shouldLoadIconFromContentProvider() {
406         final Preference preference = new Preference(RuntimeEnvironment.application);
407         mActivityInfo.packageName = RuntimeEnvironment.application.getPackageName();
408         final Tile tile = new ActivityTile(mActivityInfo, CategoryKey.CATEGORY_HOMEPAGE);
409         mActivityInfo.metaData.putString(META_DATA_PREFERENCE_KEYHINT, "key");
410         mActivityInfo.metaData.putString(TileUtils.META_DATA_PREFERENCE_ICON_URI,
411                 "content://com.android.settings/tile_icon");
412         mImpl.bindIcon(preference, tile, false /* forceRoundedIcon */);
413 
414         assertThat(preference.getIcon()).isNotNull();
415     }
416 
417     @Test
bindPreference_withBaseOrder_shouldOffsetOrder()418     public void bindPreference_withBaseOrder_shouldOffsetOrder() {
419         final int baseOrder = 100;
420         final Preference preference = new Preference(RuntimeEnvironment.application);
421         mActivityInfo.metaData.putInt(META_DATA_KEY_ORDER, 10);
422         final Tile tile = new ActivityTile(mActivityInfo, CategoryKey.CATEGORY_HOMEPAGE);
423 
424         mImpl.bindPreferenceToTileAndGetObservers(mActivity, mForceRoundedIcon,
425                 MetricsEvent.VIEW_UNKNOWN, preference, tile, "123", baseOrder);
426 
427         assertThat(preference.getOrder()).isEqualTo(tile.getOrder() + baseOrder);
428     }
429 
430     @Test
bindPreference_withOrderMetadata_shouldUseOrderInMetadata()431     public void bindPreference_withOrderMetadata_shouldUseOrderInMetadata() {
432         final Preference preference = new Preference(RuntimeEnvironment.application);
433         final int testOrder = -30;
434         mActivityInfo.metaData.putInt(META_DATA_KEY_ORDER, 10);
435         final Tile tile = new ActivityTile(mActivityInfo, CategoryKey.CATEGORY_HOMEPAGE);
436         mActivityInfo.metaData.putInt(META_DATA_KEY_ORDER, testOrder);
437         mImpl.bindPreferenceToTileAndGetObservers(mActivity, mForceRoundedIcon,
438                 MetricsEvent.VIEW_UNKNOWN, preference, tile, "123", Preference.DEFAULT_ORDER);
439 
440         assertThat(preference.getOrder()).isEqualTo(testOrder);
441     }
442 
443     @Test
bindPreference_invalidOrderMetadata_shouldIgnore()444     public void bindPreference_invalidOrderMetadata_shouldIgnore() {
445         final Preference preference = new Preference(RuntimeEnvironment.application);
446         final Tile tile = new ActivityTile(mActivityInfo, CategoryKey.CATEGORY_HOMEPAGE);
447         mActivityInfo.metaData.putString(META_DATA_KEY_ORDER, "hello");
448 
449         mImpl.bindPreferenceToTileAndGetObservers(mActivity, mForceRoundedIcon,
450                 MetricsEvent.VIEW_UNKNOWN, preference, tile, "123", Preference.DEFAULT_ORDER);
451 
452         assertThat(preference.getOrder()).isEqualTo(Preference.DEFAULT_ORDER);
453     }
454 
455     @Test
bindPreference_withIntentActionMetadata_shouldSetLaunchAction()456     public void bindPreference_withIntentActionMetadata_shouldSetLaunchAction() {
457         FragmentActivity activity = Robolectric.buildActivity(FragmentActivity.class).get();
458         final Preference preference = new Preference(RuntimeEnvironment.application);
459         final Tile tile = new ActivityTile(mActivityInfo, CategoryKey.CATEGORY_HOMEPAGE);
460         mActivityInfo.metaData.putString(META_DATA_PREFERENCE_KEYHINT, "key");
461         mActivityInfo.metaData.putString("com.android.settings.intent.action", "TestAction");
462         tile.userHandle = null;
463         mImpl.bindPreferenceToTileAndGetObservers(activity, mForceRoundedIcon,
464                 MetricsEvent.SETTINGS_GESTURES, preference, tile, "123", Preference.DEFAULT_ORDER);
465         preference.performClick();
466         ShadowActivity shadowActivity = Shadows.shadowOf(activity);
467 
468         final Intent launchIntent = shadowActivity.getNextStartedActivityForResult().intent;
469         assertThat(launchIntent.getAction())
470                 .isEqualTo("TestAction");
471         assertThat(
472                 launchIntent.getIntExtra(MetricsFeatureProvider.EXTRA_SOURCE_METRICS_CATEGORY, 0))
473                 .isEqualTo(MetricsEvent.SETTINGS_GESTURES);
474     }
475 
476     @Test
clickPreference_withUnresolvableIntent_shouldNotLaunchAnything()477     public void clickPreference_withUnresolvableIntent_shouldNotLaunchAnything() {
478         ReflectionHelpers.setField(
479                 mImpl, "mPackageManager", RuntimeEnvironment.application.getPackageManager());
480         FragmentActivity activity = Robolectric.buildActivity(FragmentActivity.class).get();
481         final Preference preference = new Preference(RuntimeEnvironment.application);
482         final Tile tile = new ActivityTile(mActivityInfo, CategoryKey.CATEGORY_HOMEPAGE);
483         mActivityInfo.metaData.putString(META_DATA_PREFERENCE_KEYHINT, "key");
484         mActivityInfo.metaData.putString("com.android.settings.intent.action", "TestAction");
485         tile.userHandle = null;
486 
487         mImpl.bindPreferenceToTileAndGetObservers(activity, mForceRoundedIcon,
488                 MetricsEvent.SETTINGS_GESTURES, preference, tile, "123", Preference.DEFAULT_ORDER);
489         preference.performClick();
490 
491         final ShadowActivity.IntentForResult launchIntent =
492                 Shadows.shadowOf(activity).getNextStartedActivityForResult();
493 
494         assertThat(launchIntent).isNull();
495     }
496 
497     @Test
openTileIntent_profileSelectionDialog_shouldShow()498     public void openTileIntent_profileSelectionDialog_shouldShow() {
499         ShadowUserManager.getShadow().addUser(10, "Someone", 0);
500 
501         final Tile tile = new ActivityTile(mActivityInfo, CategoryKey.CATEGORY_HOMEPAGE);
502         final ArrayList<UserHandle> handles = new ArrayList<>();
503         handles.add(new UserHandle(0));
504         handles.add(new UserHandle(10));
505         tile.userHandle = handles;
506         mImpl.openTileIntent(mActivity, tile);
507 
508         verify(mActivity, never())
509                 .startActivityForResult(any(Intent.class), eq(0));
510         verify(mActivity).getSupportFragmentManager();
511     }
512 
513     @Test
openTileIntent_profileSelectionDialog_explicitMetadataShouldShow()514     public void openTileIntent_profileSelectionDialog_explicitMetadataShouldShow() {
515         ShadowUserManager.getShadow().addUser(10, "Someone", 0);
516 
517         mActivityInfo.metaData.putString(META_DATA_KEY_PROFILE, PROFILE_ALL);
518         final Tile tile = new ActivityTile(mActivityInfo, CategoryKey.CATEGORY_HOMEPAGE);
519         final ArrayList<UserHandle> handles = new ArrayList<>();
520         handles.add(new UserHandle(0));
521         handles.add(new UserHandle(10));
522         tile.userHandle = handles;
523         mImpl.openTileIntent(mActivity, tile);
524 
525         verify(mActivity, never())
526                 .startActivityForResult(any(Intent.class), eq(0));
527         verify(mActivity).getSupportFragmentManager();
528     }
529 
530     @Test
openTileIntent_profileSelectionDialog_shouldNotShow()531     public void openTileIntent_profileSelectionDialog_shouldNotShow() {
532         ShadowUserManager.getShadow().addUser(10, "Someone", 0);
533 
534         mActivityInfo.metaData.putString(META_DATA_KEY_PROFILE, PROFILE_PRIMARY);
535         final Tile tile = new ActivityTile(mActivityInfo, CategoryKey.CATEGORY_HOMEPAGE);
536         final ArrayList<UserHandle> handles = new ArrayList<>();
537         handles.add(new UserHandle(0));
538         handles.add(new UserHandle(10));
539         tile.userHandle = handles;
540         mImpl.openTileIntent(mActivity, tile);
541 
542         verify(mActivity)
543                 .startActivityForResult(any(Intent.class), eq(0));
544         verify(mActivity, never()).getSupportFragmentManager();
545     }
546 
547     @Test
openTileIntent_profileSelectionDialog_validUserHandleShouldNotShow()548     public void openTileIntent_profileSelectionDialog_validUserHandleShouldNotShow() {
549         final int userId = 10;
550         ShadowUserManager.getShadow().addUser(userId, "Someone", 0);
551 
552         final UserHandle userHandle = new UserHandle(userId);
553         final Tile tile = new ActivityTile(mActivityInfo, CategoryKey.CATEGORY_HOMEPAGE);
554         tile.getIntent().putExtra(EXTRA_USER, userHandle);
555         final ArrayList<UserHandle> handles = new ArrayList<>();
556         handles.add(new UserHandle(0));
557         handles.add(userHandle);
558         tile.userHandle = handles;
559 
560         mImpl.openTileIntent(mActivity, tile);
561 
562         final ArgumentCaptor<UserHandle> argument = ArgumentCaptor.forClass(UserHandle.class);
563         verify(mActivity)
564                 .startActivityForResultAsUser(any(Intent.class), anyInt(), argument.capture());
565         assertThat(argument.getValue().getIdentifier()).isEqualTo(userId);
566         verify(mActivity, never()).getSupportFragmentManager();
567     }
568 
569     @Test
openTileIntent_profileSelectionDialog_invalidUserHandleShouldShow()570     public void openTileIntent_profileSelectionDialog_invalidUserHandleShouldShow() {
571         ShadowUserManager.getShadow().addUser(10, "Someone", 0);
572 
573         final Tile tile = new ActivityTile(mActivityInfo, CategoryKey.CATEGORY_HOMEPAGE);
574         tile.getIntent().putExtra(EXTRA_USER, new UserHandle(30));
575         final ArrayList<UserHandle> handles = new ArrayList<>();
576         handles.add(new UserHandle(0));
577         handles.add(new UserHandle(10));
578         tile.userHandle = handles;
579 
580         mImpl.openTileIntent(mActivity, tile);
581 
582         verify(mActivity, never())
583                 .startActivityForResultAsUser(any(Intent.class), anyInt(), any(UserHandle.class));
584         verify(mActivity).getSupportFragmentManager();
585     }
586 }
587