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 package com.android.settings.password; 18 19 import static com.google.common.truth.Truth.assertThat; 20 import static com.google.common.truth.Truth.assertWithMessage; 21 22 import android.content.ComponentName; 23 import android.content.Context; 24 import android.content.Intent; 25 import android.content.pm.PackageManager; 26 import android.content.res.Resources; 27 import android.os.UserHandle; 28 import android.util.TypedValue; 29 import android.view.View; 30 import android.widget.Button; 31 import android.widget.TextView; 32 33 import androidx.appcompat.app.AlertDialog; 34 import androidx.fragment.app.FragmentActivity; 35 import androidx.test.core.app.ApplicationProvider; 36 37 import com.android.internal.widget.LockPatternUtils; 38 import com.android.internal.widget.LockPatternView; 39 import com.android.internal.widget.LockPatternView.Cell; 40 import com.android.internal.widget.LockPatternView.DisplayMode; 41 import com.android.settings.R; 42 import com.android.settings.SetupRedactionInterstitial; 43 import com.android.settings.password.ChooseLockPattern.ChooseLockPatternFragment; 44 import com.android.settings.password.ChooseLockPattern.IntentBuilder; 45 import com.android.settings.testutils.shadow.ShadowAlertDialogCompat; 46 import com.android.settings.testutils.shadow.ShadowLockPatternUtils; 47 import com.android.settings.testutils.shadow.ShadowUtils; 48 49 import com.google.android.setupcompat.PartnerCustomizationLayout; 50 import com.google.android.setupcompat.template.FooterBarMixin; 51 import com.google.android.setupcompat.template.FooterButton; 52 53 import org.junit.Before; 54 import org.junit.Ignore; 55 import org.junit.Test; 56 import org.junit.runner.RunWith; 57 import org.robolectric.RobolectricTestRunner; 58 import org.robolectric.Shadows; 59 import org.robolectric.android.controller.ActivityController; 60 import org.robolectric.annotation.Config; 61 import org.robolectric.shadows.ShadowPackageManager; 62 import org.robolectric.util.ReflectionHelpers; 63 import org.robolectric.util.ReflectionHelpers.ClassParameter; 64 65 import java.util.Arrays; 66 67 @RunWith(RobolectricTestRunner.class) 68 @Config(shadows = {ShadowUtils.class, ShadowAlertDialogCompat.class, ShadowLockPatternUtils.class}) 69 public class SetupChooseLockPatternTest { 70 private Context mContext; 71 72 private SetupChooseLockPattern mActivity; 73 74 @Before setUp()75 public void setUp() { 76 mContext = ApplicationProvider.getApplicationContext(); 77 mContext.getPackageManager().setComponentEnabledSetting( 78 new ComponentName(mContext, SetupRedactionInterstitial.class), 79 PackageManager.COMPONENT_ENABLED_STATE_DISABLED, 80 PackageManager.DONT_KILL_APP); 81 82 final Intent intent = 83 SetupChooseLockPattern.modifyIntentForSetup( 84 mContext, 85 new IntentBuilder(mContext) 86 .setUserId(UserHandle.myUserId()) 87 .build()); 88 mActivity = ActivityController.of(new SetupChooseLockPattern(), intent).setup().get(); 89 } 90 91 @Test chooseLockSaved_shouldEnableRedactionInterstitial()92 public void chooseLockSaved_shouldEnableRedactionInterstitial() { 93 findFragment(mActivity).onChosenLockSaveFinished(false, null); 94 95 ShadowPackageManager spm = Shadows.shadowOf(mContext.getPackageManager()); 96 ComponentName cname = new ComponentName(mContext, SetupRedactionInterstitial.class); 97 final int componentEnabled = spm.getComponentEnabledSettingFlags(cname) 98 & PackageManager.COMPONENT_ENABLED_STATE_ENABLED; 99 assertThat(componentEnabled).isEqualTo(PackageManager.COMPONENT_ENABLED_STATE_ENABLED); 100 } 101 102 @Test 103 @Ignore("b/295325503") optionsButton_whenPatternSelected_shouldBeVisible()104 public void optionsButton_whenPatternSelected_shouldBeVisible() { 105 final Button button = mActivity.findViewById(R.id.screen_lock_options); 106 assertThat(button).isNotNull(); 107 assertThat(button.getVisibility()).isEqualTo(View.VISIBLE); 108 109 final LockPatternView lockPatternView = mActivity.findViewById(R.id.lockPattern); 110 ReflectionHelpers.callInstanceMethod(lockPatternView, "notifyPatternDetected"); 111 112 enterPattern(); 113 assertThat(button.getVisibility()).isEqualTo(View.VISIBLE); 114 } 115 verifyScreenLockOptionsShown()116 private void verifyScreenLockOptionsShown() { 117 final Button button = mActivity.findViewById(R.id.screen_lock_options); 118 assertThat(button).isNotNull(); 119 assertThat(button.getVisibility()).isEqualTo(View.VISIBLE); 120 121 button.performClick(); 122 final AlertDialog chooserDialog = ShadowAlertDialogCompat.getLatestAlertDialog(); 123 assertThat(chooserDialog).isNotNull(); 124 int count = chooserDialog.getListView().getCount(); 125 assertWithMessage("List items shown").that(count).isEqualTo(3); 126 } 127 128 @Config(qualifiers = "sw400dp") 129 @Test 130 @Ignore("b/295325503") sw400dp_shouldShowScreenLockOptions()131 public void sw400dp_shouldShowScreenLockOptions() { 132 verifyScreenLockOptionsShown(); 133 } 134 135 @Config(qualifiers = "sw400dp-land") 136 @Test 137 @Ignore("b/295325503") sw400dpLandscape_shouldShowScreenLockOptions()138 public void sw400dpLandscape_shouldShowScreenLockOptions() { 139 verifyScreenLockOptionsShown(); 140 } 141 verifyScreenLockOptionsHidden()142 private void verifyScreenLockOptionsHidden() { 143 Button button = mActivity.findViewById(R.id.screen_lock_options); 144 assertThat(button).isNotNull(); 145 assertThat(button.getVisibility()).isEqualTo(View.GONE); 146 } 147 148 @Config(qualifiers = "sw300dp") 149 @Test 150 @Ignore("b/295325503") smallScreens_shouldHideScreenLockOptions()151 public void smallScreens_shouldHideScreenLockOptions() { 152 verifyScreenLockOptionsHidden(); 153 } 154 155 @Config(qualifiers = "sw300dp-land") 156 @Test 157 @Ignore("b/295325503") smallScreensLandscape_shouldHideScreenLockOptions()158 public void smallScreensLandscape_shouldHideScreenLockOptions() { 159 verifyScreenLockOptionsHidden(); 160 } 161 162 @Test 163 @Ignore("b/295325503") skipButton_shouldBeVisible_duringNonFingerprintFlow()164 public void skipButton_shouldBeVisible_duringNonFingerprintFlow() { 165 final PartnerCustomizationLayout layout = mActivity.findViewById(R.id.setup_wizard_layout); 166 final Button skipOrClearButton = 167 layout.getMixin(FooterBarMixin.class).getSecondaryButtonView(); 168 169 assertThat(skipOrClearButton).isNotNull(); 170 assertThat(skipOrClearButton.getVisibility()).isEqualTo(View.VISIBLE); 171 172 skipOrClearButton.performClick(); 173 AlertDialog chooserDialog = ShadowAlertDialogCompat.getLatestAlertDialog(); 174 assertThat(chooserDialog).isNotNull(); 175 } 176 177 @Test clearButton_shouldBeVisible_duringRetryStage()178 public void clearButton_shouldBeVisible_duringRetryStage() { 179 enterPattern(); 180 181 final PartnerCustomizationLayout layout = mActivity.findViewById(R.id.setup_wizard_layout); 182 final Button skipOrClearButton = 183 layout.getMixin(FooterBarMixin.class).getSecondaryButtonView(); 184 185 assertThat(skipOrClearButton.getVisibility()).isEqualTo(View.VISIBLE); 186 assertThat(skipOrClearButton.isEnabled()).isTrue(); 187 188 skipOrClearButton.performClick(); 189 190 assertThat(findFragment(mActivity).mChosenPattern).isNull(); 191 } 192 193 @Test createActivity_enterPattern_clearButtonShouldBeShown()194 public void createActivity_enterPattern_clearButtonShouldBeShown() { 195 final PartnerCustomizationLayout layout = mActivity.findViewById(R.id.setup_wizard_layout); 196 final Button skipOrClearButton = 197 layout.getMixin(FooterBarMixin.class).getSecondaryButtonView(); 198 199 assertThat(skipOrClearButton.isEnabled()).isTrue(); 200 assertThat(skipOrClearButton.getVisibility()).isEqualTo(View.VISIBLE); 201 assertThat(skipOrClearButton.getText()) 202 .isEqualTo(mContext.getString(R.string.skip_label)); 203 204 enterPattern(); 205 206 assertThat(skipOrClearButton.isEnabled()).isTrue(); 207 assertThat(skipOrClearButton.getVisibility()).isEqualTo(View.VISIBLE); 208 assertThat(skipOrClearButton.getText()) 209 .isEqualTo(mContext.getString(R.string.lockpattern_retry_button_text)); 210 } 211 212 @Test createActivity_patternDescription_shouldBeShown()213 public void createActivity_patternDescription_shouldBeShown() { 214 final PartnerCustomizationLayout layout = mActivity.findViewById(R.id.setup_wizard_layout); 215 final TextView patternDescription = 216 layout.findViewById(R.id.sud_layout_subtitle); 217 218 assertThat(patternDescription.getVisibility()).isEqualTo(View.VISIBLE); 219 assertThat(patternDescription.getText()).isEqualTo( 220 mContext.getString(R.string.lockpassword_choose_your_pattern_description)); 221 } 222 223 @Test createActivity_patternTitle_shouldShowGenericText()224 public void createActivity_patternTitle_shouldShowGenericText() { 225 final CharSequence headerView = mActivity.getTitle(); 226 227 assertThat(headerView).isEqualTo( 228 mContext.getString(R.string.lockpassword_choose_your_pattern_header)); 229 } 230 231 @Test inIntroductionStage_theHeaderHeight_shouldSetMinLinesTwoToPreventFlicker()232 public void inIntroductionStage_theHeaderHeight_shouldSetMinLinesTwoToPreventFlicker() { 233 final PartnerCustomizationLayout layout = mActivity.findViewById(R.id.setup_wizard_layout); 234 final TextView headerView = layout.findViewById(R.id.sud_layout_subtitle); 235 236 assertThat(headerView.getVisibility()).isEqualTo(View.VISIBLE); 237 assertThat(headerView.getText().toString()).isEqualTo( 238 mContext.getString(R.string.lockpassword_choose_your_pattern_description)); 239 } 240 241 @Test createActivity_enterPattern_shouldGoToFirstChoiceValidStage()242 public void createActivity_enterPattern_shouldGoToFirstChoiceValidStage() { 243 final PartnerCustomizationLayout layout = mActivity.findViewById(R.id.setup_wizard_layout); 244 final TextView headerView = layout.findViewById(R.id.sud_layout_subtitle); 245 246 assertThat(headerView.getVisibility()).isEqualTo(View.VISIBLE); 247 248 enterPattern(); 249 250 assertThat(headerView.getText().toString()).isEqualTo( 251 mContext.getString(R.string.lockpattern_pattern_entered_header)); 252 } 253 254 @Test createActivity_enterShortPattern_shouldGoToChoiceTooShortStage()255 public void createActivity_enterShortPattern_shouldGoToChoiceTooShortStage() { 256 final PartnerCustomizationLayout layout = mActivity.findViewById(R.id.setup_wizard_layout); 257 final TextView headerView = layout.findViewById(R.id.sud_layout_subtitle); 258 259 enterShortPattern(); 260 261 assertThat(headerView.getVisibility()).isEqualTo(View.VISIBLE); 262 assertThat(headerView.getText().toString()).isEqualTo( 263 mContext.getResources().getString( 264 R.string.lockpattern_recording_incorrect_too_short, 265 LockPatternUtils.MIN_LOCK_PATTERN_SIZE)); 266 } 267 268 @Test inChoiceTooShortStage_theHeaderColor_shouldTintOnErrorColor()269 public void inChoiceTooShortStage_theHeaderColor_shouldTintOnErrorColor() { 270 final PartnerCustomizationLayout layout = mActivity.findViewById(R.id.setup_wizard_layout); 271 final TextView headerView = layout.findViewById(R.id.sud_layout_subtitle); 272 final TypedValue typedValue = new TypedValue(); 273 final Resources.Theme theme = mActivity.getTheme(); 274 theme.resolveAttribute(androidx.appcompat.R.attr.colorError, typedValue, true); 275 final int errorColor = typedValue.data; 276 277 enterShortPattern(); 278 279 assertThat(headerView.getVisibility()).isEqualTo(View.VISIBLE); 280 assertThat(headerView.getTextColors().getDefaultColor()).isEqualTo(errorColor); 281 } 282 283 @Test inFirstChoiceValidStage_nextButtonState_shouldEnabled()284 public void inFirstChoiceValidStage_nextButtonState_shouldEnabled() { 285 final PartnerCustomizationLayout layout = mActivity.findViewById(R.id.setup_wizard_layout); 286 final FooterBarMixin footerBarMixin = layout.getMixin(FooterBarMixin.class); 287 final FooterButton nextButton = footerBarMixin.getPrimaryButton(); 288 289 assertThat(nextButton.getVisibility()).isEqualTo(View.VISIBLE); 290 assertThat(nextButton.isEnabled()).isFalse(); 291 292 enterPattern(); 293 294 assertThat(nextButton.isEnabled()).isTrue(); 295 } 296 297 @Test inFirstChoiceValidStage_clickNextButton_shouldGoToNeedToConfirmStage()298 public void inFirstChoiceValidStage_clickNextButton_shouldGoToNeedToConfirmStage() { 299 final PartnerCustomizationLayout layout = mActivity.findViewById(R.id.setup_wizard_layout); 300 final TextView headerView = layout.findViewById(R.id.sud_layout_subtitle); 301 final FooterBarMixin footerBarMixin = layout.getMixin(FooterBarMixin.class); 302 final Button nextButton = footerBarMixin.getPrimaryButtonView(); 303 304 assertThat(headerView.getVisibility()).isEqualTo(View.VISIBLE); 305 306 enterPattern(); 307 nextButton.performClick(); 308 309 assertThat(headerView.getText().toString()).isEqualTo( 310 mContext.getString(R.string.lockpattern_need_to_confirm)); 311 } 312 313 @Test inNeedToConfirmStage_enterWrongPattern_shouldGoToConfirmWrongStage()314 public void inNeedToConfirmStage_enterWrongPattern_shouldGoToConfirmWrongStage() { 315 final PartnerCustomizationLayout layout = mActivity.findViewById(R.id.setup_wizard_layout); 316 final TextView headerView = layout.findViewById(R.id.sud_layout_subtitle); 317 final FooterBarMixin footerBarMixin = layout.getMixin(FooterBarMixin.class); 318 final Button nextButton = footerBarMixin.getPrimaryButtonView(); 319 // IntroductionStage 320 assertThat(headerView.getVisibility()).isEqualTo(View.VISIBLE); 321 322 enterPattern(); 323 nextButton.performClick(); 324 325 // NeedToConfirmStage 326 assertThat(headerView.getText().toString()).isEqualTo( 327 mContext.getString(R.string.lockpattern_need_to_confirm)); 328 329 enterShortPattern(); 330 331 // ConfirmWrongStage 332 assertThat(headerView.getText().toString()).isEqualTo( 333 mContext.getString(R.string.lockpattern_need_to_unlock_wrong)); 334 assertThat(nextButton.getText().toString()).isEqualTo( 335 mContext.getString(R.string.lockpattern_confirm_button_text)); 336 assertThat(nextButton.isEnabled()).isFalse(); 337 } 338 339 @Test inNeedToConfirmStage_enterCorrectPattern_shouldGoToChoiceConfirmedStage()340 public void inNeedToConfirmStage_enterCorrectPattern_shouldGoToChoiceConfirmedStage() { 341 final PartnerCustomizationLayout layout = mActivity.findViewById(R.id.setup_wizard_layout); 342 final TextView headerView = layout.findViewById(R.id.sud_layout_subtitle); 343 final FooterBarMixin footerBarMixin = layout.getMixin(FooterBarMixin.class); 344 final Button nextButton = footerBarMixin.getPrimaryButtonView(); 345 // IntroductionStage 346 assertThat(headerView.getVisibility()).isEqualTo(View.VISIBLE); 347 348 enterPattern(); 349 nextButton.performClick(); 350 351 // NeedToConfirmStage 352 assertThat(headerView.getText().toString()).isEqualTo( 353 mContext.getString(R.string.lockpattern_need_to_confirm)); 354 355 enterPattern(); 356 357 // ChoiceConfirmedStage 358 assertThat(headerView.getText().toString()).isEqualTo( 359 mContext.getString(R.string.lockpattern_pattern_confirmed_header)); 360 assertThat(nextButton.getText().toString()).isEqualTo( 361 mContext.getString(R.string.lockpattern_confirm_button_text)); 362 assertThat(nextButton.isEnabled()).isTrue(); 363 } 364 findFragment(FragmentActivity activity)365 private ChooseLockPatternFragment findFragment(FragmentActivity activity) { 366 return (ChooseLockPatternFragment) 367 activity.getSupportFragmentManager().findFragmentById(R.id.main_content); 368 } 369 enterPattern()370 private void enterPattern() { 371 LockPatternView lockPatternView = mActivity.findViewById(R.id.lockPattern); 372 lockPatternView.setPattern( 373 DisplayMode.Animate, 374 Arrays.asList( 375 createCell(0, 0), 376 createCell(0, 1), 377 createCell(1, 1), 378 createCell(1, 0))); 379 ReflectionHelpers.callInstanceMethod(lockPatternView, "notifyPatternDetected"); 380 } 381 enterShortPattern()382 private void enterShortPattern() { 383 LockPatternView lockPatternView = mActivity.findViewById(R.id.lockPattern); 384 lockPatternView.setPattern( 385 DisplayMode.Animate, 386 Arrays.asList( 387 createCell(0, 0), 388 createCell(0, 1), 389 createCell(1, 1))); 390 ReflectionHelpers.callInstanceMethod(lockPatternView, "notifyPatternDetected"); 391 } 392 createCell(int row, int column)393 private Cell createCell(int row, int column) { 394 return ReflectionHelpers.callConstructor( 395 Cell.class, 396 ClassParameter.from(int.class, row), 397 ClassParameter.from(int.class, column)); 398 } 399 } 400