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.os.UserHandle;
28 import android.view.View;
29 import android.widget.Button;
30 
31 import androidx.appcompat.app.AlertDialog;
32 import androidx.fragment.app.FragmentActivity;
33 
34 import com.android.internal.widget.LockPatternView;
35 import com.android.internal.widget.LockPatternView.Cell;
36 import com.android.internal.widget.LockPatternView.DisplayMode;
37 import com.android.settings.R;
38 import com.android.settings.SetupRedactionInterstitial;
39 import com.android.settings.password.ChooseLockPattern.ChooseLockPatternFragment;
40 import com.android.settings.password.ChooseLockPattern.IntentBuilder;
41 import com.android.settings.testutils.shadow.ShadowAlertDialogCompat;
42 import com.android.settings.testutils.shadow.ShadowLockPatternUtils;
43 import com.android.settings.testutils.shadow.ShadowUtils;
44 
45 import com.google.android.setupcompat.PartnerCustomizationLayout;
46 import com.google.android.setupcompat.template.FooterBarMixin;
47 
48 import org.junit.Before;
49 import org.junit.Test;
50 import org.junit.runner.RunWith;
51 import org.robolectric.RobolectricTestRunner;
52 import org.robolectric.Shadows;
53 import org.robolectric.android.controller.ActivityController;
54 import org.robolectric.annotation.Config;
55 import org.robolectric.shadows.ShadowPackageManager;
56 import org.robolectric.util.ReflectionHelpers;
57 import org.robolectric.util.ReflectionHelpers.ClassParameter;
58 
59 import java.util.Arrays;
60 
61 @RunWith(RobolectricTestRunner.class)
62 @Config(shadows = {ShadowUtils.class, ShadowAlertDialogCompat.class, ShadowLockPatternUtils.class})
63 public class SetupChooseLockPatternTest {
64 
65     private SetupChooseLockPattern mActivity;
66 
67     @Before
setUp()68     public void setUp() {
69         application.getPackageManager().setComponentEnabledSetting(
70                 new ComponentName(application, SetupRedactionInterstitial.class),
71                 PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
72                 PackageManager.DONT_KILL_APP);
73 
74         final Intent intent =
75                 SetupChooseLockPattern.modifyIntentForSetup(
76                         application,
77                         new IntentBuilder(application)
78                                 .setUserId(UserHandle.myUserId())
79                                 .build());
80         mActivity = ActivityController.of(new SetupChooseLockPattern(), intent).setup().get();
81     }
82 
83     @Test
chooseLockSaved_shouldEnableRedactionInterstitial()84     public void chooseLockSaved_shouldEnableRedactionInterstitial() {
85         findFragment(mActivity).onChosenLockSaveFinished(false, null);
86 
87         ShadowPackageManager spm = Shadows.shadowOf(application.getPackageManager());
88         ComponentName cname = new ComponentName(application, SetupRedactionInterstitial.class);
89         final int componentEnabled = spm.getComponentEnabledSettingFlags(cname)
90                 & PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
91         assertThat(componentEnabled).isEqualTo(PackageManager.COMPONENT_ENABLED_STATE_ENABLED);
92     }
93 
94     @Test
optionsButton_whenPatternSelected_shouldBeVisible()95     public void optionsButton_whenPatternSelected_shouldBeVisible() {
96         Button button = mActivity.findViewById(R.id.screen_lock_options);
97         assertThat(button).isNotNull();
98         assertThat(button.getVisibility()).isEqualTo(View.VISIBLE);
99 
100         LockPatternView lockPatternView = mActivity.findViewById(R.id.lockPattern);
101         ReflectionHelpers.callInstanceMethod(lockPatternView, "notifyPatternDetected");
102 
103         enterPattern();
104         assertThat(button.getVisibility()).isEqualTo(View.VISIBLE);
105     }
106 
verifyScreenLockOptionsShown()107     private void verifyScreenLockOptionsShown() {
108         Button button = mActivity.findViewById(R.id.screen_lock_options);
109         assertThat(button).isNotNull();
110         assertThat(button.getVisibility()).isEqualTo(View.VISIBLE);
111 
112         button.performClick();
113         AlertDialog chooserDialog = ShadowAlertDialogCompat.getLatestAlertDialog();
114         assertThat(chooserDialog).isNotNull();
115         int count = chooserDialog.getListView().getCount();
116         assertWithMessage("List items shown").that(count).isEqualTo(3);
117     }
118 
119     @Config(qualifiers = "sw400dp")
120     @Test
sw400dp_shouldShowScreenLockOptions()121     public void sw400dp_shouldShowScreenLockOptions() {
122         verifyScreenLockOptionsShown();
123     }
124 
125     @Config(qualifiers = "sw400dp-land")
126     @Test
sw400dpLandscape_shouldShowScreenLockOptions()127     public void sw400dpLandscape_shouldShowScreenLockOptions() {
128         verifyScreenLockOptionsShown();
129     }
130 
verifyScreenLockOptionsHidden()131     private void verifyScreenLockOptionsHidden() {
132         Button button = mActivity.findViewById(R.id.screen_lock_options);
133         assertThat(button).isNotNull();
134         assertThat(button.getVisibility()).isEqualTo(View.GONE);
135     }
136 
137     @Config(qualifiers = "sw300dp")
138     @Test
smallScreens_shouldHideScreenLockOptions()139     public void smallScreens_shouldHideScreenLockOptions() {
140         verifyScreenLockOptionsHidden();
141     }
142 
143     @Config(qualifiers = "sw300dp-land")
144     @Test
smallScreensLandscape_shouldHideScreenLockOptions()145     public void smallScreensLandscape_shouldHideScreenLockOptions() {
146         verifyScreenLockOptionsHidden();
147     }
148 
149     @Test
skipButton_shouldBeVisible_duringNonFingerprintFlow()150     public void skipButton_shouldBeVisible_duringNonFingerprintFlow() {
151         PartnerCustomizationLayout layout = mActivity.findViewById(R.id.setup_wizard_layout);
152         final Button skipOrClearButton =
153                 layout.getMixin(FooterBarMixin.class).getSecondaryButtonView();
154         assertThat(skipOrClearButton).isNotNull();
155         assertThat(skipOrClearButton.getVisibility()).isEqualTo(View.VISIBLE);
156 
157         skipOrClearButton.performClick();
158         AlertDialog chooserDialog = ShadowAlertDialogCompat.getLatestAlertDialog();
159         assertThat(chooserDialog).isNotNull();
160     }
161 
162     @Test
clearButton_shouldBeVisible_duringRetryStage()163     public void clearButton_shouldBeVisible_duringRetryStage() {
164         enterPattern();
165 
166         PartnerCustomizationLayout layout = mActivity.findViewById(R.id.setup_wizard_layout);
167         final Button skipOrClearButton =
168                 layout.getMixin(FooterBarMixin.class).getSecondaryButtonView();
169         assertThat(skipOrClearButton.getVisibility()).isEqualTo(View.VISIBLE);
170         assertThat(skipOrClearButton.isEnabled()).isTrue();
171 
172         skipOrClearButton.performClick();
173         assertThat(findFragment(mActivity).mChosenPattern).isNull();
174     }
175 
176     @Test
createActivity_enterPattern_clearButtonShouldBeShown()177     public void createActivity_enterPattern_clearButtonShouldBeShown() {
178         ChooseLockPatternFragment fragment = findFragment(mActivity);
179 
180         PartnerCustomizationLayout layout = mActivity.findViewById(R.id.setup_wizard_layout);
181         final Button skipOrClearButton =
182                 layout.getMixin(FooterBarMixin.class).getSecondaryButtonView();
183         assertThat(skipOrClearButton.isEnabled()).isTrue();
184         assertThat(skipOrClearButton.getVisibility()).isEqualTo(View.VISIBLE);
185         assertThat(skipOrClearButton.getText())
186                 .isEqualTo(application.getString(R.string.skip_label));
187 
188         enterPattern();
189         assertThat(skipOrClearButton.isEnabled()).isTrue();
190         assertThat(skipOrClearButton.getVisibility()).isEqualTo(View.VISIBLE);
191         assertThat(skipOrClearButton.getText())
192                 .isEqualTo(application.getString(R.string.lockpattern_retry_button_text));
193     }
194 
findFragment(FragmentActivity activity)195     private ChooseLockPatternFragment findFragment(FragmentActivity activity) {
196         return (ChooseLockPatternFragment)
197                 activity.getSupportFragmentManager().findFragmentById(R.id.main_content);
198     }
199 
enterPattern()200     private void enterPattern() {
201         LockPatternView lockPatternView = mActivity.findViewById(R.id.lockPattern);
202         lockPatternView.setPattern(
203                 DisplayMode.Animate,
204                 Arrays.asList(
205                         createCell(0, 0),
206                         createCell(0, 1),
207                         createCell(1, 1),
208                         createCell(1, 0)));
209         ReflectionHelpers.callInstanceMethod(lockPatternView, "notifyPatternDetected");
210     }
211 
createCell(int row, int column)212     private Cell createCell(int row, int column) {
213         return ReflectionHelpers.callConstructor(
214                 Cell.class,
215                 ClassParameter.from(int.class, row),
216                 ClassParameter.from(int.class, column));
217     }
218 }
219