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.applications; 18 19 20 import static com.google.common.truth.Truth.assertThat; 21 import static org.mockito.Matchers.any; 22 import static org.mockito.Matchers.anyInt; 23 import static org.mockito.Matchers.eq; 24 import static org.mockito.Mockito.mock; 25 import static org.mockito.Mockito.verify; 26 import static org.mockito.Mockito.when; 27 28 import android.app.ActionBar; 29 import android.app.Activity; 30 import android.app.Fragment; 31 import android.content.Context; 32 import android.content.Intent; 33 import android.content.pm.ActivityInfo; 34 import android.content.pm.PackageInfo; 35 import android.content.pm.ResolveInfo; 36 import android.graphics.drawable.ColorDrawable; 37 import android.os.UserHandle; 38 import android.support.v7.preference.Preference; 39 import android.view.LayoutInflater; 40 import android.view.View; 41 import android.widget.TextView; 42 43 import com.android.settings.R; 44 import com.android.settings.SettingsRobolectricTestRunner; 45 import com.android.settings.TestConfig; 46 47 import org.junit.Before; 48 import org.junit.Test; 49 import org.junit.runner.RunWith; 50 import org.mockito.Answers; 51 import org.mockito.Mock; 52 import org.mockito.MockitoAnnotations; 53 import org.robolectric.RuntimeEnvironment; 54 import org.robolectric.annotation.Config; 55 56 @RunWith(SettingsRobolectricTestRunner.class) 57 @Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION) 58 public class AppHeaderControllerTest { 59 60 @Mock(answer = Answers.RETURNS_DEEP_STUBS) 61 private Context mContext; 62 @Mock(answer = Answers.RETURNS_DEEP_STUBS) 63 private Activity mActivity; 64 @Mock 65 private Fragment mFragment; 66 67 private Context mShadowContext; 68 private LayoutInflater mLayoutInflater; 69 private PackageInfo mInfo; 70 private AppHeaderController mController; 71 72 73 @Before 74 public void setUp() { 75 MockitoAnnotations.initMocks(this); 76 mShadowContext = RuntimeEnvironment.application; 77 when(mFragment.getContext()).thenReturn(mShadowContext); 78 mLayoutInflater = LayoutInflater.from(mShadowContext); 79 mInfo = new PackageInfo(); 80 mInfo.versionName = "1234"; 81 } 82 83 @Test 84 public void testBuildView_constructedWithoutView_shouldCreateNewView() { 85 mController = new AppHeaderController(mShadowContext, mFragment, null); 86 View view = mController.done(mActivity); 87 88 assertThat(view).isNotNull(); 89 } 90 91 @Test 92 public void testBuildView_withContext_shouldBuildPreference() { 93 mController = new AppHeaderController(mShadowContext, mFragment, null); 94 Preference preference = mController.done(mActivity, mShadowContext); 95 96 assertThat(preference instanceof LayoutPreference).isTrue(); 97 } 98 99 @Test 100 public void testBuildView_constructedWithView_shouldReturnSameView() { 101 View inputView = mLayoutInflater.inflate(R.layout.app_details, null /* root */); 102 mController = new AppHeaderController(mShadowContext, mFragment, inputView); 103 View view = mController.done(mActivity); 104 105 assertThat(view).isSameAs(inputView); 106 } 107 108 @Test 109 public void bindViews_shouldBindAllData() { 110 final String testString = "test"; 111 final View appHeader = mLayoutInflater.inflate(R.layout.app_details, null /* root */); 112 final TextView label = appHeader.findViewById(R.id.app_detail_title); 113 final TextView version = appHeader.findViewById(R.id.app_detail_summary); 114 115 mController = new AppHeaderController(mShadowContext, mFragment, appHeader); 116 mController.setLabel(testString); 117 mController.setSummary(testString); 118 mController.setIcon(mShadowContext.getDrawable(R.drawable.ic_add)); 119 mController.done(mActivity); 120 121 assertThat(label.getText()).isEqualTo(testString); 122 assertThat(version.getText()).isEqualTo(testString); 123 } 124 125 @Test 126 public void bindButton_hasAppPref_shouldShowButton() { 127 final ResolveInfo info = new ResolveInfo(); 128 info.activityInfo = new ActivityInfo(); 129 info.activityInfo.packageName = "123"; 130 info.activityInfo.name = "321"; 131 final View appLinks = mLayoutInflater 132 .inflate(R.layout.app_details, null /* root */); 133 when(mContext.getPackageManager().resolveActivity(any(Intent.class), anyInt())) 134 .thenReturn(info); 135 136 mController = new AppHeaderController(mContext, mFragment, appLinks); 137 mController.setButtonActions( 138 AppHeaderController.ActionType.ACTION_APP_PREFERENCE, 139 AppHeaderController.ActionType.ACTION_NONE); 140 mController.done(mActivity); 141 142 assertThat(appLinks.findViewById(R.id.left_button).getVisibility()) 143 .isEqualTo(View.VISIBLE); 144 assertThat(appLinks.findViewById(R.id.right_button).getVisibility()) 145 .isEqualTo(View.GONE); 146 try { 147 appLinks.findViewById(R.id.left_button).performClick(); 148 } catch (Exception e) { 149 // Ignore exception because the launching intent is fake. 150 } 151 verify(mFragment).startActivity(any(Intent.class)); 152 } 153 154 @Test 155 public void bindButton_noAppPref_shouldNotShowButton() { 156 final View appLinks = mLayoutInflater 157 .inflate(R.layout.app_details, null /* root */); 158 when(mContext.getPackageManager().resolveActivity(any(Intent.class), anyInt())) 159 .thenReturn(null); 160 161 mController = new AppHeaderController(mContext, mFragment, appLinks); 162 mController.setButtonActions( 163 AppHeaderController.ActionType.ACTION_APP_PREFERENCE, 164 AppHeaderController.ActionType.ACTION_NONE); 165 mController.done(mActivity); 166 167 assertThat(appLinks.findViewById(R.id.left_button).getVisibility()) 168 .isEqualTo(View.GONE); 169 assertThat(appLinks.findViewById(R.id.right_button).getVisibility()) 170 .isEqualTo(View.GONE); 171 } 172 173 @Test 174 public void bindButton_noAppInfo_shouldNotShowButton() { 175 final View appLinks = mLayoutInflater 176 .inflate(R.layout.app_details, null /* root */); 177 178 mController = new AppHeaderController(mContext, mFragment, appLinks); 179 mController.setPackageName(null) 180 .setButtonActions( 181 AppHeaderController.ActionType.ACTION_APP_INFO, 182 AppHeaderController.ActionType.ACTION_NONE); 183 mController.done(mActivity); 184 185 assertThat(appLinks.findViewById(R.id.left_button).getVisibility()) 186 .isEqualTo(View.GONE); 187 assertThat(appLinks.findViewById(R.id.right_button).getVisibility()) 188 .isEqualTo(View.GONE); 189 } 190 191 @Test 192 public void bindButton_hasAppInfo_shouldShowButton() { 193 final View appLinks = mLayoutInflater 194 .inflate(R.layout.app_details, null /* root */); 195 when(mFragment.getActivity()).thenReturn(mock(Activity.class)); 196 197 mController = new AppHeaderController(mContext, mFragment, appLinks); 198 mController.setPackageName("123") 199 .setUid(UserHandle.USER_SYSTEM) 200 .setButtonActions( 201 AppHeaderController.ActionType.ACTION_APP_INFO, 202 AppHeaderController.ActionType.ACTION_NOTIF_PREFERENCE); 203 mController.done(mActivity); 204 205 assertThat(appLinks.findViewById(R.id.left_button).getVisibility()) 206 .isEqualTo(View.VISIBLE); 207 assertThat(appLinks.findViewById(R.id.right_button).getVisibility()) 208 .isEqualTo(View.GONE); 209 } 210 211 @Test 212 public void bindButton_hasAppInfo_shouldHaveContentDescription() { 213 final View appLinks = mLayoutInflater 214 .inflate(R.layout.app_details, null /* root */); 215 when(mFragment.getActivity()).thenReturn(mock(Activity.class)); 216 when(mContext.getString(eq(R.string.application_info_label))).thenReturn("App Info"); 217 218 mController = new AppHeaderController(mContext, mFragment, appLinks); 219 mController.setPackageName("123") 220 .setUid(UserHandle.USER_SYSTEM) 221 .setButtonActions( 222 AppHeaderController.ActionType.ACTION_APP_INFO, 223 AppHeaderController.ActionType.ACTION_NOTIF_PREFERENCE); 224 mController.done(mActivity); 225 226 assertThat(appLinks.findViewById(R.id.left_button).getContentDescription()) 227 .isEqualTo("App Info"); 228 } 229 230 @Test 231 public void bindButton_hasAppNotifIntent_shouldShowButton() { 232 final View appLinks = mLayoutInflater 233 .inflate(R.layout.app_details, null /* root */); 234 235 mController = new AppHeaderController(mContext, mFragment, appLinks); 236 mController.setAppNotifPrefIntent(new Intent()) 237 .setButtonActions( 238 AppHeaderController.ActionType.ACTION_NOTIF_PREFERENCE, 239 AppHeaderController.ActionType.ACTION_NONE); 240 mController.done(mActivity); 241 242 assertThat(appLinks.findViewById(R.id.left_button).getVisibility()) 243 .isEqualTo(View.VISIBLE); 244 assertThat(appLinks.findViewById(R.id.right_button).getVisibility()) 245 .isEqualTo(View.GONE); 246 } 247 248 // Ensure that the instant app label does not show up when we haven't told the controller the 249 // app is instant. 250 @Test 251 public void instantApps_normalAppsDontGetLabel() { 252 final View appHeader = mLayoutInflater.inflate(R.layout.app_details, null /* root */); 253 mController = new AppHeaderController(mContext, mFragment, appHeader); 254 mController.done(mActivity); 255 assertThat(appHeader.findViewById(R.id.install_type).getVisibility()) 256 .isEqualTo(View.GONE); 257 } 258 259 // Test that the "instant apps" label is present in the header when we have an instant app. 260 @Test 261 public void instantApps_expectedHeaderItem() { 262 final View appHeader = mLayoutInflater.inflate(R.layout.app_details, null /* root */); 263 mController = new AppHeaderController(mContext, mFragment, appHeader); 264 mController.setIsInstantApp(true); 265 mController.done(mActivity); 266 TextView label = appHeader.findViewById(R.id.install_type); 267 assertThat(label.getVisibility()).isEqualTo(View.VISIBLE); 268 assertThat(label.getText()).isEqualTo( 269 appHeader.getResources().getString(R.string.install_type_instant)); 270 assertThat(appHeader.findViewById(R.id.app_detail_summary).getVisibility()) 271 .isEqualTo(View.GONE); 272 } 273 274 @Test 275 public void styleActionBar_invalidObjects_shouldNotCrash() { 276 mController = new AppHeaderController(mShadowContext, mFragment, null); 277 mController.styleActionBar(null); 278 279 when(mActivity.getActionBar()).thenReturn(null); 280 mController.styleActionBar(mActivity); 281 282 verify(mActivity).getActionBar(); 283 } 284 285 @Test 286 public void styleActionBar_setElevationAndBackground() { 287 final ActionBar actionBar = mActivity.getActionBar(); 288 289 mController = new AppHeaderController(mShadowContext, mFragment, null); 290 mController.styleActionBar(mActivity); 291 292 verify(actionBar).setElevation(0); 293 // Enforce a color drawable as background here, as image based drawables might not be 294 // wide enough to cover entire action bar. 295 verify(actionBar).setBackgroundDrawable(any(ColorDrawable.class)); 296 } 297 298 @Test 299 public void initAppHeaderController_appHeaderNull_useFragmentContext() { 300 mController = new AppHeaderController(mContext, mFragment, null); 301 302 // Fragment.getContext() is invoked to inflate the view 303 verify(mFragment).getContext(); 304 } 305 } 306