1 /*
2  * Copyright (C) 2019 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.accessibility;
18 
19 import static com.android.settings.accessibility.AccessibilityUtil.State.ON;
20 import static com.android.settings.accessibility.MagnificationCapabilities.MagnificationMode;
21 import static com.android.settings.accessibility.MagnificationModePreferenceController.MagnificationModeInfo;
22 
23 import static com.google.common.truth.Truth.assertThat;
24 
25 import static org.mockito.Mockito.never;
26 import static org.mockito.Mockito.verify;
27 
28 import android.app.Dialog;
29 import android.content.Context;
30 import android.content.DialogInterface;
31 import android.os.Bundle;
32 import android.provider.Settings;
33 import android.text.SpannableString;
34 import android.text.TextUtils;
35 import android.view.View;
36 import android.widget.AdapterView;
37 import android.widget.ListView;
38 import android.widget.TextView;
39 
40 import androidx.preference.Preference;
41 import androidx.preference.PreferenceManager;
42 import androidx.preference.PreferenceScreen;
43 import androidx.test.core.app.ApplicationProvider;
44 
45 import com.android.settings.DialogCreatable;
46 import com.android.settings.R;
47 import com.android.settings.utils.AnnotationSpan;
48 
49 import org.junit.Before;
50 import org.junit.Rule;
51 import org.junit.Test;
52 import org.junit.runner.RunWith;
53 import org.mockito.Spy;
54 import org.mockito.junit.MockitoJUnit;
55 import org.mockito.junit.MockitoRule;
56 import org.robolectric.RobolectricTestRunner;
57 
58 /** Tests for {@link MagnificationModePreferenceController}. */
59 @RunWith(RobolectricTestRunner.class)
60 public class MagnificationModePreferenceControllerTest {
61     private static final String PREF_KEY = "screen_magnification_mode";
62     private static final int MAGNIFICATION_MODE_DEFAULT = MagnificationMode.ALL;
63 
64     @Rule
65     public MockitoRule mocks = MockitoJUnit.rule();
66 
67     private PreferenceScreen mScreen;
68     private Context mContext;
69     private MagnificationModePreferenceController mController;
70     private Preference mModePreference;
71     @Spy
72     private TestDialogHelper mDialogHelper = new TestDialogHelper();
73 
74     @Before
setUp()75     public void setUp() {
76         mContext = ApplicationProvider.getApplicationContext();
77         mContext.setTheme(androidx.appcompat.R.style.Theme_AppCompat);
78         final PreferenceManager preferenceManager = new PreferenceManager(mContext);
79         mScreen = preferenceManager.createPreferenceScreen(mContext);
80         mModePreference = new Preference(mContext);
81         mModePreference.setKey(PREF_KEY);
82         mScreen.addPreference(mModePreference);
83         MagnificationCapabilities.setCapabilities(mContext, MAGNIFICATION_MODE_DEFAULT);
84         mController = new MagnificationModePreferenceController(mContext, PREF_KEY);
85         showPreferenceOnTheScreen(null);
86     }
87 
88     @Test
clickPreference_settingsModeIsDefault_checkedModeInDialogIsDefault()89     public void clickPreference_settingsModeIsDefault_checkedModeInDialogIsDefault() {
90         mModePreference.getOnPreferenceClickListener().onPreferenceClick(mModePreference);
91 
92         assertThat(getCheckedModeFromDialog()).isEqualTo(MAGNIFICATION_MODE_DEFAULT);
93     }
94 
95     @Test
choseModeIsDifferentFromInSettings_checkedModeInDialogIsExpected()96     public void choseModeIsDifferentFromInSettings_checkedModeInDialogIsExpected() {
97         mModePreference.getOnPreferenceClickListener().onPreferenceClick(mModePreference);
98 
99         performItemClickWith(MagnificationMode.WINDOW);
100 
101         assertThat(getCheckedModeFromDialog()).isEqualTo(MagnificationMode.WINDOW);
102     }
103 
104     @Test
dialogIsReCreated_settingsModeIsAllAndChoseWindowMode_checkedModeIsWindow()105     public void dialogIsReCreated_settingsModeIsAllAndChoseWindowMode_checkedModeIsWindow() {
106         mModePreference.getOnPreferenceClickListener().onPreferenceClick(mModePreference);
107         performItemClickWith(MagnificationMode.WINDOW);
108 
109         reshowPreferenceOnTheScreen();
110         mDialogHelper.showDialog(MagnificationModePreferenceController.DIALOG_MAGNIFICATION_MODE);
111 
112         assertThat(getCheckedModeFromDialog()).isEqualTo(
113                 MagnificationMode.WINDOW);
114     }
115 
116     @Test
chooseFullscreenMode_tripleTapEnabled_notShowTripleTapWarningDialog()117     public void chooseFullscreenMode_tripleTapEnabled_notShowTripleTapWarningDialog() {
118         enableTripleTap();
119         mModePreference.getOnPreferenceClickListener().onPreferenceClick(mModePreference);
120 
121         performItemClickWith(MagnificationMode.FULLSCREEN);
122         mController.onMagnificationModeDialogPositiveButtonClicked(mDialogHelper.getDialog(),
123                 DialogInterface.BUTTON_POSITIVE);
124 
125         verify(mDialogHelper, never()).showDialog(
126                 MagnificationModePreferenceController.DIALOG_MAGNIFICATION_TRIPLE_TAP_WARNING);
127     }
128 
129     @Test
chooseWindowMode_tripleTapEnabled_showTripleTapWarningDialog()130     public void chooseWindowMode_tripleTapEnabled_showTripleTapWarningDialog() {
131         enableTripleTap();
132         mModePreference.getOnPreferenceClickListener().onPreferenceClick(mModePreference);
133 
134         performItemClickWith(MagnificationMode.WINDOW);
135         mController.onMagnificationModeDialogPositiveButtonClicked(mDialogHelper.getDialog(),
136                 DialogInterface.BUTTON_POSITIVE);
137 
138         verify(mDialogHelper).showDialog(
139                 MagnificationModePreferenceController.DIALOG_MAGNIFICATION_TRIPLE_TAP_WARNING);
140     }
141 
142     @Test
chooseAllMode_tripleTapEnabled_showTripleTapWarningDialog()143     public void chooseAllMode_tripleTapEnabled_showTripleTapWarningDialog() {
144         enableTripleTap();
145         mModePreference.getOnPreferenceClickListener().onPreferenceClick(mModePreference);
146 
147         performItemClickWith(MagnificationMode.ALL);
148         mController.onMagnificationModeDialogPositiveButtonClicked(mDialogHelper.getDialog(),
149                 DialogInterface.BUTTON_POSITIVE);
150 
151         verify(mDialogHelper).showDialog(
152                 MagnificationModePreferenceController.DIALOG_MAGNIFICATION_TRIPLE_TAP_WARNING);
153     }
154 
155     @Test
onTripleTapWarningDialogNegativeButtonClicked_showModeDialog()156     public void onTripleTapWarningDialogNegativeButtonClicked_showModeDialog() {
157         mDialogHelper.showDialog(
158                 MagnificationModePreferenceController.DIALOG_MAGNIFICATION_TRIPLE_TAP_WARNING);
159 
160         mController.onMagnificationTripleTapWarningDialogNegativeButtonClicked(
161                 mDialogHelper.getDialog(), DialogInterface.BUTTON_NEGATIVE);
162 
163         verify(mDialogHelper).showDialog(
164                 MagnificationModePreferenceController.DIALOG_MAGNIFICATION_MODE);
165     }
166 
167     @Test
onTripleTapWarningDialogPositiveButtonClicked_chooseAllMode_returnAllSummary()168     public void onTripleTapWarningDialogPositiveButtonClicked_chooseAllMode_returnAllSummary() {
169         enableTripleTap();
170         mModePreference.getOnPreferenceClickListener().onPreferenceClick(mModePreference);
171         performItemClickWith(MagnificationMode.ALL);
172         mController.onMagnificationModeDialogPositiveButtonClicked(mDialogHelper.getDialog(),
173                 DialogInterface.BUTTON_POSITIVE);
174 
175         mController.onMagnificationTripleTapWarningDialogPositiveButtonClicked(
176                 mDialogHelper.getDialog(), DialogInterface.BUTTON_POSITIVE);
177 
178         final String allSummary = mContext.getString(
179                 R.string.accessibility_magnification_area_settings_all_summary);
180         assertThat(TextUtils.equals(mController.getSummary(), allSummary)).isTrue();
181     }
182 
183     @Test
checkSpansInTripleTapWarningDialog_existAnnotationSpan()184     public void checkSpansInTripleTapWarningDialog_existAnnotationSpan() {
185         mDialogHelper.showDialog(
186                 MagnificationModePreferenceController.DIALOG_MAGNIFICATION_TRIPLE_TAP_WARNING);
187         final View contentView = mDialogHelper.getDialog().findViewById(android.R.id.content);
188         final TextView messageView = contentView.findViewById(R.id.message);
189         final CharSequence textInTripleTapWarningDialog = messageView.getText();
190 
191         final AnnotationSpan[] annotationSpans =
192                 ((SpannableString) textInTripleTapWarningDialog).getSpans(/*queryStart= */ 0,
193                         textInTripleTapWarningDialog.length(), AnnotationSpan.class);
194 
195         assertThat(annotationSpans[0]).isNotNull();
196     }
197 
198     @Test
getSummary_saveWindowScreen_shouldReturnWindowScreenSummary()199     public void getSummary_saveWindowScreen_shouldReturnWindowScreenSummary() {
200         MagnificationCapabilities.setCapabilities(mContext, MagnificationMode.WINDOW);
201 
202         final String windowSummary = mContext.getString(
203                 R.string.accessibility_magnification_area_settings_window_screen_summary);
204         assertThat(TextUtils.equals(mController.getSummary(), windowSummary)).isTrue();
205     }
206 
207     @Test
getSummary_saveAll_shouldReturnAllSummary()208     public void getSummary_saveAll_shouldReturnAllSummary() {
209         MagnificationCapabilities.setCapabilities(mContext, MagnificationMode.ALL);
210 
211         final String allSummary = mContext.getString(
212                 R.string.accessibility_magnification_area_settings_all_summary);
213         assertThat(TextUtils.equals(mController.getSummary(), allSummary)).isTrue();
214     }
215 
getCheckedModeFromDialog()216     private int getCheckedModeFromDialog() {
217         final ListView listView = mController.mMagnificationModesListView;
218         assertThat(listView).isNotNull();
219 
220         final int checkedPosition = listView.getCheckedItemPosition();
221         final MagnificationModeInfo modeInfo =
222                 (MagnificationModeInfo) listView.getAdapter().getItem(checkedPosition);
223         return modeInfo.mMagnificationMode;
224     }
225 
performItemClickWith(@agnificationMode int mode)226     private void performItemClickWith(@MagnificationMode int mode) {
227         final ListView listView = mController.mMagnificationModesListView;
228         assertThat(listView).isNotNull();
229 
230         int modeIndex = AdapterView.NO_ID;
231         // Index 0 is header.
232         for (int i = 1; i < listView.getAdapter().getCount(); i++) {
233             final MagnificationModeInfo modeInfo =
234                     (MagnificationModeInfo) listView.getAdapter().getItem(i);
235             if (modeInfo.mMagnificationMode == mode) {
236                 modeIndex = i;
237                 break;
238             }
239         }
240         if (modeIndex == AdapterView.NO_ID) {
241             throw new RuntimeException("The mode is not in the list.");
242         }
243 
244         listView.performItemClick(listView.getChildAt(modeIndex), modeIndex, modeIndex);
245     }
246 
enableTripleTap()247     private void enableTripleTap() {
248         Settings.Secure.putInt(mContext.getContentResolver(),
249                 Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED, ON);
250     }
251 
reshowPreferenceOnTheScreen()252     private void reshowPreferenceOnTheScreen() {
253         final Bundle bundle = new Bundle();
254         mController.onSaveInstanceState(bundle);
255         showPreferenceOnTheScreen(bundle);
256     }
257 
showPreferenceOnTheScreen(Bundle savedInstanceState)258     private void showPreferenceOnTheScreen(Bundle savedInstanceState) {
259         mController.setDialogHelper(mDialogHelper);
260         mController.onCreate(savedInstanceState);
261         mController.displayPreference(mScreen);
262     }
263 
264     private static class TestDialogHelper implements DialogCreatable,
265             MagnificationModePreferenceController.DialogHelper {
266         private DialogCreatable mDialogDelegate;
267         private Dialog mDialog;
268 
269         @Override
showDialog(int dialogId)270         public void showDialog(int dialogId) {
271             mDialog = onCreateDialog(dialogId);
272         }
273 
274         @Override
setDialogDelegate(DialogCreatable delegate)275         public void setDialogDelegate(DialogCreatable delegate) {
276             mDialogDelegate = delegate;
277         }
278 
279         @Override
onCreateDialog(int dialogId)280         public Dialog onCreateDialog(int dialogId) {
281             return mDialogDelegate.onCreateDialog(dialogId);
282         }
283 
284         @Override
getDialogMetricsCategory(int dialogId)285         public int getDialogMetricsCategory(int dialogId) {
286             return mDialogDelegate.getDialogMetricsCategory(dialogId);
287         }
288 
getDialog()289         public Dialog getDialog() {
290             return mDialog;
291         }
292     }
293 }
294