OSDN Git Service

bac02d37d869e8c63917c416d923337f19171aa9
[android-x86/packages-apps-Settings.git] / tests / robotests / src / com / android / settings / dashboard / suggestions / SuggestionAdapterTest.java
1 /*
2  * Copyright (C) 2017 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 package com.android.settings.dashboard.suggestions;
17
18 import static com.google.common.truth.Truth.assertThat;
19
20 import static org.mockito.ArgumentMatchers.any;
21 import static org.mockito.ArgumentMatchers.anyInt;
22 import static org.mockito.Mockito.doReturn;
23 import static org.mockito.Mockito.mock;
24 import static org.mockito.Mockito.never;
25 import static org.mockito.Mockito.spy;
26 import static org.mockito.Mockito.verify;
27 import static org.mockito.Mockito.when;
28
29 import android.app.PendingIntent;
30 import android.content.Context;
31 import android.content.res.Resources;
32 import android.content.res.TypedArray;
33 import android.graphics.drawable.Drawable;
34 import android.graphics.drawable.Icon;
35 import android.service.settings.suggestions.Suggestion;
36 import android.view.Display;
37 import android.view.LayoutInflater;
38 import android.view.View;
39 import android.view.WindowManager;
40 import android.widget.FrameLayout;
41 import android.widget.LinearLayout;
42
43 import com.android.internal.logging.nano.MetricsProto;
44 import com.android.settings.R;
45 import com.android.settings.SettingsActivity;
46 import com.android.settings.TestConfig;
47 import com.android.settings.dashboard.DashboardAdapter;
48 import com.android.settings.testutils.FakeFeatureFactory;
49 import com.android.settings.testutils.SettingsRobolectricTestRunner;
50 import com.android.settingslib.suggestions.SuggestionControllerMixin;
51
52 import org.junit.Before;
53 import org.junit.Test;
54 import org.junit.runner.RunWith;
55 import org.mockito.Answers;
56 import org.mockito.Mock;
57 import org.mockito.MockitoAnnotations;
58 import org.robolectric.RuntimeEnvironment;
59 import org.robolectric.annotation.Config;
60 import org.robolectric.util.ReflectionHelpers;
61
62 import java.util.ArrayList;
63 import java.util.List;
64
65 @RunWith(SettingsRobolectricTestRunner.class)
66 @Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
67 public class SuggestionAdapterTest {
68
69     @Mock(answer = Answers.RETURNS_DEEP_STUBS)
70     private SettingsActivity mActivity;
71     @Mock
72     private SuggestionControllerMixin mSuggestionControllerMixin;
73     @Mock
74     private Resources mResources;
75     @Mock
76     private WindowManager mWindowManager;
77
78     private FakeFeatureFactory mFeatureFactory;
79     private Context mContext;
80     private SuggestionAdapter mSuggestionAdapter;
81     private DashboardAdapter.DashboardItemHolder mSuggestionHolder;
82     private List<Suggestion> mOneSuggestion;
83     private List<Suggestion> mTwoSuggestions;
84     private SuggestionAdapter.CardConfig mConfig;
85
86     @Before
87     public void setUp() {
88         MockitoAnnotations.initMocks(this);
89         mContext = spy(RuntimeEnvironment.application);
90         when(mActivity.getSystemService(Context.WINDOW_SERVICE)).thenReturn(mWindowManager);
91         when(mActivity.getResources()).thenReturn(mResources);
92         when(mResources.getDimensionPixelOffset(R.dimen.suggestion_card_inner_margin))
93             .thenReturn(10);
94         when(mResources.getDimensionPixelOffset(R.dimen.suggestion_card_outer_margin))
95             .thenReturn(20);
96         when(mResources.getDimensionPixelOffset(R.dimen.suggestion_card_width_multiple_cards))
97             .thenReturn(120);
98         mConfig = spy(SuggestionAdapter.CardConfig.get(mActivity));
99
100         mFeatureFactory = FakeFeatureFactory.setupForTest();
101
102         final Suggestion suggestion1 = new Suggestion.Builder("id1")
103                 .setTitle("Test suggestion 1")
104                 .build();
105         final Suggestion suggestion2 = new Suggestion.Builder("id2")
106                 .setTitle("Test suggestion 2")
107                 .build();
108         mOneSuggestion = new ArrayList<>();
109         mOneSuggestion.add(suggestion1);
110         mTwoSuggestions = new ArrayList<>();
111         mTwoSuggestions.add(suggestion1);
112         mTwoSuggestions.add(suggestion2);
113     }
114
115     @Test
116     public void getItemCount_shouldReturnListSize() {
117         mSuggestionAdapter = new SuggestionAdapter(mContext, mSuggestionControllerMixin,
118             null /* savedInstanceState */, null /* callback */, null /* lifecycle */);
119         mSuggestionAdapter.setSuggestions(mOneSuggestion);
120         assertThat(mSuggestionAdapter.getItemCount()).isEqualTo(1);
121
122         mSuggestionAdapter.setSuggestions(mTwoSuggestions);
123         assertThat(mSuggestionAdapter.getItemCount()).isEqualTo(2);
124     }
125
126     @Test
127     public void getItemViewType_shouldReturnSuggestionTile() {
128         mSuggestionAdapter = new SuggestionAdapter(mContext, mSuggestionControllerMixin,
129             null /* savedInstanceState */, null /* callback */, null /* lifecycle */);
130         mSuggestionAdapter.setSuggestions(mOneSuggestion);
131         assertThat(mSuggestionAdapter.getItemViewType(0))
132             .isEqualTo(R.layout.suggestion_tile);
133     }
134
135     @Test
136     public void getItemType_hasButton_shouldReturnSuggestionWithButton() {
137         final List<Suggestion> suggestions = new ArrayList<>();
138         suggestions.add(new Suggestion.Builder("id")
139                 .setFlags(Suggestion.FLAG_HAS_BUTTON)
140                 .setTitle("123")
141                 .setSummary("456")
142                 .build());
143         mSuggestionAdapter = new SuggestionAdapter(mContext, mSuggestionControllerMixin,
144             null /* savedInstanceState */, null /* callback */, null /* lifecycle */);
145         mSuggestionAdapter.setSuggestions(suggestions);
146
147         assertThat(mSuggestionAdapter.getItemViewType(0))
148             .isEqualTo(R.layout.suggestion_tile_with_button);
149     }
150
151     @Test
152     public void onBindViewHolder_shouldLog() {
153         final View view = spy(LayoutInflater.from(mContext).inflate(
154             R.layout.suggestion_tile, new LinearLayout(mContext), true));
155         mSuggestionHolder = new DashboardAdapter.DashboardItemHolder(view);
156         mSuggestionAdapter = new SuggestionAdapter(mContext, mSuggestionControllerMixin,
157             null /* savedInstanceState */, null /* callback */, null /* lifecycle */);
158         mSuggestionAdapter.setSuggestions(mOneSuggestion);
159         doReturn("sans").when(mContext).getString(anyInt());
160
161         // Bind twice
162         mSuggestionAdapter.onBindViewHolder(mSuggestionHolder, 0);
163         mSuggestionAdapter.onBindViewHolder(mSuggestionHolder, 0);
164
165         // Log once
166         verify(mFeatureFactory.metricsFeatureProvider).action(
167                 mContext, MetricsProto.MetricsEvent.ACTION_SHOW_SETTINGS_SUGGESTION,
168                 mOneSuggestion.get(0).getId());
169     }
170
171     @Test
172     public void onBindViewHolder_itemViewShouldHandleClick()
173             throws PendingIntent.CanceledException {
174         final List<Suggestion> suggestions = makeSuggestions("pkg1");
175         setupSuggestions(mActivity, suggestions);
176
177         mSuggestionAdapter.onBindViewHolder(mSuggestionHolder, 0);
178         mSuggestionHolder.itemView.performClick();
179
180         verify(mSuggestionControllerMixin).launchSuggestion(suggestions.get(0));
181         verify(suggestions.get(0).getPendingIntent()).send();
182     }
183
184     @Test
185     public void onBindViewHolder_hasButton_buttonShouldHandleClick()
186         throws PendingIntent.CanceledException {
187         final List<Suggestion> suggestions = new ArrayList<>();
188         final PendingIntent pendingIntent = mock(PendingIntent.class);
189         suggestions.add(new Suggestion.Builder("id")
190             .setFlags(Suggestion.FLAG_HAS_BUTTON)
191             .setTitle("123")
192             .setSummary("456")
193             .setPendingIntent(pendingIntent)
194             .build());
195         mSuggestionAdapter = new SuggestionAdapter(mContext, mSuggestionControllerMixin,
196             null /* savedInstanceState */, null /* callback */, null /* lifecycle */);
197         mSuggestionAdapter.setSuggestions(suggestions);
198         mSuggestionHolder = mSuggestionAdapter.onCreateViewHolder(
199             new FrameLayout(RuntimeEnvironment.application),
200             mSuggestionAdapter.getItemViewType(0));
201         doReturn("sans").when(mContext).getString(anyInt());
202
203         mSuggestionAdapter.onBindViewHolder(mSuggestionHolder, 0);
204         mSuggestionHolder.itemView.findViewById(android.R.id.primary).performClick();
205
206         verify(mSuggestionControllerMixin).launchSuggestion(suggestions.get(0));
207         verify(pendingIntent).send();
208     }
209
210     @Test
211     public void getSuggestions_shouldReturnSuggestionWhenMatch() {
212         final List<Suggestion> suggestions = makeSuggestions("pkg1");
213         setupSuggestions(mActivity, suggestions);
214
215         assertThat(mSuggestionAdapter.getSuggestion(0)).isNotNull();
216     }
217
218     @Test
219     public void onBindViewHolder_closeButtonShouldHandleClick()
220         throws PendingIntent.CanceledException {
221         final List<Suggestion> suggestions = makeSuggestions("pkg1");
222         final SuggestionAdapter.Callback callback = mock(SuggestionAdapter.Callback.class);
223         mSuggestionAdapter = new SuggestionAdapter(mActivity, mSuggestionControllerMixin,
224             null /* savedInstanceState */, callback, null /* lifecycle */);
225         mSuggestionAdapter.setSuggestions(suggestions);
226         mSuggestionHolder = mSuggestionAdapter.onCreateViewHolder(
227             new FrameLayout(RuntimeEnvironment.application),
228             mSuggestionAdapter.getItemViewType(0));
229
230         mSuggestionAdapter.onBindViewHolder(mSuggestionHolder, 0);
231         mSuggestionHolder.itemView.findViewById(R.id.close_button).performClick();
232
233         final Suggestion suggestion = suggestions.get(0);
234         verify(mFeatureFactory.suggestionsFeatureProvider).dismissSuggestion(
235             mActivity, mSuggestionControllerMixin, suggestion);
236         verify(callback).onSuggestionClosed(suggestion);
237     }
238
239     @Test
240     public void onBindViewHolder_iconNotTintable_shouldNotTintIcon()
241             throws PendingIntent.CanceledException {
242         final Icon icon = mock(Icon.class);
243         final Suggestion suggestion = new Suggestion.Builder("pkg1")
244             .setPendingIntent(mock(PendingIntent.class))
245             .setIcon(icon)
246             .build();
247         final List<Suggestion> suggestions = new ArrayList<>();
248         suggestions.add(suggestion);
249         mSuggestionAdapter = new SuggestionAdapter(mActivity, mSuggestionControllerMixin,
250             null /* savedInstanceState */, null /* callback */, null /* lifecycle */);
251         mSuggestionAdapter.setSuggestions(suggestions);
252         mSuggestionHolder = mSuggestionAdapter.onCreateViewHolder(
253             new FrameLayout(RuntimeEnvironment.application),
254             mSuggestionAdapter.getItemViewType(0));
255         DashboardAdapter.IconCache cache = mock(DashboardAdapter.IconCache.class);
256         final Drawable drawable = mock(Drawable.class);
257         when(cache.getIcon(icon)).thenReturn(drawable);
258         ReflectionHelpers.setField(mSuggestionAdapter, "mCache", cache);
259
260         mSuggestionAdapter.onBindViewHolder(mSuggestionHolder, 0);
261
262         verify(drawable, never()).setTint(anyInt());
263     }
264
265     @Test
266     public void onBindViewHolder_iconTintable_shouldTintIcon()
267             throws PendingIntent.CanceledException {
268         final Icon icon = mock(Icon.class);
269         final int FLAG_ICON_TINTABLE = 1 << 1;
270         final Suggestion suggestion = new Suggestion.Builder("pkg1")
271             .setPendingIntent(mock(PendingIntent.class))
272             .setIcon(icon)
273             .setFlags(FLAG_ICON_TINTABLE)
274             .build();
275         final List<Suggestion> suggestions = new ArrayList<>();
276         suggestions.add(suggestion);
277         mSuggestionAdapter = new SuggestionAdapter(mActivity, mSuggestionControllerMixin,
278             null /* savedInstanceState */, null /* callback */, null /* lifecycle */);
279         mSuggestionAdapter.setSuggestions(suggestions);
280         mSuggestionHolder = mSuggestionAdapter.onCreateViewHolder(
281             new FrameLayout(RuntimeEnvironment.application),
282             mSuggestionAdapter.getItemViewType(0));
283         DashboardAdapter.IconCache cache = mock(DashboardAdapter.IconCache.class);
284         final Drawable drawable = mock(Drawable.class);
285         when(cache.getIcon(icon)).thenReturn(drawable);
286         ReflectionHelpers.setField(mSuggestionAdapter, "mCache", cache);
287         TypedArray typedArray = mock(TypedArray.class);
288         final int colorAccent = 1234;
289         when(mActivity.obtainStyledAttributes(any())).thenReturn(typedArray);
290         when(typedArray.getColor(anyInt(), anyInt())).thenReturn(colorAccent);
291
292         mSuggestionAdapter.onBindViewHolder(mSuggestionHolder, 0);
293
294         verify(drawable).setTint(colorAccent);
295     }
296
297     @Test
298     public void setCardLayout_oneCard_shouldSetCardWidthToMatchParent() {
299         final List<Suggestion> suggestions = makeSuggestions("pkg1");
300         setupSuggestions(mContext, suggestions);
301
302         mConfig.setCardLayout(mSuggestionHolder, 1, 0);
303
304         assertThat(mSuggestionHolder.itemView.getLayoutParams().width)
305             .isEqualTo(LinearLayout.LayoutParams.MATCH_PARENT);
306     }
307
308     @Test
309     public void setCardLayout_twoCards_shouldSetCardWidthToHalfScreenMinusPadding() {
310         final List<Suggestion> suggestions = makeSuggestions("pkg1");
311         setupSuggestions(mContext, suggestions);
312         doReturn(200).when(mConfig).getScreenWidth();
313
314         mConfig.setCardLayout(mSuggestionHolder, 2, 0);
315
316         /*
317          * card width = (screen width - left margin - inner margin - right margin) / 2
318          *            = (200 - 20 - 10 - 20) / 2
319          *            = 75
320          */
321         assertThat(mSuggestionHolder.itemView.getLayoutParams().width).isEqualTo(75);
322     }
323
324
325     @Test
326     public void setCardLayout_multipleCards_shouldSetCardWidthFromResource() {
327         final List<Suggestion> suggestions = makeSuggestions("pkg1");
328         setupSuggestions(mContext, suggestions);
329
330         mConfig.setCardLayout(mSuggestionHolder, 3, 0);
331
332         assertThat(mSuggestionHolder.itemView.getLayoutParams().width).isEqualTo(120);
333     }
334
335     private void setupSuggestions(Context context, List<Suggestion> suggestions) {
336         mSuggestionAdapter = new SuggestionAdapter(context, mSuggestionControllerMixin,
337             null /* savedInstanceState */, null /* callback */, null /* lifecycle */);
338         mSuggestionAdapter.setSuggestions(suggestions);
339         mSuggestionHolder = mSuggestionAdapter.onCreateViewHolder(
340                 new FrameLayout(RuntimeEnvironment.application),
341                 mSuggestionAdapter.getItemViewType(0));
342     }
343
344     private List<Suggestion> makeSuggestions(String... pkgNames) {
345         final List<Suggestion> suggestions = new ArrayList<>();
346         for (String pkgName : pkgNames) {
347             final Suggestion suggestion = new Suggestion.Builder(pkgName)
348                     .setPendingIntent(mock(PendingIntent.class))
349                     .build();
350             suggestions.add(suggestion);
351         }
352         return suggestions;
353     }
354 }