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 
18 package com.android.settings.search;
19 
20 import static com.google.common.truth.Truth.assertThat;
21 
22 import static org.mockito.Matchers.any;
23 import static org.mockito.Matchers.eq;
24 import static org.mockito.Mockito.doReturn;
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.content.ComponentName;
30 import android.content.Context;
31 import android.content.Intent;
32 import android.content.pm.ApplicationInfo;
33 import android.content.pm.PackageManager;
34 import android.graphics.drawable.Drawable;
35 import android.os.UserHandle;
36 import android.util.Pair;
37 import android.view.LayoutInflater;
38 import android.view.View;
39 
40 import com.android.internal.logging.nano.MetricsProto;
41 import com.android.settings.R;
42 import com.android.settings.SettingsRobolectricTestRunner;
43 import com.android.settings.TestConfig;
44 import com.android.settings.search2.AppSearchResult;
45 import com.android.settings.search2.IntentPayload;
46 import com.android.settings.search2.IntentSearchViewHolder;
47 import com.android.settings.search2.SearchFragment;
48 import com.android.settings.search2.SearchResult;
49 import com.android.settings.search2.SearchResult.Builder;
50 import com.android.settings.testutils.FakeFeatureFactory;
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 
61 import java.util.ArrayList;
62 import java.util.List;
63 
64 @RunWith(SettingsRobolectricTestRunner.class)
65 @Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
66 public class IntentSearchViewHolderTest {
67 
68     private static final String TITLE = "title";
69     private static final String SUMMARY = "summary";
70     private static final int USER_ID = 10;
71     private static final String BADGED_LABEL = "work title";
72 
73     @Mock(answer = Answers.RETURNS_DEEP_STUBS)
74     private Context mContext;
75     @Mock(answer = Answers.RETURNS_DEEP_STUBS)
76     private SearchFragment mFragment;
77     @Mock
78     private PackageManager mPackageManager;
79     private FakeFeatureFactory mFeatureFactory;
80     private IntentSearchViewHolder mHolder;
81     private Drawable mIcon;
82     private Drawable mBadgedIcon;
83 
84     @Before
setUp()85     public void setUp() {
86         MockitoAnnotations.initMocks(this);
87         FakeFeatureFactory.setupForTest(mContext);
88         mFeatureFactory = (FakeFeatureFactory) FakeFeatureFactory.getFactory(mContext);
89 
90         final Context context = RuntimeEnvironment.application;
91         View view = LayoutInflater.from(context).inflate(R.layout.search_intent_item, null);
92         mHolder = new IntentSearchViewHolder(view);
93 
94         mIcon = context.getDrawable(R.drawable.ic_search_history);
95         mBadgedIcon = context.getDrawable(R.drawable.ic_add);
96         when(mFragment.getActivity().getPackageManager()).thenReturn(mPackageManager);
97     }
98 
99     @Test
testConstructor_membersNotNull()100     public void testConstructor_membersNotNull() {
101         assertThat(mHolder.titleView).isNotNull();
102         assertThat(mHolder.summaryView).isNotNull();
103         assertThat(mHolder.iconView).isNotNull();
104         assertThat(mHolder.breadcrumbView).isNotNull();
105     }
106 
107     @Test
testBindViewElements_allUpdated()108     public void testBindViewElements_allUpdated() {
109         SearchResult result = getSearchResult(TITLE, SUMMARY, mIcon);
110         mHolder.onBind(mFragment, result);
111         mHolder.itemView.performClick();
112 
113         assertThat(mHolder.titleView.getText()).isEqualTo(TITLE);
114         assertThat(mHolder.summaryView.getText()).isEqualTo(SUMMARY);
115         assertThat(mHolder.iconView.getDrawable()).isEqualTo(mIcon);
116         assertThat(mHolder.summaryView.getVisibility()).isEqualTo(View.VISIBLE);
117         assertThat(mHolder.breadcrumbView.getVisibility()).isEqualTo(View.GONE);
118 
119         verify(mFragment).onSearchResultClicked();
120         verify(mFragment).startActivity(any(Intent.class));
121         verify(mFeatureFactory.metricsFeatureProvider).action(any(Context.class),
122                 eq(MetricsProto.MetricsEvent.ACTION_CLICK_SETTINGS_SEARCH_RESULT),
123                 eq(((IntentPayload)result.payload).intent.getComponent().flattenToString()),
124                 any(Pair.class));
125     }
126 
127     @Test
testBindViewIcon_nullIcon_imageDrawableIsNull()128     public void testBindViewIcon_nullIcon_imageDrawableIsNull() {
129         final SearchResult result = getSearchResult(TITLE, SUMMARY, null);
130         mHolder.onBind(mFragment, result);
131 
132         assertThat(mHolder.iconView.getDrawable()).isNull();
133     }
134 
135     @Test
testBindViewElements_emptySummary_hideSummaryView()136     public void testBindViewElements_emptySummary_hideSummaryView() {
137         final SearchResult result = new Builder()
138                 .addTitle(TITLE)
139                 .addRank(1)
140                 .addPayload(new IntentPayload(null))
141                 .addIcon(mIcon)
142                 .build();
143 
144         mHolder.onBind(mFragment, result);
145         assertThat(mHolder.summaryView.getVisibility()).isEqualTo(View.GONE);
146     }
147 
148     @Test
testBindViewElements_withBreadcrumb_shouldFormatBreadcrumb()149     public void testBindViewElements_withBreadcrumb_shouldFormatBreadcrumb() {
150         final List<String> breadcrumbs = new ArrayList<>();
151         breadcrumbs.add("a");
152         breadcrumbs.add("b");
153         breadcrumbs.add("c");
154         final SearchResult result = new Builder()
155                 .addTitle(TITLE)
156                 .addRank(1)
157                 .addPayload(new IntentPayload(null))
158                 .addBreadcrumbs(breadcrumbs)
159                 .addIcon(mIcon)
160                 .build();
161 
162         mHolder.onBind(mFragment, result);
163         assertThat(mHolder.breadcrumbView.getVisibility()).isEqualTo(View.VISIBLE);
164         assertThat(mHolder.breadcrumbView.getText()).isEqualTo("a > b > c");
165     }
166 
167     @Test
testBindElements_placeholderSummary_visibilityIsGone()168     public void testBindElements_placeholderSummary_visibilityIsGone() {
169         String nonBreakingSpace = mContext.getString(R.string.summary_placeholder);
170         SearchResult result = new Builder()
171                 .addTitle(TITLE)
172                 .addSummary(nonBreakingSpace)
173                 .addPayload(new IntentPayload(null))
174                 .build();
175 
176         mHolder.onBind(mFragment, result);
177 
178         assertThat(mHolder.summaryView.getVisibility()).isEqualTo(View.GONE);
179     }
180 
181     @Test
testBindElements_dynamicSummary_visibilityIsGone()182     public void testBindElements_dynamicSummary_visibilityIsGone() {
183         String dynamicSummary = "%s";
184         SearchResult result = new Builder()
185                 .addTitle(TITLE)
186                 .addSummary(dynamicSummary)
187                 .addPayload(new IntentPayload(null))
188                 .build();
189 
190         mHolder.onBind(mFragment, result);
191 
192         assertThat(mHolder.summaryView.getVisibility()).isEqualTo(View.GONE);
193     }
194 
testBindViewElements_appSearchResult()195     public void testBindViewElements_appSearchResult() {
196         when(mPackageManager.getUserBadgedLabel(any(CharSequence.class),
197                 eq(new UserHandle(USER_ID)))).thenReturn(BADGED_LABEL);
198 
199         SearchResult result = getAppSearchResult(
200                 TITLE, SUMMARY, mIcon, getApplicationInfo(USER_ID, TITLE, mIcon));
201         mHolder.onBind(mFragment, result);
202         mHolder.itemView.performClick();
203 
204         assertThat(mHolder.titleView.getText()).isEqualTo(TITLE);
205         assertThat(mHolder.summaryView.getText()).isEqualTo(SUMMARY);
206         assertThat(mHolder.summaryView.getVisibility()).isEqualTo(View.VISIBLE);
207         assertThat(mHolder.breadcrumbView.getVisibility()).isEqualTo(View.GONE);
208         assertThat(mHolder.titleView.getContentDescription()).isEqualTo(BADGED_LABEL);
209 
210         verify(mFragment).onSearchResultClicked();
211         verify(mFragment.getActivity()).startActivityAsUser(
212                 any(Intent.class), eq(new UserHandle(USER_ID)));
213         verify(mFeatureFactory.metricsFeatureProvider).action(any(Context.class),
214                 eq(MetricsProto.MetricsEvent.ACTION_CLICK_SETTINGS_SEARCH_RESULT),
215                 eq(((IntentPayload)result.payload).intent.getComponent().flattenToString()),
216                 any(Pair.class));
217     }
218 
getSearchResult(String title, String summary, Drawable icon)219     private SearchResult getSearchResult(String title, String summary, Drawable icon) {
220         Builder builder = new Builder();
221         builder.addTitle(title)
222                 .addSummary(summary)
223                 .addRank(1)
224                 .addPayload(new IntentPayload(
225                         new Intent().setComponent(new ComponentName("pkg", "class"))))
226                 .addBreadcrumbs(new ArrayList<>())
227                 .addIcon(icon);
228 
229         return builder.build();
230     }
231 
getAppSearchResult( String title, String summary, Drawable icon, ApplicationInfo applicationInfo)232     private SearchResult getAppSearchResult(
233             String title, String summary, Drawable icon, ApplicationInfo applicationInfo) {
234         AppSearchResult.Builder builder = new AppSearchResult.Builder();
235         builder.addTitle(title)
236                 .addSummary(summary)
237                 .addRank(1)
238                 .addPayload(new IntentPayload(
239                         new Intent().setComponent(new ComponentName("pkg", "class"))))
240                 .addBreadcrumbs(new ArrayList<>())
241                 .addIcon(icon);
242         builder.setAppInfo(applicationInfo);
243         return builder.build();
244     }
245 
getApplicationInfo(int userId, CharSequence appLabel, Drawable icon)246     private ApplicationInfo getApplicationInfo(int userId, CharSequence appLabel, Drawable icon) {
247         ApplicationInfo applicationInfo = spy(new ApplicationInfo());
248         applicationInfo.uid = UserHandle.getUid(userId, 12345);
249         doReturn(icon).when(applicationInfo).loadIcon(any(PackageManager.class));
250         doReturn(appLabel).when(applicationInfo).loadLabel(any(PackageManager.class));
251         return applicationInfo;
252     }
253 }
254