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