2 * Copyright (C) 2017 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
16 package com.android.settings.dashboard.suggestions;
18 import static com.google.common.truth.Truth.assertThat;
20 import static org.mockito.ArgumentMatchers.any;
21 import static org.mockito.ArgumentMatchers.anyInt;
22 import static org.mockito.Mockito.mock;
23 import static org.mockito.Mockito.never;
24 import static org.mockito.Mockito.spy;
25 import static org.mockito.Mockito.verify;
26 import static org.mockito.Mockito.when;
28 import android.app.PendingIntent;
29 import android.content.Context;
30 import android.content.res.TypedArray;
31 import android.graphics.drawable.Drawable;
32 import android.graphics.drawable.Icon;
33 import android.service.settings.suggestions.Suggestion;
34 import android.view.LayoutInflater;
35 import android.view.View;
36 import android.widget.FrameLayout;
37 import android.widget.LinearLayout;
39 import com.android.internal.logging.nano.MetricsProto;
40 import com.android.settings.R;
41 import com.android.settings.SettingsActivity;
42 import com.android.settings.TestConfig;
43 import com.android.settings.dashboard.DashboardAdapter;
44 import com.android.settings.testutils.FakeFeatureFactory;
45 import com.android.settings.testutils.SettingsRobolectricTestRunner;
46 import com.android.settingslib.suggestions.SuggestionControllerMixin;
48 import org.junit.Before;
49 import org.junit.Test;
50 import org.junit.runner.RunWith;
51 import org.mockito.Answers;
52 import org.mockito.Mock;
53 import org.mockito.MockitoAnnotations;
54 import org.robolectric.RuntimeEnvironment;
55 import org.robolectric.annotation.Config;
56 import org.robolectric.util.ReflectionHelpers;
58 import java.util.ArrayList;
59 import java.util.List;
61 @RunWith(SettingsRobolectricTestRunner.class)
62 @Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
63 public class SuggestionAdapterTest {
65 @Mock(answer = Answers.RETURNS_DEEP_STUBS)
66 private SettingsActivity mActivity;
68 private SuggestionControllerMixin mSuggestionControllerMixin;
69 private FakeFeatureFactory mFeatureFactory;
70 private Context mContext;
71 private SuggestionAdapter mSuggestionAdapter;
72 private DashboardAdapter.DashboardItemHolder mSuggestionHolder;
73 private List<Suggestion> mOneSuggestion;
74 private List<Suggestion> mTwoSuggestions;
78 MockitoAnnotations.initMocks(this);
79 mContext = RuntimeEnvironment.application;
80 mFeatureFactory = FakeFeatureFactory.setupForTest();
82 final Suggestion suggestion1 = new Suggestion.Builder("id1")
83 .setTitle("Test suggestion 1")
85 final Suggestion suggestion2 = new Suggestion.Builder("id2")
86 .setTitle("Test suggestion 2")
88 mOneSuggestion = new ArrayList<>();
89 mOneSuggestion.add(suggestion1);
90 mTwoSuggestions = new ArrayList<>();
91 mTwoSuggestions.add(suggestion1);
92 mTwoSuggestions.add(suggestion2);
96 public void getItemCount_shouldReturnListSize() {
97 mSuggestionAdapter = new SuggestionAdapter(mContext, mSuggestionControllerMixin,
98 null /* savedInstanceState */, null /* callback */, null /* lifecycle */);
99 mSuggestionAdapter.setSuggestions(mOneSuggestion);
100 assertThat(mSuggestionAdapter.getItemCount()).isEqualTo(1);
102 mSuggestionAdapter.setSuggestions(mTwoSuggestions);
103 assertThat(mSuggestionAdapter.getItemCount()).isEqualTo(2);
107 public void getItemViewType_shouldReturnSuggestionTile() {
108 mSuggestionAdapter = new SuggestionAdapter(mContext, mSuggestionControllerMixin,
109 null /* savedInstanceState */, null /* callback */, null /* lifecycle */);
110 mSuggestionAdapter.setSuggestions(mOneSuggestion);
111 assertThat(mSuggestionAdapter.getItemViewType(0))
112 .isEqualTo(R.layout.suggestion_tile);
116 public void getItemType_hasButton_shouldReturnSuggestionWithButton() {
117 final List<Suggestion> suggestions = new ArrayList<>();
118 suggestions.add(new Suggestion.Builder("id")
119 .setFlags(Suggestion.FLAG_HAS_BUTTON)
123 mSuggestionAdapter = new SuggestionAdapter(mContext, mSuggestionControllerMixin,
124 null /* savedInstanceState */, null /* callback */, null /* lifecycle */);
125 mSuggestionAdapter.setSuggestions(suggestions);
127 assertThat(mSuggestionAdapter.getItemViewType(0))
128 .isEqualTo(R.layout.suggestion_tile_with_button);
132 public void onBindViewHolder_shouldLog() {
133 final View view = spy(LayoutInflater.from(mContext).inflate(
134 R.layout.suggestion_tile, new LinearLayout(mContext), true));
135 mSuggestionHolder = new DashboardAdapter.DashboardItemHolder(view);
136 mSuggestionAdapter = new SuggestionAdapter(mContext, mSuggestionControllerMixin,
137 null /* savedInstanceState */, null /* callback */, null /* lifecycle */);
138 mSuggestionAdapter.setSuggestions(mOneSuggestion);
141 mSuggestionAdapter.onBindViewHolder(mSuggestionHolder, 0);
142 mSuggestionAdapter.onBindViewHolder(mSuggestionHolder, 0);
145 verify(mFeatureFactory.metricsFeatureProvider).action(
146 mContext, MetricsProto.MetricsEvent.ACTION_SHOW_SETTINGS_SUGGESTION,
147 mOneSuggestion.get(0).getId());
151 public void onBindViewHolder_itemViewShouldHandleClick()
152 throws PendingIntent.CanceledException {
153 final List<Suggestion> suggestions = makeSuggestions("pkg1");
154 setupSuggestions(mActivity, suggestions);
156 mSuggestionAdapter.onBindViewHolder(mSuggestionHolder, 0);
157 mSuggestionHolder.itemView.performClick();
159 verify(mSuggestionControllerMixin).launchSuggestion(suggestions.get(0));
160 verify(suggestions.get(0).getPendingIntent()).send();
164 public void onBindViewHolder_hasButton_buttonShouldHandleClick()
165 throws PendingIntent.CanceledException {
166 final List<Suggestion> suggestions = new ArrayList<>();
167 final PendingIntent pendingIntent = mock(PendingIntent.class);
168 suggestions.add(new Suggestion.Builder("id")
169 .setFlags(Suggestion.FLAG_HAS_BUTTON)
172 .setPendingIntent(pendingIntent)
174 mSuggestionAdapter = new SuggestionAdapter(mContext, mSuggestionControllerMixin,
175 null /* savedInstanceState */, null /* callback */, null /* lifecycle */);
176 mSuggestionAdapter.setSuggestions(suggestions);
177 mSuggestionHolder = mSuggestionAdapter.onCreateViewHolder(
178 new FrameLayout(RuntimeEnvironment.application),
179 mSuggestionAdapter.getItemViewType(0));
181 mSuggestionAdapter.onBindViewHolder(mSuggestionHolder, 0);
182 mSuggestionHolder.itemView.findViewById(android.R.id.primary).performClick();
184 verify(mSuggestionControllerMixin).launchSuggestion(suggestions.get(0));
185 verify(pendingIntent).send();
189 public void getSuggestions_shouldReturnSuggestionWhenMatch() {
190 final List<Suggestion> suggestions = makeSuggestions("pkg1");
191 setupSuggestions(mActivity, suggestions);
193 assertThat(mSuggestionAdapter.getSuggestion(0)).isNotNull();
197 public void onBindViewHolder_closeButtonShouldHandleClick()
198 throws PendingIntent.CanceledException {
199 final List<Suggestion> suggestions = makeSuggestions("pkg1");
200 final SuggestionAdapter.Callback callback = mock(SuggestionAdapter.Callback.class);
201 mSuggestionAdapter = new SuggestionAdapter(mActivity, mSuggestionControllerMixin,
202 null /* savedInstanceState */, callback, null /* lifecycle */);
203 mSuggestionAdapter.setSuggestions(suggestions);
204 mSuggestionHolder = mSuggestionAdapter.onCreateViewHolder(
205 new FrameLayout(RuntimeEnvironment.application),
206 mSuggestionAdapter.getItemViewType(0));
208 mSuggestionAdapter.onBindViewHolder(mSuggestionHolder, 0);
209 mSuggestionHolder.itemView.findViewById(R.id.close_button).performClick();
211 final Suggestion suggestion = suggestions.get(0);
212 verify(mFeatureFactory.suggestionsFeatureProvider).dismissSuggestion(
213 mActivity, mSuggestionControllerMixin, suggestion);
214 verify(callback).onSuggestionClosed(suggestion);
218 public void onBindViewHolder_iconNotTintable_shouldNotTintIcon()
219 throws PendingIntent.CanceledException {
220 final Icon icon = mock(Icon.class);
221 final Suggestion suggestion = new Suggestion.Builder("pkg1")
222 .setPendingIntent(mock(PendingIntent.class))
225 final List<Suggestion> suggestions = new ArrayList<>();
226 suggestions.add(suggestion);
227 mSuggestionAdapter = new SuggestionAdapter(mActivity, mSuggestionControllerMixin,
228 null /* savedInstanceState */, null /* callback */, null /* lifecycle */);
229 mSuggestionAdapter.setSuggestions(suggestions);
230 mSuggestionHolder = mSuggestionAdapter.onCreateViewHolder(
231 new FrameLayout(RuntimeEnvironment.application),
232 mSuggestionAdapter.getItemViewType(0));
233 DashboardAdapter.IconCache cache = mock(DashboardAdapter.IconCache.class);
234 final Drawable drawable = mock(Drawable.class);
235 when(cache.getIcon(icon)).thenReturn(drawable);
236 ReflectionHelpers.setField(mSuggestionAdapter, "mCache", cache);
238 mSuggestionAdapter.onBindViewHolder(mSuggestionHolder, 0);
240 verify(drawable, never()).setTint(anyInt());
244 public void onBindViewHolder_iconTintable_shouldTintIcon()
245 throws PendingIntent.CanceledException {
246 final Icon icon = mock(Icon.class);
247 final int FLAG_ICON_TINTABLE = 1 << 1;
248 final Suggestion suggestion = new Suggestion.Builder("pkg1")
249 .setPendingIntent(mock(PendingIntent.class))
251 .setFlags(FLAG_ICON_TINTABLE)
253 final List<Suggestion> suggestions = new ArrayList<>();
254 suggestions.add(suggestion);
255 mSuggestionAdapter = new SuggestionAdapter(mActivity, mSuggestionControllerMixin,
256 null /* savedInstanceState */, null /* callback */, null /* lifecycle */);
257 mSuggestionAdapter.setSuggestions(suggestions);
258 mSuggestionHolder = mSuggestionAdapter.onCreateViewHolder(
259 new FrameLayout(RuntimeEnvironment.application),
260 mSuggestionAdapter.getItemViewType(0));
261 DashboardAdapter.IconCache cache = mock(DashboardAdapter.IconCache.class);
262 final Drawable drawable = mock(Drawable.class);
263 when(cache.getIcon(icon)).thenReturn(drawable);
264 ReflectionHelpers.setField(mSuggestionAdapter, "mCache", cache);
265 TypedArray typedArray = mock(TypedArray.class);
266 final int colorAccent = 1234;
267 when(mActivity.obtainStyledAttributes(any())).thenReturn(typedArray);
268 when(typedArray.getColor(anyInt(), anyInt())).thenReturn(colorAccent);
270 mSuggestionAdapter.onBindViewHolder(mSuggestionHolder, 0);
272 verify(drawable).setTint(colorAccent);
275 private void setupSuggestions(Context context, List<Suggestion> suggestions) {
276 mSuggestionAdapter = new SuggestionAdapter(context, mSuggestionControllerMixin,
277 null /* savedInstanceState */, null /* callback */, null /* lifecycle */);
278 mSuggestionAdapter.setSuggestions(suggestions);
279 mSuggestionHolder = mSuggestionAdapter.onCreateViewHolder(
280 new FrameLayout(RuntimeEnvironment.application),
281 mSuggestionAdapter.getItemViewType(0));
284 private List<Suggestion> makeSuggestions(String... pkgNames) {
285 final List<Suggestion> suggestions = new ArrayList<>();
286 for (String pkgName : pkgNames) {
287 final Suggestion suggestion = new Suggestion.Builder(pkgName)
288 .setPendingIntent(mock(PendingIntent.class))
290 suggestions.add(suggestion);