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