1 /*
2  * Copyright (C) 2020 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.OFF;
20 import static com.android.settings.accessibility.AccessibilityUtil.State.ON;
21 import static com.android.settings.accessibility.AccessibilityUtil.UserShortcutType;
22 import static com.android.settings.accessibility.MagnificationCapabilities.MagnificationMode;
23 import static com.android.settings.accessibility.ToggleFeaturePreferenceFragment.KEY_SAVED_USER_SHORTCUT_TYPE;
24 
25 import static com.google.common.truth.Truth.assertThat;
26 
27 import static org.junit.Assert.assertTrue;
28 import static org.mockito.ArgumentMatchers.anyInt;
29 import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
30 import static org.mockito.Mockito.mock;
31 import static org.mockito.Mockito.spy;
32 import static org.mockito.Mockito.verify;
33 import static org.mockito.Mockito.verifyNoMoreInteractions;
34 import static org.mockito.Mockito.when;
35 
36 import android.app.settings.SettingsEnums;
37 import android.content.ComponentName;
38 import android.content.Context;
39 import android.content.DialogInterface;
40 import android.content.pm.PackageManager;
41 import android.content.res.Resources;
42 import android.database.ContentObserver;
43 import android.icu.text.CaseMap;
44 import android.net.Uri;
45 import android.os.Bundle;
46 import android.os.UserHandle;
47 import android.platform.test.annotations.DisableFlags;
48 import android.platform.test.annotations.EnableFlags;
49 import android.platform.test.flag.junit.SetFlagsRule;
50 import android.provider.DeviceConfig;
51 import android.provider.Settings;
52 import android.view.accessibility.AccessibilityManager;
53 
54 import androidx.appcompat.app.AlertDialog;
55 import androidx.preference.Preference;
56 import androidx.preference.TwoStatePreference;
57 import androidx.test.core.app.ApplicationProvider;
58 
59 import com.android.server.accessibility.Flags;
60 import com.android.settings.DialogCreatable;
61 import com.android.settings.R;
62 import com.android.settings.SettingsActivity;
63 import com.android.settings.accessibility.AccessibilityDialogUtils.DialogType;
64 import com.android.settings.testutils.AccessibilityTestUtils;
65 import com.android.settings.testutils.shadow.ShadowDeviceConfig;
66 import com.android.settings.testutils.shadow.ShadowStorageManager;
67 import com.android.settings.testutils.shadow.ShadowUserManager;
68 import com.android.settingslib.core.lifecycle.LifecycleObserver;
69 
70 import com.google.common.truth.Correspondence;
71 
72 import org.junit.After;
73 import org.junit.Before;
74 import org.junit.Rule;
75 import org.junit.Test;
76 import org.junit.runner.RunWith;
77 import org.robolectric.RobolectricTestRunner;
78 import org.robolectric.Shadows;
79 import org.robolectric.annotation.Config;
80 import org.robolectric.shadows.ShadowContentResolver;
81 import org.robolectric.shadows.ShadowPackageManager;
82 import org.robolectric.shadows.ShadowSettings;
83 import org.robolectric.shadows.androidx.fragment.FragmentController;
84 import org.robolectric.util.ReflectionHelpers;
85 
86 import java.util.Collection;
87 import java.util.List;
88 import java.util.Locale;
89 import java.util.Set;
90 
91 /** Tests for {@link ToggleScreenMagnificationPreferenceFragment}. */
92 @RunWith(RobolectricTestRunner.class)
93 @Config(shadows = {
94         ShadowUserManager.class,
95         ShadowStorageManager.class,
96         ShadowSettings.ShadowSecure.class,
97         ShadowDeviceConfig.class,
98 })
99 public class ToggleScreenMagnificationPreferenceFragmentTest {
100 
101     @Rule
102     public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
103 
104     private static final String PLACEHOLDER_PACKAGE_NAME = "com.mock.example";
105     private static final String PLACEHOLDER_CLASS_NAME =
106             PLACEHOLDER_PACKAGE_NAME + ".mock_a11y_service";
107     private static final ComponentName PLACEHOLDER_COMPONENT_NAME = new ComponentName(
108             PLACEHOLDER_PACKAGE_NAME, PLACEHOLDER_CLASS_NAME);
109     private static final String PLACEHOLDER_DIALOG_TITLE = "title";
110 
111     private static final String SOFTWARE_SHORTCUT_KEY =
112             Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS;
113     private static final String HARDWARE_SHORTCUT_KEY =
114             Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE;
115     private static final String TRIPLETAP_SHORTCUT_KEY =
116             Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED;
117     private static final String TWO_FINGER_TRIPLE_TAP_SHORTCUT_KEY =
118             Settings.Secure.ACCESSIBILITY_MAGNIFICATION_TWO_FINGER_TRIPLE_TAP_ENABLED;
119 
120     private static final String MAGNIFICATION_CONTROLLER_NAME =
121             "com.android.server.accessibility.MagnificationController";
122 
123     private static final String KEY_FOLLOW_TYPING =
124             Settings.Secure.ACCESSIBILITY_MAGNIFICATION_FOLLOW_TYPING_ENABLED;
125     private static final String KEY_SINGLE_FINGER_PANNING =
126             Settings.Secure.ACCESSIBILITY_SINGLE_FINGER_PANNING_ENABLED;
127     private static final String KEY_ALWAYS_ON =
128             Settings.Secure.ACCESSIBILITY_MAGNIFICATION_ALWAYS_ON_ENABLED;
129     private static final String KEY_JOYSTICK =
130             Settings.Secure.ACCESSIBILITY_MAGNIFICATION_JOYSTICK_ENABLED;
131 
132     private FragmentController<ToggleScreenMagnificationPreferenceFragment> mFragController;
133     private Context mContext;
134     private AccessibilityManager mAccessibilityManager;
135     private Resources mSpyResources;
136     private ShadowPackageManager mShadowPackageManager;
137 
138     @Before
setUpTestFragment()139     public void setUpTestFragment() {
140 
141         mContext = spy(ApplicationProvider.getApplicationContext());
142         mAccessibilityManager = AccessibilityTestUtils.setupMockAccessibilityManager(mContext);
143 
144         // Set up the fragment that support window magnification feature
145         mSpyResources = spy(mContext.getResources());
146         mShadowPackageManager = Shadows.shadowOf(mContext.getPackageManager());
147         Context spyContext = spy(mContext);
148         when(spyContext.getResources()).thenReturn(mSpyResources);
149 
150         setWindowMagnificationSupported(
151                 /* magnificationAreaSupported= */ true,
152                 /* windowMagnificationSupported= */ true);
153 
154         TestToggleScreenMagnificationPreferenceFragment fragment =
155                 new TestToggleScreenMagnificationPreferenceFragment();
156         fragment.setArguments(new Bundle());
157         fragment.setContext(spyContext);
158 
159         mFragController = FragmentController.of(fragment, SettingsActivity.class);
160     }
161 
162     @After
tearDown()163     public void tearDown() {
164         ShadowDeviceConfig.reset();
165     }
166 
167     @Test
onResume_defaultStateForMagnificationMode_preferenceShouldReturnFullScreen()168     public void onResume_defaultStateForMagnificationMode_preferenceShouldReturnFullScreen() {
169         mFragController.create(R.id.main_content, /* bundle= */ null).start().resume();
170 
171         // Default is MagnificationMode.FULLSCREEN
172         final String expected =
173                 MagnificationCapabilities.getSummary(mContext, MagnificationMode.FULLSCREEN);
174 
175         final Preference preference = mFragController.get().findPreference(
176                 MagnificationModePreferenceController.PREF_KEY);
177         assertThat(preference).isNotNull();
178         assertThat(preference.getSummary()).isEqualTo(expected);
179     }
180 
181     @Test
onResume_setMagnificationModeToAll_preferenceShouldReturnAll()182     public void onResume_setMagnificationModeToAll_preferenceShouldReturnAll() {
183         setKeyMagnificationMode(MagnificationMode.ALL);
184 
185         mFragController.create(R.id.main_content, /* bundle= */ null).start().resume();
186 
187         final String expected =
188                 MagnificationCapabilities.getSummary(mContext, MagnificationMode.ALL);
189 
190         final Preference preference = mFragController.get().findPreference(
191                 MagnificationModePreferenceController.PREF_KEY);
192         assertThat(preference).isNotNull();
193         assertThat(preference.getSummary()).isEqualTo(expected);
194     }
195 
196     @Test
onResume_defaultStateForFollowingTyping_switchPreferenceShouldReturnTrue()197     public void onResume_defaultStateForFollowingTyping_switchPreferenceShouldReturnTrue() {
198         setKeyFollowTypingEnabled(true);
199 
200         mFragController.create(R.id.main_content, /* bundle= */ null).start().resume();
201 
202         final TwoStatePreference switchPreference = mFragController.get().findPreference(
203                 MagnificationFollowTypingPreferenceController.PREF_KEY);
204         assertThat(switchPreference).isNotNull();
205         assertThat(switchPreference.isChecked()).isTrue();
206     }
207 
208     @Test
onResume_disableFollowingTyping_switchPreferenceShouldReturnFalse()209     public void onResume_disableFollowingTyping_switchPreferenceShouldReturnFalse() {
210         setKeyFollowTypingEnabled(false);
211 
212         mFragController.create(R.id.main_content, /* bundle= */ null).start().resume();
213 
214         final TwoStatePreference switchPreference = mFragController.get().findPreference(
215                 MagnificationFollowTypingPreferenceController.PREF_KEY);
216         assertThat(switchPreference).isNotNull();
217         assertThat(switchPreference.isChecked()).isFalse();
218     }
219 
220     @Test
221     @EnableFlags(Flags.FLAG_ENABLE_MAGNIFICATION_ONE_FINGER_PANNING_GESTURE)
onResume_defaultStateForOneFingerPan_switchPreferenceShouldReturnFalse()222     public void onResume_defaultStateForOneFingerPan_switchPreferenceShouldReturnFalse() {
223         mFragController.create(R.id.main_content, /* bundle= */ null).start().resume();
224 
225         final TwoStatePreference switchPreference = mFragController.get().findPreference(
226                 MagnificationOneFingerPanningPreferenceController.PREF_KEY);
227         assertThat(switchPreference).isNotNull();
228         assertThat(switchPreference.isChecked()).isFalse();
229     }
230 
231     @Test
232     @EnableFlags(Flags.FLAG_ENABLE_MAGNIFICATION_ONE_FINGER_PANNING_GESTURE)
onResume_enableOneFingerPan_switchPreferenceShouldReturnTrue()233     public void onResume_enableOneFingerPan_switchPreferenceShouldReturnTrue() {
234         setKeyOneFingerPanEnabled(true);
235 
236         mFragController.create(R.id.main_content, /* bundle= */ null).start().resume();
237 
238         final TwoStatePreference switchPreference = mFragController.get().findPreference(
239                 MagnificationOneFingerPanningPreferenceController.PREF_KEY);
240         assertThat(switchPreference).isNotNull();
241         assertThat(switchPreference.isChecked()).isTrue();
242     }
243 
244     @Test
245     @EnableFlags(Flags.FLAG_ENABLE_MAGNIFICATION_ONE_FINGER_PANNING_GESTURE)
onResume_disableOneFingerPan_switchPreferenceShouldReturnFalse()246     public void onResume_disableOneFingerPan_switchPreferenceShouldReturnFalse() {
247         setKeyOneFingerPanEnabled(false);
248 
249         mFragController.create(R.id.main_content, /* bundle= */ null).start().resume();
250 
251         final TwoStatePreference switchPreference = mFragController.get().findPreference(
252                 MagnificationOneFingerPanningPreferenceController.PREF_KEY);
253         assertThat(switchPreference).isNotNull();
254         assertThat(switchPreference.isChecked()).isFalse();
255     }
256 
257     @Test
onResume_defaultStateForAlwaysOn_switchPreferenceShouldReturnTrue()258     public void onResume_defaultStateForAlwaysOn_switchPreferenceShouldReturnTrue() {
259         setAlwaysOnSupported(true);
260 
261         mFragController.create(R.id.main_content, /* bundle= */ null).start().resume();
262 
263         final TwoStatePreference switchPreference = mFragController.get().findPreference(
264                 MagnificationAlwaysOnPreferenceController.PREF_KEY);
265         assertThat(switchPreference).isNotNull();
266         assertThat(switchPreference.isChecked()).isTrue();
267     }
268 
269     @Test
onResume_enableAlwaysOn_switchPreferenceShouldReturnTrue()270     public void onResume_enableAlwaysOn_switchPreferenceShouldReturnTrue() {
271         setAlwaysOnSupported(true);
272         setKeyAlwaysOnEnabled(true);
273 
274         mFragController.create(R.id.main_content, /* bundle= */ null).start().resume();
275 
276         final TwoStatePreference switchPreference = mFragController.get().findPreference(
277                 MagnificationAlwaysOnPreferenceController.PREF_KEY);
278         assertThat(switchPreference).isNotNull();
279         assertThat(switchPreference.isChecked()).isTrue();
280     }
281 
282     @Test
onResume_disableAlwaysOn_switchPreferenceShouldReturnFalse()283     public void onResume_disableAlwaysOn_switchPreferenceShouldReturnFalse() {
284         setAlwaysOnSupported(true);
285         setKeyAlwaysOnEnabled(false);
286 
287         mFragController.create(R.id.main_content, /* bundle= */ null).start().resume();
288 
289         final TwoStatePreference switchPreference = mFragController.get().findPreference(
290                 MagnificationAlwaysOnPreferenceController.PREF_KEY);
291         assertThat(switchPreference).isNotNull();
292         assertThat(switchPreference.isChecked()).isFalse();
293     }
294 
295     @Test
onResume_defaultStateForJoystick_switchPreferenceShouldReturnFalse()296     public void onResume_defaultStateForJoystick_switchPreferenceShouldReturnFalse() {
297         setJoystickSupported(true);
298 
299         mFragController.create(R.id.main_content, /* bundle= */ null).start().resume();
300 
301         final TwoStatePreference switchPreference = mFragController.get().findPreference(
302                 MagnificationJoystickPreferenceController.PREF_KEY);
303         assertThat(switchPreference).isNotNull();
304         assertThat(switchPreference.isChecked()).isFalse();
305     }
306 
307     @Test
onResume_enableJoystick_switchPreferenceShouldReturnTrue()308     public void onResume_enableJoystick_switchPreferenceShouldReturnTrue() {
309         setJoystickSupported(true);
310         setKeyJoystickEnabled(true);
311 
312         mFragController.create(R.id.main_content, /* bundle= */ null).start().resume();
313 
314         final TwoStatePreference switchPreference = mFragController.get().findPreference(
315                 MagnificationJoystickPreferenceController.PREF_KEY);
316         assertThat(switchPreference).isNotNull();
317         assertThat(switchPreference.isChecked()).isTrue();
318     }
319 
320     @Test
onResume_disableJoystick_switchPreferenceShouldReturnFalse()321     public void onResume_disableJoystick_switchPreferenceShouldReturnFalse() {
322         setJoystickSupported(true);
323         setKeyJoystickEnabled(false);
324 
325         mFragController.create(R.id.main_content, /* bundle= */ null).start().resume();
326 
327         final TwoStatePreference switchPreference = mFragController.get().findPreference(
328                 MagnificationJoystickPreferenceController.PREF_KEY);
329         assertThat(switchPreference).isNotNull();
330         assertThat(switchPreference.isChecked()).isFalse();
331     }
332 
333     @Test
334     @EnableFlags(android.view.accessibility.Flags.FLAG_A11Y_QS_SHORTCUT)
onResume_flagEnabled_haveRegisterToSpecificUris()335     public void onResume_flagEnabled_haveRegisterToSpecificUris() {
336         ShadowContentResolver shadowContentResolver = Shadows.shadowOf(
337                 mContext.getContentResolver());
338         Uri[] observedUri = new Uri[]{
339                 Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS),
340                 Settings.Secure.getUriFor(
341                         Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE),
342                 Settings.Secure.getUriFor(
343                         Settings.Secure.ACCESSIBILITY_QS_TARGETS),
344                 Settings.Secure.getUriFor(
345                         Settings.Secure.ACCESSIBILITY_MAGNIFICATION_FOLLOW_TYPING_ENABLED),
346                 Settings.Secure.getUriFor(
347                         Settings.Secure.ACCESSIBILITY_MAGNIFICATION_ALWAYS_ON_ENABLED)
348         };
349         for (Uri uri : observedUri) {
350             // verify no observer registered before launching the fragment
351             assertThat(shadowContentResolver.getContentObservers(uri)).isEmpty();
352         }
353 
354         mFragController.create(R.id.main_content, /* bundle= */ null).start().resume();
355 
356         for (Uri uri : observedUri) {
357             Collection<ContentObserver> observers = shadowContentResolver.getContentObservers(uri);
358             assertThat(observers.size()).isEqualTo(1);
359             assertThat(observers.stream().findFirst().get()).isInstanceOf(
360                     AccessibilitySettingsContentObserver.class);
361         }
362     }
363 
364     @Test
365     @DisableFlags(android.view.accessibility.Flags.FLAG_A11Y_QS_SHORTCUT)
onResume_flagDisabled_haveRegisterToSpecificUris()366     public void onResume_flagDisabled_haveRegisterToSpecificUris() {
367         ShadowContentResolver shadowContentResolver = Shadows.shadowOf(
368                 mContext.getContentResolver());
369         Uri[] observedUri = new Uri[]{
370                 Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS),
371                 Settings.Secure.getUriFor(
372                         Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE),
373                 Settings.Secure.getUriFor(
374                         Settings.Secure.ACCESSIBILITY_MAGNIFICATION_FOLLOW_TYPING_ENABLED),
375                 Settings.Secure.getUriFor(
376                         Settings.Secure.ACCESSIBILITY_MAGNIFICATION_ALWAYS_ON_ENABLED)
377         };
378         for (Uri uri : observedUri) {
379             // verify no observer registered before launching the fragment
380             assertThat(shadowContentResolver.getContentObservers(uri)).isEmpty();
381         }
382 
383         mFragController.create(R.id.main_content, /* bundle= */ null).start().resume();
384 
385         for (Uri uri : observedUri) {
386             Collection<ContentObserver> observers = shadowContentResolver.getContentObservers(uri);
387             assertThat(observers.size()).isEqualTo(1);
388             assertThat(observers.stream().findFirst().get()).isInstanceOf(
389                     AccessibilitySettingsContentObserver.class);
390         }
391         assertThat(shadowContentResolver.getContentObservers(
392                 Settings.Secure.getUriFor(
393                         Settings.Secure.ACCESSIBILITY_QS_TARGETS))).hasSize(0);
394     }
395 
396     @Test
hasValueInSettings_putValue_hasValue()397     public void hasValueInSettings_putValue_hasValue() {
398         setMagnificationTripleTapEnabled(/* enabled= */ true);
399 
400         assertThat(ToggleScreenMagnificationPreferenceFragment.hasMagnificationValuesInSettings(
401                 mContext, UserShortcutType.TRIPLETAP)).isTrue();
402     }
403 
404     @Test
405     @EnableFlags(Flags.FLAG_ENABLE_MAGNIFICATION_MULTIPLE_FINGER_MULTIPLE_TAP_GESTURE)
hasMagnificationValuesInSettings_twoFingerTripleTapIsOn_isTrue()406     public void hasMagnificationValuesInSettings_twoFingerTripleTapIsOn_isTrue() {
407         Settings.Secure.putInt(
408                 mContext.getContentResolver(), TWO_FINGER_TRIPLE_TAP_SHORTCUT_KEY, ON);
409 
410         assertThat(ToggleScreenMagnificationPreferenceFragment.hasMagnificationValuesInSettings(
411                 mContext, UserShortcutType.TWOFINGER_DOUBLETAP)).isTrue();
412     }
413 
414     @Test
415     @EnableFlags(Flags.FLAG_ENABLE_MAGNIFICATION_MULTIPLE_FINGER_MULTIPLE_TAP_GESTURE)
hasMagnificationValuesInSettings_twoFingerTripleTapIsOff_isFalse()416     public void hasMagnificationValuesInSettings_twoFingerTripleTapIsOff_isFalse() {
417         Settings.Secure.putInt(
418                 mContext.getContentResolver(), TWO_FINGER_TRIPLE_TAP_SHORTCUT_KEY, OFF);
419 
420         assertThat(ToggleScreenMagnificationPreferenceFragment.hasMagnificationValuesInSettings(
421                 mContext, UserShortcutType.TWOFINGER_DOUBLETAP)).isFalse();
422     }
423 
424     @Test
425     @DisableFlags(android.view.accessibility.Flags.FLAG_A11Y_QS_SHORTCUT)
optInAllValuesToSettings_optInValue_haveMatchString()426     public void optInAllValuesToSettings_optInValue_haveMatchString() {
427         int shortcutTypes = UserShortcutType.SOFTWARE | UserShortcutType.TRIPLETAP;
428 
429         ToggleScreenMagnificationPreferenceFragment.optInAllMagnificationValuesToSettings(mContext,
430                 shortcutTypes);
431 
432         assertThat(getStringFromSettings(SOFTWARE_SHORTCUT_KEY)).isEqualTo(
433                 MAGNIFICATION_CONTROLLER_NAME);
434         assertThat(getMagnificationTripleTapStatus()).isTrue();
435     }
436 
437     @Test
438     @EnableFlags(android.view.accessibility.Flags.FLAG_A11Y_QS_SHORTCUT)
optInAllValuesToSettings_optInValue_callA11yManager()439     public void optInAllValuesToSettings_optInValue_callA11yManager() {
440         int shortcutTypes =
441                 UserShortcutType.SOFTWARE | UserShortcutType.TRIPLETAP | UserShortcutType.HARDWARE
442                         | UserShortcutType.QUICK_SETTINGS;
443         Set<String> shortcutTargets = Set.of(MAGNIFICATION_CONTROLLER_NAME);
444 
445         ToggleScreenMagnificationPreferenceFragment.optInAllMagnificationValuesToSettings(mContext,
446                 shortcutTypes);
447 
448         verify(mAccessibilityManager).enableShortcutsForTargets(
449                 /* enable= */ true, UserShortcutType.SOFTWARE,
450                 shortcutTargets, UserHandle.myUserId());
451         verify(mAccessibilityManager).enableShortcutsForTargets(
452                 /* enable= */ true, UserShortcutType.HARDWARE,
453                 shortcutTargets, UserHandle.myUserId());
454         verify(mAccessibilityManager).enableShortcutsForTargets(
455                 /* enable= */ true, UserShortcutType.QUICK_SETTINGS,
456                 shortcutTargets, UserHandle.myUserId());
457         verify(mAccessibilityManager).enableShortcutsForTargets(
458                 /* enable= */ true, UserShortcutType.TRIPLETAP,
459                 shortcutTargets, UserHandle.myUserId());
460         verifyNoMoreInteractions(mAccessibilityManager);
461     }
462 
463     @Test
464     @EnableFlags(Flags.FLAG_ENABLE_MAGNIFICATION_MULTIPLE_FINGER_MULTIPLE_TAP_GESTURE)
465     @DisableFlags(android.view.accessibility.Flags.FLAG_A11Y_QS_SHORTCUT)
optInAllValuesToSettings_twoFingerTripleTap_haveMatchString()466     public void optInAllValuesToSettings_twoFingerTripleTap_haveMatchString() {
467         int shortcutTypes = UserShortcutType.TWOFINGER_DOUBLETAP;
468 
469         ToggleScreenMagnificationPreferenceFragment.optInAllMagnificationValuesToSettings(mContext,
470                 shortcutTypes);
471 
472         assertThat(Settings.Secure.getInt(mContext.getContentResolver(),
473                 TWO_FINGER_TRIPLE_TAP_SHORTCUT_KEY, OFF)).isEqualTo(ON);
474     }
475 
476     @Test
477     @DisableFlags(android.view.accessibility.Flags.FLAG_A11Y_QS_SHORTCUT)
optInAllValuesToSettings_existOtherValue_optInValue_haveMatchString()478     public void optInAllValuesToSettings_existOtherValue_optInValue_haveMatchString() {
479         putStringIntoSettings(SOFTWARE_SHORTCUT_KEY, PLACEHOLDER_COMPONENT_NAME.flattenToString());
480 
481         ToggleScreenMagnificationPreferenceFragment.optInAllMagnificationValuesToSettings(mContext,
482                 UserShortcutType.SOFTWARE);
483 
484         assertThat(getStringFromSettings(SOFTWARE_SHORTCUT_KEY)).isEqualTo(
485                 PLACEHOLDER_COMPONENT_NAME.flattenToString() + ":" + MAGNIFICATION_CONTROLLER_NAME);
486     }
487 
488     @Test
489     @DisableFlags(android.view.accessibility.Flags.FLAG_A11Y_QS_SHORTCUT)
optInAllValuesToSettings_software_sizeValueIsNull_putLargeSizeValue()490     public void optInAllValuesToSettings_software_sizeValueIsNull_putLargeSizeValue() {
491         ShadowSettings.ShadowSecure.reset();
492 
493         ToggleScreenMagnificationPreferenceFragment.optInAllMagnificationValuesToSettings(mContext,
494                 UserShortcutType.SOFTWARE);
495 
496         assertThat(Settings.Secure.getInt(mContext.getContentResolver(),
497                 Settings.Secure.ACCESSIBILITY_FLOATING_MENU_SIZE,
498                 FloatingMenuSizePreferenceController.Size.UNKNOWN)).isEqualTo(
499                 FloatingMenuSizePreferenceController.Size.LARGE);
500     }
501 
502     @Test
optInAllValuesToSettings_software_sizeValueIsNotNull_sizeValueIsNotChanged()503     public void optInAllValuesToSettings_software_sizeValueIsNotNull_sizeValueIsNotChanged() {
504         for (int size : new int[] {FloatingMenuSizePreferenceController.Size.LARGE,
505                 FloatingMenuSizePreferenceController.Size.SMALL}) {
506             Settings.Secure.putInt(mContext.getContentResolver(),
507                     Settings.Secure.ACCESSIBILITY_FLOATING_MENU_SIZE, size);
508 
509             ToggleScreenMagnificationPreferenceFragment.optInAllMagnificationValuesToSettings(
510                     mContext,
511                     UserShortcutType.SOFTWARE);
512 
513             assertThat(Settings.Secure.getInt(mContext.getContentResolver(),
514                     Settings.Secure.ACCESSIBILITY_FLOATING_MENU_SIZE,
515                     FloatingMenuSizePreferenceController.Size.UNKNOWN)).isEqualTo(
516                     size);
517         }
518     }
519 
520     @Test
optInAllValuesToSettings_hardware_sizeValueIsNotChanged()521     public void optInAllValuesToSettings_hardware_sizeValueIsNotChanged() {
522         for (int size : new int[] {FloatingMenuSizePreferenceController.Size.UNKNOWN,
523                 FloatingMenuSizePreferenceController.Size.LARGE,
524                 FloatingMenuSizePreferenceController.Size.SMALL}) {
525             Settings.Secure.putInt(mContext.getContentResolver(),
526                     Settings.Secure.ACCESSIBILITY_FLOATING_MENU_SIZE, size);
527 
528             ToggleScreenMagnificationPreferenceFragment.optInAllMagnificationValuesToSettings(
529                     mContext,
530                     UserShortcutType.HARDWARE);
531 
532             assertThat(Settings.Secure.getInt(mContext.getContentResolver(),
533                     Settings.Secure.ACCESSIBILITY_FLOATING_MENU_SIZE, size + 1)).isEqualTo(
534                     size);
535         }
536     }
537 
538     @Test
optInAllValuesToSettings_tripletap_sizeValueIsNotChanged()539     public void optInAllValuesToSettings_tripletap_sizeValueIsNotChanged() {
540         for (int size : new int[] {FloatingMenuSizePreferenceController.Size.UNKNOWN,
541                 FloatingMenuSizePreferenceController.Size.LARGE,
542                 FloatingMenuSizePreferenceController.Size.SMALL}) {
543             Settings.Secure.putInt(mContext.getContentResolver(),
544                     Settings.Secure.ACCESSIBILITY_FLOATING_MENU_SIZE, size);
545 
546             ToggleScreenMagnificationPreferenceFragment.optInAllMagnificationValuesToSettings(
547                     mContext,
548                     UserShortcutType.TRIPLETAP);
549 
550             assertThat(Settings.Secure.getInt(mContext.getContentResolver(),
551                     Settings.Secure.ACCESSIBILITY_FLOATING_MENU_SIZE, size + 1)).isEqualTo(
552                     size);
553         }
554     }
555 
556     @Test
557     @DisableFlags(android.view.accessibility.Flags.FLAG_A11Y_QS_SHORTCUT)
optOutAllValuesToSettings_optOutValue_emptyString()558     public void optOutAllValuesToSettings_optOutValue_emptyString() {
559         putStringIntoSettings(SOFTWARE_SHORTCUT_KEY, MAGNIFICATION_CONTROLLER_NAME);
560         putStringIntoSettings(HARDWARE_SHORTCUT_KEY, MAGNIFICATION_CONTROLLER_NAME);
561         setMagnificationTripleTapEnabled(/* enabled= */ true);
562         int shortcutTypes =
563                 UserShortcutType.SOFTWARE | UserShortcutType.HARDWARE | UserShortcutType.TRIPLETAP;
564 
565         ToggleScreenMagnificationPreferenceFragment.optOutAllMagnificationValuesFromSettings(
566                 mContext, shortcutTypes);
567 
568         assertThat(getStringFromSettings(SOFTWARE_SHORTCUT_KEY)).isEmpty();
569         assertThat(getStringFromSettings(HARDWARE_SHORTCUT_KEY)).isEmpty();
570         assertThat(getMagnificationTripleTapStatus()).isFalse();
571     }
572 
573     @Test
574     @EnableFlags(android.view.accessibility.Flags.FLAG_A11Y_QS_SHORTCUT)
optOutAllValuesToSettings_optOutValue_callA11yManager()575     public void optOutAllValuesToSettings_optOutValue_callA11yManager() {
576         Set<String> shortcutTargets = Set.of(MAGNIFICATION_CONTROLLER_NAME);
577         putStringIntoSettings(SOFTWARE_SHORTCUT_KEY, MAGNIFICATION_CONTROLLER_NAME);
578         putStringIntoSettings(HARDWARE_SHORTCUT_KEY, MAGNIFICATION_CONTROLLER_NAME);
579         setMagnificationTripleTapEnabled(/* enabled= */ true);
580         int shortcutTypes =
581                 UserShortcutType.SOFTWARE | UserShortcutType.HARDWARE | UserShortcutType.TRIPLETAP;
582 
583         ToggleScreenMagnificationPreferenceFragment.optOutAllMagnificationValuesFromSettings(
584                 mContext, shortcutTypes);
585 
586         verify(mAccessibilityManager).enableShortcutsForTargets(
587                 /* enable= */ false, UserShortcutType.SOFTWARE,
588                 shortcutTargets, UserHandle.myUserId());
589         verify(mAccessibilityManager).enableShortcutsForTargets(
590                 /* enable= */ false, UserShortcutType.HARDWARE,
591                 shortcutTargets, UserHandle.myUserId());
592         verify(mAccessibilityManager).enableShortcutsForTargets(
593                 /* enable= */ false, UserShortcutType.TRIPLETAP,
594                 shortcutTargets, UserHandle.myUserId());
595         verifyNoMoreInteractions(mAccessibilityManager);
596     }
597 
598     @Test
599     @EnableFlags(Flags.FLAG_ENABLE_MAGNIFICATION_MULTIPLE_FINGER_MULTIPLE_TAP_GESTURE)
600     @DisableFlags(android.view.accessibility.Flags.FLAG_A11Y_QS_SHORTCUT)
optOutAllValuesToSettings_twoFingerTripleTap_settingsValueIsOff()601     public void optOutAllValuesToSettings_twoFingerTripleTap_settingsValueIsOff() {
602         Settings.Secure.putInt(mContext.getContentResolver(),
603                 TWO_FINGER_TRIPLE_TAP_SHORTCUT_KEY, ON);
604 
605         ToggleScreenMagnificationPreferenceFragment.optOutAllMagnificationValuesFromSettings(
606                 mContext, UserShortcutType.TWOFINGER_DOUBLETAP);
607 
608         assertThat(Settings.Secure.getInt(mContext.getContentResolver(),
609                 TWO_FINGER_TRIPLE_TAP_SHORTCUT_KEY, ON)).isEqualTo(OFF);
610     }
611 
612     @Test
613     @DisableFlags(android.view.accessibility.Flags.FLAG_A11Y_QS_SHORTCUT)
optOutValueFromSettings_existOtherValue_optOutValue_haveMatchString()614     public void optOutValueFromSettings_existOtherValue_optOutValue_haveMatchString() {
615         putStringIntoSettings(SOFTWARE_SHORTCUT_KEY,
616                 PLACEHOLDER_COMPONENT_NAME.flattenToString() + ":" + MAGNIFICATION_CONTROLLER_NAME);
617         putStringIntoSettings(HARDWARE_SHORTCUT_KEY,
618                 PLACEHOLDER_COMPONENT_NAME.flattenToString() + ":" + MAGNIFICATION_CONTROLLER_NAME);
619         int shortcutTypes = UserShortcutType.SOFTWARE | UserShortcutType.HARDWARE;
620 
621         ToggleScreenMagnificationPreferenceFragment.optOutAllMagnificationValuesFromSettings(
622                 mContext, shortcutTypes);
623 
624         assertThat(getStringFromSettings(SOFTWARE_SHORTCUT_KEY)).isEqualTo(
625                 PLACEHOLDER_COMPONENT_NAME.flattenToString());
626         assertThat(getStringFromSettings(HARDWARE_SHORTCUT_KEY)).isEqualTo(
627                 PLACEHOLDER_COMPONENT_NAME.flattenToString());
628     }
629 
630     @Test
updateShortcutPreferenceData_assignDefaultValueToVariable()631     public void updateShortcutPreferenceData_assignDefaultValueToVariable() {
632         mFragController.create(R.id.main_content, /* bundle= */ null).start().resume();
633 
634         mFragController.get().updateShortcutPreferenceData();
635 
636         final int expectedType = PreferredShortcuts.retrieveUserShortcutType(mContext,
637                 MAGNIFICATION_CONTROLLER_NAME);
638         // Compare to default UserShortcutType
639         assertThat(expectedType).isEqualTo(UserShortcutType.SOFTWARE);
640     }
641 
642     @Test
updateShortcutPreferenceData_hasValueInSettings_assignToVariable()643     public void updateShortcutPreferenceData_hasValueInSettings_assignToVariable() {
644         putStringIntoSettings(SOFTWARE_SHORTCUT_KEY, MAGNIFICATION_CONTROLLER_NAME);
645         setMagnificationTripleTapEnabled(/* enabled= */ true);
646         mFragController.create(R.id.main_content, /* bundle= */ null).start().resume();
647 
648         mFragController.get().updateShortcutPreferenceData();
649 
650         final int expectedType = PreferredShortcuts.retrieveUserShortcutType(mContext,
651                 MAGNIFICATION_CONTROLLER_NAME);
652         assertThat(expectedType).isEqualTo(UserShortcutType.SOFTWARE | UserShortcutType.TRIPLETAP);
653     }
654 
655     @Test
updateShortcutPreferenceData_hasValueInSharedPreference_assignToVariable()656     public void updateShortcutPreferenceData_hasValueInSharedPreference_assignToVariable() {
657         final PreferredShortcut tripleTapShortcut = new PreferredShortcut(
658                 MAGNIFICATION_CONTROLLER_NAME, UserShortcutType.TRIPLETAP);
659         putUserShortcutTypeIntoSharedPreference(mContext, tripleTapShortcut);
660         mFragController.create(R.id.main_content, /* bundle= */ null).start().resume();
661 
662         mFragController.get().updateShortcutPreferenceData();
663 
664         final int expectedType = PreferredShortcuts.retrieveUserShortcutType(mContext,
665                 MAGNIFICATION_CONTROLLER_NAME);
666         assertThat(expectedType).isEqualTo(UserShortcutType.TRIPLETAP);
667     }
668 
669     @Test
670     @EnableFlags(Flags.FLAG_ENABLE_MAGNIFICATION_MULTIPLE_FINGER_MULTIPLE_TAP_GESTURE)
updateShortcutPreferenceData_hasTwoFingerTripleTapInSettings_assignToVariable()671     public void updateShortcutPreferenceData_hasTwoFingerTripleTapInSettings_assignToVariable() {
672         Settings.Secure.putInt(
673                 mContext.getContentResolver(), TWO_FINGER_TRIPLE_TAP_SHORTCUT_KEY, ON);
674         mFragController.create(R.id.main_content, /* bundle= */ null).start().resume();
675 
676         mFragController.get().updateShortcutPreferenceData();
677 
678         final int expectedType = PreferredShortcuts.retrieveUserShortcutType(mContext,
679                 MAGNIFICATION_CONTROLLER_NAME);
680         assertThat(expectedType).isEqualTo(UserShortcutType.TWOFINGER_DOUBLETAP);
681     }
682 
683     @Test
684     @EnableFlags(Flags.FLAG_ENABLE_MAGNIFICATION_MULTIPLE_FINGER_MULTIPLE_TAP_GESTURE)
updateShortcutPreferenceData_hasTwoFingerTripleTapInSharedPref_assignToVariable()685     public void updateShortcutPreferenceData_hasTwoFingerTripleTapInSharedPref_assignToVariable() {
686         final PreferredShortcut tripleTapShortcut = new PreferredShortcut(
687                 MAGNIFICATION_CONTROLLER_NAME, UserShortcutType.TWOFINGER_DOUBLETAP);
688         putUserShortcutTypeIntoSharedPreference(mContext, tripleTapShortcut);
689         mFragController.create(R.id.main_content, /* bundle= */ null).start().resume();
690 
691         mFragController.get().updateShortcutPreferenceData();
692 
693         final int expectedType = PreferredShortcuts.retrieveUserShortcutType(mContext,
694                 MAGNIFICATION_CONTROLLER_NAME);
695         assertThat(expectedType).isEqualTo(UserShortcutType.TWOFINGER_DOUBLETAP);
696     }
697 
698     @Test
setupMagnificationEditShortcutDialog_shortcutPreferenceOff_checkboxIsEmptyValue()699     public void setupMagnificationEditShortcutDialog_shortcutPreferenceOff_checkboxIsEmptyValue() {
700         ToggleScreenMagnificationPreferenceFragment fragment =
701                 mFragController.create(R.id.main_content, /* bundle= */
702                         null).start().resume().get();
703         fragment.mShortcutPreference = new ShortcutPreference(mContext, /* attrs= */ null);
704 
705         fragment.mShortcutPreference.setChecked(false);
706         fragment.setupMagnificationEditShortcutDialog(
707                 createEditShortcutDialog(fragment.getActivity()));
708 
709         final int checkboxValue = fragment.getShortcutTypeCheckBoxValue();
710         assertThat(checkboxValue).isEqualTo(UserShortcutType.EMPTY);
711     }
712 
713     @Test
setupMagnificationEditShortcutDialog_shortcutPreferenceOn_checkboxIsSavedValue()714     public void setupMagnificationEditShortcutDialog_shortcutPreferenceOn_checkboxIsSavedValue() {
715         ToggleScreenMagnificationPreferenceFragment fragment =
716                 mFragController.create(R.id.main_content, /* bundle= */
717                         null).start().resume().get();
718         final ShortcutPreference shortcutPreference = new ShortcutPreference(mContext, /* attrs= */
719                 null);
720         final PreferredShortcut tripletapShortcut = new PreferredShortcut(
721                 MAGNIFICATION_CONTROLLER_NAME, UserShortcutType.TRIPLETAP);
722         fragment.mShortcutPreference = shortcutPreference;
723 
724         PreferredShortcuts.saveUserShortcutType(mContext, tripletapShortcut);
725         fragment.mShortcutPreference.setChecked(true);
726         fragment.setupMagnificationEditShortcutDialog(
727                 createEditShortcutDialog(fragment.getActivity()));
728 
729         final int checkboxValue = fragment.getShortcutTypeCheckBoxValue();
730         assertThat(checkboxValue).isEqualTo(UserShortcutType.TRIPLETAP);
731     }
732 
733     @Test
734     @EnableFlags(Flags.FLAG_ENABLE_MAGNIFICATION_MULTIPLE_FINGER_MULTIPLE_TAP_GESTURE)
setupMagnificationEditShortcutDialog_twoFingerTripleTapOn_checkboxIsSavedValue()735     public void setupMagnificationEditShortcutDialog_twoFingerTripleTapOn_checkboxIsSavedValue() {
736         ToggleScreenMagnificationPreferenceFragment fragment =
737                 mFragController.create(R.id.main_content, /* bundle= */
738                         null).start().resume().get();
739         final ShortcutPreference shortcutPreference = new ShortcutPreference(mContext, /* attrs= */
740                 null);
741         final PreferredShortcut twoFingerTripleTapShortcut = new PreferredShortcut(
742                 MAGNIFICATION_CONTROLLER_NAME, UserShortcutType.TWOFINGER_DOUBLETAP);
743         fragment.mShortcutPreference = shortcutPreference;
744 
745         PreferredShortcuts.saveUserShortcutType(mContext, twoFingerTripleTapShortcut);
746         fragment.mShortcutPreference.setChecked(true);
747         fragment.setupMagnificationEditShortcutDialog(
748                 createEditShortcutDialog(fragment.getActivity()));
749 
750         final int checkboxValue = fragment.getShortcutTypeCheckBoxValue();
751         assertThat(checkboxValue).isEqualTo(UserShortcutType.TWOFINGER_DOUBLETAP);
752     }
753 
754     @Test
restoreValueFromSavedInstanceState_assignToVariable()755     public void restoreValueFromSavedInstanceState_assignToVariable() {
756         final Bundle fragmentState = createFragmentSavedInstanceState(
757                 UserShortcutType.HARDWARE | UserShortcutType.TRIPLETAP);
758         ToggleScreenMagnificationPreferenceFragment fragment = mFragController.get();
759         // Had to use reflection to pass the savedInstanceState when launching the fragment
760         ReflectionHelpers.setField(fragment, "mSavedFragmentState", fragmentState);
761 
762         FragmentController.of(fragment, SettingsActivity.class).create(
763                 R.id.main_content, /* bundle= */ null).start().resume().get();
764         fragment.setupMagnificationEditShortcutDialog(
765                 createEditShortcutDialog(fragment.getActivity()));
766         final int value = fragment.getShortcutTypeCheckBoxValue();
767         fragment.saveNonEmptyUserShortcutType(value);
768 
769         final int expectedType = PreferredShortcuts.retrieveUserShortcutType(mContext,
770                 MAGNIFICATION_CONTROLLER_NAME);
771         assertThat(value).isEqualTo(6);
772         assertThat(expectedType).isEqualTo(UserShortcutType.HARDWARE | UserShortcutType.TRIPLETAP);
773     }
774 
775     @Test
776     @EnableFlags(Flags.FLAG_ENABLE_MAGNIFICATION_MULTIPLE_FINGER_MULTIPLE_TAP_GESTURE)
restoreValueFromSavedInstanceState_twoFingerTripleTap_assignToVariable()777     public void restoreValueFromSavedInstanceState_twoFingerTripleTap_assignToVariable() {
778         final Bundle fragmentState =
779                 createFragmentSavedInstanceState(UserShortcutType.TWOFINGER_DOUBLETAP);
780         ToggleScreenMagnificationPreferenceFragment fragment = mFragController.get();
781         // Had to use reflection to pass the savedInstanceState when launching the fragment
782         ReflectionHelpers.setField(fragment, "mSavedFragmentState", fragmentState);
783 
784         FragmentController.of(fragment, SettingsActivity.class).create(
785                 R.id.main_content, /* bundle= */ null).start().resume().get();
786         fragment.setupMagnificationEditShortcutDialog(
787                 createEditShortcutDialog(fragment.getActivity()));
788         final int value = fragment.getShortcutTypeCheckBoxValue();
789         fragment.saveNonEmptyUserShortcutType(value);
790 
791         final int expectedType = PreferredShortcuts.retrieveUserShortcutType(mContext,
792                 MAGNIFICATION_CONTROLLER_NAME);
793         assertThat(value).isEqualTo(UserShortcutType.TWOFINGER_DOUBLETAP);
794         assertThat(expectedType).isEqualTo(UserShortcutType.TWOFINGER_DOUBLETAP);
795     }
796 
797     @Test
onCreateView_magnificationAreaNotSupported_settingsPreferenceIsNull()798     public void onCreateView_magnificationAreaNotSupported_settingsPreferenceIsNull() {
799         setWindowMagnificationSupported(
800                 /* magnificationAreaSupported= */ false,
801                 /* windowMagnificationSupported= */ true);
802 
803         mFragController.create(R.id.main_content, /* bundle= */ null).start().resume();
804 
805         assertThat(mFragController.get().mSettingsPreference).isNull();
806     }
807 
808     @Test
onCreateView_windowMagnificationNotSupported_settingsPreferenceIsNull()809     public void onCreateView_windowMagnificationNotSupported_settingsPreferenceIsNull() {
810         setWindowMagnificationSupported(
811                 /* magnificationAreaSupported= */ true,
812                 /* windowMagnificationSupported= */ false);
813 
814         mFragController.create(R.id.main_content, /* bundle= */ null).start().resume();
815 
816         assertThat(mFragController.get().mSettingsPreference).isNull();
817     }
818 
819     @Test
820     @DisableFlags(Flags.FLAG_ENABLE_MAGNIFICATION_ONE_FINGER_PANNING_GESTURE)
onCreateView_oneFingerPanNotSupported_settingsPreferenceIsNull()821     public void onCreateView_oneFingerPanNotSupported_settingsPreferenceIsNull() {
822         mFragController.create(R.id.main_content, /* bundle= */ null).start().resume();
823 
824         final TwoStatePreference switchPreference = mFragController.get().findPreference(
825                 MagnificationOneFingerPanningPreferenceController.PREF_KEY);
826         assertThat(switchPreference).isNull();
827     }
828 
829     @Test
onCreateView_alwaysOnNotSupported_settingsPreferenceIsNull()830     public void onCreateView_alwaysOnNotSupported_settingsPreferenceIsNull() {
831         setAlwaysOnSupported(false);
832 
833         mFragController.create(R.id.main_content, /* bundle= */ null).start().resume();
834 
835         final TwoStatePreference switchPreference = mFragController.get().findPreference(
836                 MagnificationAlwaysOnPreferenceController.PREF_KEY);
837         assertThat(switchPreference).isNull();
838     }
839 
840     @Test
onCreateView_joystickNotSupported_settingsPreferenceIsNull()841     public void onCreateView_joystickNotSupported_settingsPreferenceIsNull() {
842         setJoystickSupported(false);
843 
844         mFragController.create(R.id.main_content, /* bundle= */ null).start().resume();
845 
846         final TwoStatePreference switchPreference = mFragController.get().findPreference(
847                 MagnificationJoystickPreferenceController.PREF_KEY);
848         assertThat(switchPreference).isNull();
849     }
850 
851     @Test
onCreateView_setDialogDelegateAndAddTheControllerToLifeCycleObserver()852     public void onCreateView_setDialogDelegateAndAddTheControllerToLifeCycleObserver() {
853         Correspondence instanceOf = Correspondence.transforming(
854                 observer -> (observer instanceof MagnificationModePreferenceController),
855                 "contains MagnificationModePreferenceController");
856 
857         ToggleScreenMagnificationPreferenceFragment fragment = mFragController.create(
858                 R.id.main_content, /* bundle= */ null).start().resume().get();
859 
860         DialogCreatable dialogDelegate = ReflectionHelpers.getField(fragment, "mDialogDelegate");
861         List<LifecycleObserver> lifecycleObservers = ReflectionHelpers.getField(
862                 fragment.getSettingsLifecycle(), "mObservers");
863         assertThat(dialogDelegate).isInstanceOf(MagnificationModePreferenceController.class);
864         assertThat(lifecycleObservers).isNotNull();
865         assertThat(lifecycleObservers).comparingElementsUsing(instanceOf).contains(true);
866     }
867 
868     @Test
869     @EnableFlags(Flags.FLAG_ENABLE_MAGNIFICATION_ONE_FINGER_PANNING_GESTURE)
onCreateView_oneFingerPanSupported_addControllerToLifeCycleObserver()870     public void onCreateView_oneFingerPanSupported_addControllerToLifeCycleObserver() {
871         Correspondence instanceOf = Correspondence.transforming(
872                 observer -> (observer instanceof MagnificationOneFingerPanningPreferenceController),
873                 "contains MagnificationOneFingerPanningPreferenceController");
874 
875         ToggleScreenMagnificationPreferenceFragment fragment = mFragController.create(
876                 R.id.main_content, /* bundle= */ null).start().resume().get();
877 
878         List<LifecycleObserver> lifecycleObservers = ReflectionHelpers.getField(
879                 fragment.getSettingsLifecycle(), "mObservers");
880         assertThat(lifecycleObservers).isNotNull();
881         assertThat(lifecycleObservers).comparingElementsUsing(instanceOf).contains(true);
882     }
883 
884     @Test
onCreateView_alwaysOnSupported_addControllerToLifeCycleObserver()885     public void onCreateView_alwaysOnSupported_addControllerToLifeCycleObserver() {
886         setAlwaysOnSupported(true);
887 
888         Correspondence instanceOf = Correspondence.transforming(
889                 observer -> (observer instanceof MagnificationAlwaysOnPreferenceController),
890                 "contains MagnificationAlwaysOnPreferenceController");
891 
892         ToggleScreenMagnificationPreferenceFragment fragment = mFragController.create(
893                 R.id.main_content, /* bundle= */ null).start().resume().get();
894 
895         List<LifecycleObserver> lifecycleObservers = ReflectionHelpers.getField(
896                 fragment.getSettingsLifecycle(), "mObservers");
897         assertThat(lifecycleObservers).isNotNull();
898         assertThat(lifecycleObservers).comparingElementsUsing(instanceOf).contains(true);
899     }
900 
901     @Test
onCreateDialog_setDialogDelegate_invokeDialogDelegate()902     public void onCreateDialog_setDialogDelegate_invokeDialogDelegate() {
903         ToggleScreenMagnificationPreferenceFragment fragment =
904                 mFragController.create(
905                         R.id.main_content, /* bundle= */ null).start().resume().get();
906         final DialogCreatable dialogDelegate = mock(DialogCreatable.class, RETURNS_DEEP_STUBS);
907         when(dialogDelegate.getDialogMetricsCategory(anyInt())).thenReturn(1);
908         fragment.setDialogDelegate(dialogDelegate);
909 
910         fragment.onCreateDialog(1);
911         fragment.getDialogMetricsCategory(1);
912 
913         verify(dialogDelegate).onCreateDialog(1);
914         verify(dialogDelegate).getDialogMetricsCategory(1);
915     }
916 
917     @Test
getMetricsCategory_returnsCorrectCategory()918     public void getMetricsCategory_returnsCorrectCategory() {
919         ToggleScreenMagnificationPreferenceFragment fragment =
920                 mFragController.create(
921                         R.id.main_content, /* bundle= */ null).start().resume().get();
922 
923         assertThat(fragment.getMetricsCategory()).isEqualTo(
924                 SettingsEnums.ACCESSIBILITY_TOGGLE_SCREEN_MAGNIFICATION);
925     }
926 
927     @Test
getHelpResource_returnsCorrectHelpResource()928     public void getHelpResource_returnsCorrectHelpResource() {
929         ToggleScreenMagnificationPreferenceFragment fragment =
930                 mFragController.create(
931                         R.id.main_content, /* bundle= */ null).start().resume().get();
932 
933         assertThat(fragment.getHelpResource()).isEqualTo(R.string.help_url_magnification);
934     }
935 
936     @Test
onProcessArguments_defaultArgumentUnavailable_shouldSetDefaultArguments()937     public void onProcessArguments_defaultArgumentUnavailable_shouldSetDefaultArguments() {
938         ToggleScreenMagnificationPreferenceFragment fragment =
939                 mFragController.create(
940                         R.id.main_content, /* bundle= */ null).start().resume().get();
941         Bundle arguments = new Bundle();
942 
943         fragment.onProcessArguments(arguments);
944 
945         assertTrue(arguments.containsKey(AccessibilitySettings.EXTRA_PREFERENCE_KEY));
946         assertTrue(arguments.containsKey(AccessibilitySettings.EXTRA_INTRO));
947         assertTrue(arguments.containsKey(AccessibilitySettings.EXTRA_HTML_DESCRIPTION));
948     }
949 
950     @Test
getSummary_magnificationEnabled_returnShortcutOnWithSummary()951     public void getSummary_magnificationEnabled_returnShortcutOnWithSummary() {
952         setMagnificationTripleTapEnabled(true);
953 
954         assertThat(
955                 ToggleScreenMagnificationPreferenceFragment.getServiceSummary(mContext).toString())
956                 .isEqualTo(
957                         mContext.getString(R.string.preference_summary_default_combination,
958                                 mContext.getText(R.string.accessibility_summary_shortcut_enabled),
959                                 mContext.getText(R.string.magnification_feature_summary)));
960     }
961 
962     @Test
getSummary_magnificationDisabled_returnShortcutOffWithSummary()963     public void getSummary_magnificationDisabled_returnShortcutOffWithSummary() {
964         setMagnificationTripleTapEnabled(false);
965 
966         assertThat(
967                 ToggleScreenMagnificationPreferenceFragment.getServiceSummary(mContext).toString())
968                 .isEqualTo(
969                         mContext.getString(R.string.preference_summary_default_combination,
970                                 mContext.getText(
971                                         R.string.generic_accessibility_feature_shortcut_off),
972                                 mContext.getText(R.string.magnification_feature_summary)));
973     }
974 
975     @Test
976     @EnableFlags(Flags.FLAG_ENABLE_MAGNIFICATION_MULTIPLE_FINGER_MULTIPLE_TAP_GESTURE)
getSummary_magnificationGestureEnabled_returnShortcutOnWithSummary()977     public void getSummary_magnificationGestureEnabled_returnShortcutOnWithSummary() {
978         Settings.Secure.putInt(
979                 mContext.getContentResolver(), TWO_FINGER_TRIPLE_TAP_SHORTCUT_KEY, ON);
980 
981         assertThat(
982                 ToggleScreenMagnificationPreferenceFragment.getServiceSummary(mContext).toString())
983                 .isEqualTo(
984                         mContext.getString(R.string.preference_summary_default_combination,
985                                 mContext.getText(R.string.accessibility_summary_shortcut_enabled),
986                                 mContext.getText(R.string.magnification_feature_summary)));
987     }
988 
989     @Test
990     @EnableFlags(Flags.FLAG_ENABLE_MAGNIFICATION_MULTIPLE_FINGER_MULTIPLE_TAP_GESTURE)
getSummary_magnificationGestureDisabled_returnShortcutOffWithSummary()991     public void getSummary_magnificationGestureDisabled_returnShortcutOffWithSummary() {
992         Settings.Secure.putInt(
993                 mContext.getContentResolver(), TWO_FINGER_TRIPLE_TAP_SHORTCUT_KEY, OFF);
994 
995         assertThat(
996                 ToggleScreenMagnificationPreferenceFragment.getServiceSummary(mContext).toString())
997                 .isEqualTo(
998                         mContext.getString(R.string.preference_summary_default_combination,
999                                 mContext.getText(
1000                                         R.string.generic_accessibility_feature_shortcut_off),
1001                                 mContext.getText(R.string.magnification_feature_summary)));
1002     }
1003 
1004     @Test
1005     @EnableFlags(android.view.accessibility.Flags.FLAG_A11Y_QS_SHORTCUT)
getShortcutTypeSummary_shortcutSummaryIsCorrectlySet()1006     public void getShortcutTypeSummary_shortcutSummaryIsCorrectlySet() {
1007         final PreferredShortcut userPreferredShortcut = new PreferredShortcut(
1008                 MAGNIFICATION_CONTROLLER_NAME,
1009                 UserShortcutType.HARDWARE | UserShortcutType.QUICK_SETTINGS);
1010         putUserShortcutTypeIntoSharedPreference(mContext, userPreferredShortcut);
1011         final ShortcutPreference shortcutPreference =
1012                 new ShortcutPreference(mContext, /* attrs= */ null);
1013         shortcutPreference.setChecked(true);
1014         shortcutPreference.setSettingsEditable(true);
1015         ToggleScreenMagnificationPreferenceFragment fragment =
1016                 mFragController.create(R.id.main_content, /* bundle= */
1017                         null).start().resume().get();
1018         fragment.mShortcutPreference = shortcutPreference;
1019         String expected = CaseMap.toTitle().wholeString().noLowercase().apply(Locale.getDefault(),
1020                 /* iter= */ null,
1021                 mContext.getString(
1022                         R.string.accessibility_feature_shortcut_setting_summary_quick_settings)
1023                         + ", "
1024                         + mContext.getString(R.string.accessibility_shortcut_hardware_keyword));
1025 
1026         String summary = fragment.getShortcutTypeSummary(mContext).toString();
1027 
1028         assertThat(summary).isEqualTo(expected);
1029     }
1030 
putStringIntoSettings(String key, String componentName)1031     private void putStringIntoSettings(String key, String componentName) {
1032         Settings.Secure.putString(mContext.getContentResolver(), key, componentName);
1033     }
1034 
putUserShortcutTypeIntoSharedPreference(Context context, PreferredShortcut shortcut)1035     private void putUserShortcutTypeIntoSharedPreference(Context context,
1036             PreferredShortcut shortcut) {
1037         PreferredShortcuts.saveUserShortcutType(context, shortcut);
1038     }
1039 
setMagnificationTripleTapEnabled(boolean enabled)1040     private void setMagnificationTripleTapEnabled(boolean enabled) {
1041         Settings.Secure.putInt(mContext.getContentResolver(), TRIPLETAP_SHORTCUT_KEY,
1042                 enabled ? ON : OFF);
1043     }
1044 
setKeyMagnificationMode(@agnificationMode int mode)1045     private void setKeyMagnificationMode(@MagnificationMode int mode) {
1046         MagnificationCapabilities.setCapabilities(mContext, mode);
1047     }
1048 
setKeyFollowTypingEnabled(boolean enabled)1049     private void setKeyFollowTypingEnabled(boolean enabled) {
1050         Settings.Secure.putInt(mContext.getContentResolver(), KEY_FOLLOW_TYPING,
1051                 enabled ? ON : OFF);
1052     }
1053 
setKeyOneFingerPanEnabled(boolean enabled)1054     private void setKeyOneFingerPanEnabled(boolean enabled) {
1055         Settings.Secure.putInt(mContext.getContentResolver(), KEY_SINGLE_FINGER_PANNING,
1056                 enabled ? ON : OFF);
1057     }
1058 
setAlwaysOnSupported(boolean supported)1059     private void setAlwaysOnSupported(boolean supported) {
1060         ShadowDeviceConfig.setProperty(
1061                 DeviceConfig.NAMESPACE_WINDOW_MANAGER,
1062                 "AlwaysOnMagnifier__enable_always_on_magnifier",
1063                 supported ? "true" : "false",
1064                 /* makeDefault= */ false);
1065     }
1066 
setKeyAlwaysOnEnabled(boolean enabled)1067     private void setKeyAlwaysOnEnabled(boolean enabled) {
1068         Settings.Secure.putInt(mContext.getContentResolver(), KEY_ALWAYS_ON,
1069                 enabled ? ON : OFF);
1070     }
1071 
setJoystickSupported(boolean supported)1072     private void setJoystickSupported(boolean supported) {
1073         ShadowDeviceConfig.setProperty(
1074                 DeviceConfig.NAMESPACE_WINDOW_MANAGER,
1075                 "MagnificationJoystick__enable_magnification_joystick",
1076                 supported ? "true" : "false",
1077                 /* makeDefault= */ false);
1078     }
1079 
setKeyJoystickEnabled(boolean enabled)1080     private void setKeyJoystickEnabled(boolean enabled) {
1081         Settings.Secure.putInt(mContext.getContentResolver(), KEY_JOYSTICK,
1082                 enabled ? ON : OFF);
1083     }
1084 
getStringFromSettings(String key)1085     private String getStringFromSettings(String key) {
1086         return Settings.Secure.getString(mContext.getContentResolver(), key);
1087     }
1088 
getMagnificationTripleTapStatus()1089     private boolean getMagnificationTripleTapStatus() {
1090         return Settings.Secure.getInt(mContext.getContentResolver(), TRIPLETAP_SHORTCUT_KEY, OFF)
1091                 == ON;
1092     }
1093 
callEmptyOnClicked(DialogInterface dialog, int which)1094     private void callEmptyOnClicked(DialogInterface dialog, int which) {
1095     }
1096 
setWindowMagnificationSupported(boolean magnificationAreaSupported, boolean windowMagnificationSupported)1097     private void setWindowMagnificationSupported(boolean magnificationAreaSupported,
1098             boolean windowMagnificationSupported) {
1099         when(mSpyResources.getBoolean(
1100                 com.android.internal.R.bool.config_magnification_area))
1101                 .thenReturn(magnificationAreaSupported);
1102         mShadowPackageManager.setSystemFeature(PackageManager.FEATURE_WINDOW_MAGNIFICATION,
1103                 windowMagnificationSupported);
1104     }
1105 
createEditShortcutDialog(Context context)1106     private AlertDialog createEditShortcutDialog(Context context) {
1107         context.setTheme(androidx.appcompat.R.style.Theme_AppCompat);
1108         return AccessibilityDialogUtils.showEditShortcutDialog(
1109                 context,
1110                 DialogType.EDIT_SHORTCUT_MAGNIFICATION, PLACEHOLDER_DIALOG_TITLE,
1111                 this::callEmptyOnClicked);
1112     }
1113 
createFragmentSavedInstanceState(int userShortcutType)1114     private Bundle createFragmentSavedInstanceState(int userShortcutType) {
1115         final Bundle savedInstanceState = new Bundle();
1116         savedInstanceState.putInt(KEY_SAVED_USER_SHORTCUT_TYPE, userShortcutType);
1117         final Bundle fragmentState = new Bundle();
1118         fragmentState.putBundle(
1119                 /* FragmentStateManager.SAVED_INSTANCE_STATE_KEY */ "savedInstanceState",
1120                 savedInstanceState);
1121         return fragmentState;
1122     }
1123 
1124     /**
1125      * A test fragment that provides a way to change the context
1126      */
1127     public static class TestToggleScreenMagnificationPreferenceFragment
1128             extends ToggleScreenMagnificationPreferenceFragment {
1129         private Context mContext;
1130 
1131         @Override
getContext()1132         public Context getContext() {
1133             return this.mContext != null ? this.mContext : super.getContext();
1134         }
1135 
1136         /**
1137          * Sets the spy context used for RoboTest in order to change the value of
1138          * com.android.internal.R.bool.config_magnification_area
1139          */
setContext(Context context)1140         public void setContext(Context context) {
1141             this.mContext = context;
1142         }
1143     }
1144 }
1145