1 /*
2  * Copyright (C) 2022 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.ToggleDaltonizerPreferenceFragment.KEY_DEUTERANOMALY;
22 import static com.android.settings.accessibility.ToggleDaltonizerPreferenceFragment.KEY_GRAYSCALE;
23 import static com.android.settings.accessibility.ToggleDaltonizerPreferenceFragment.KEY_PROTANOMALY;
24 import static com.android.settings.accessibility.ToggleDaltonizerPreferenceFragment.KEY_TRITANOMEALY;
25 import static com.android.settings.accessibility.ToggleDaltonizerPreferenceFragment.KEY_USE_SERVICE_PREFERENCE;
26 
27 import static com.google.common.truth.Truth.assertThat;
28 
29 import static org.mockito.Mockito.doReturn;
30 import static org.mockito.Mockito.mock;
31 import static org.mockito.Mockito.spy;
32 import static org.mockito.Mockito.when;
33 
34 import android.app.settings.SettingsEnums;
35 import android.content.ComponentName;
36 import android.content.Context;
37 import android.os.Bundle;
38 import android.platform.test.annotations.DisableFlags;
39 import android.platform.test.flag.junit.SetFlagsRule;
40 import android.provider.Settings;
41 import android.view.LayoutInflater;
42 import android.view.View;
43 import android.view.ViewGroup;
44 import android.view.accessibility.Flags;
45 import android.widget.PopupWindow;
46 
47 import androidx.fragment.app.FragmentActivity;
48 import androidx.preference.PreferenceManager;
49 import androidx.preference.PreferenceScreen;
50 import androidx.test.core.app.ApplicationProvider;
51 
52 import com.android.settings.R;
53 import com.android.settings.accessibility.AccessibilityUtil.QuickSettingsTooltipType;
54 import com.android.settings.testutils.XmlTestUtils;
55 import com.android.settings.testutils.shadow.ShadowFragment;
56 import com.android.settings.widget.SettingsMainSwitchPreference;
57 import com.android.settingslib.widget.SelectorWithWidgetPreference;
58 
59 import org.junit.Before;
60 import org.junit.Rule;
61 import org.junit.Test;
62 import org.junit.runner.RunWith;
63 import org.mockito.Answers;
64 import org.mockito.Mock;
65 import org.mockito.MockitoAnnotations;
66 import org.robolectric.RobolectricTestRunner;
67 import org.robolectric.annotation.Config;
68 import org.robolectric.shadow.api.Shadow;
69 import org.robolectric.shadows.ShadowApplication;
70 
71 import java.util.List;
72 
73 /** Tests for {@link ToggleDaltonizerPreferenceFragment} */
74 @RunWith(RobolectricTestRunner.class)
75 @Config(shadows = ShadowFragment.class)
76 public class ToggleDaltonizerPreferenceFragmentTest {
77     @Rule
78     public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
79     private final Context mContext = ApplicationProvider.getApplicationContext();
80     private TestToggleDaltonizerPreferenceFragment mFragment;
81     private PreferenceScreen mScreen;
82     private SettingsMainSwitchPreference mSwitchPreference;
83 
84     @Mock(answer = Answers.RETURNS_DEEP_STUBS)
85     private PreferenceManager mPreferenceManager;
86     @Mock
87     private SelectorWithWidgetPreference mMockDeuteranomalyPref;
88     @Mock
89     private SelectorWithWidgetPreference mMockProtanomalyPref;
90     @Mock
91     private SelectorWithWidgetPreference mMockTritanomalyPref;
92     @Mock
93     private SelectorWithWidgetPreference mMockGrayscalePref;
94     @Mock
95     private FragmentActivity mActivity;
96 
97     @Before
setUpTestFragment()98     public void setUpTestFragment() {
99         MockitoAnnotations.initMocks(this);
100 
101         mFragment = spy(new TestToggleDaltonizerPreferenceFragment(mContext));
102         when(mFragment.getPreferenceManager()).thenReturn(mPreferenceManager);
103         when(mFragment.getPreferenceManager().getContext()).thenReturn(mContext);
104         when(mFragment.getContext()).thenReturn(mContext);
105         when(mFragment.getActivity()).thenReturn(mActivity);
106         when(mActivity.getContentResolver()).thenReturn(mContext.getContentResolver());
107 
108         mScreen = spy(new PreferenceScreen(mContext, /* attrs= */ null));
109         when(mScreen.findPreference(KEY_USE_SERVICE_PREFERENCE))
110                 .thenReturn(mFragment.mToggleServiceSwitchPreference);
111         when(mScreen.findPreference(KEY_DEUTERANOMALY)).thenReturn(mMockDeuteranomalyPref);
112         when(mMockDeuteranomalyPref.getKey()).thenReturn(KEY_DEUTERANOMALY);
113         when(mScreen.findPreference(KEY_PROTANOMALY)).thenReturn(mMockProtanomalyPref);
114         when(mMockProtanomalyPref.getKey()).thenReturn(KEY_PROTANOMALY);
115         when(mScreen.findPreference(KEY_TRITANOMEALY)).thenReturn(mMockTritanomalyPref);
116         when(mMockTritanomalyPref.getKey()).thenReturn(KEY_TRITANOMEALY);
117         when(mScreen.findPreference(KEY_GRAYSCALE)).thenReturn(mMockGrayscalePref);
118         when(mMockGrayscalePref.getKey()).thenReturn(KEY_GRAYSCALE);
119         when(mScreen.getPreferenceManager()).thenReturn(mPreferenceManager);
120         doReturn(mScreen).when(mFragment).getPreferenceScreen();
121 
122         mSwitchPreference = mScreen.findPreference(KEY_USE_SERVICE_PREFERENCE);
123     }
124 
125     @Test
onResume_colorCorrectEnabled_shouldReturnTrue()126     public void onResume_colorCorrectEnabled_shouldReturnTrue() {
127         Settings.Secure.putInt(mContext.getContentResolver(),
128                 Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED, ON);
129         mFragment.onAttach(mContext);
130         mFragment.onCreate(Bundle.EMPTY);
131 
132         mFragment.onResume();
133 
134         assertThat(mSwitchPreference.isChecked()).isTrue();
135     }
136 
137     @Test
onResume_colorCorrectDisabled_shouldReturnFalse()138     public void onResume_colorCorrectDisabled_shouldReturnFalse() {
139         Settings.Secure.putInt(mContext.getContentResolver(),
140                 Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED, OFF);
141         mFragment.onAttach(mContext);
142         mFragment.onCreate(Bundle.EMPTY);
143 
144         mFragment.onResume();
145 
146         assertThat(mSwitchPreference.isChecked()).isFalse();
147     }
148 
149     @Test
onResume_colorCorrectEnabled_switchPreferenceChecked_notShowTooltips()150     public void onResume_colorCorrectEnabled_switchPreferenceChecked_notShowTooltips() {
151         Settings.Secure.putInt(mContext.getContentResolver(),
152                 Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED, ON);
153         mSwitchPreference.setChecked(true);
154         mFragment.onAttach(mContext);
155         mFragment.onCreate(Bundle.EMPTY);
156 
157         mFragment.onResume();
158 
159         assertThat(getLatestPopupWindow()).isNull();
160     }
161 
162     @Test
163     @DisableFlags(Flags.FLAG_A11Y_QS_SHORTCUT)
onPreferenceToggled_colorCorrectDisabled_shouldReturnTrueAndShowTooltipView()164     public void onPreferenceToggled_colorCorrectDisabled_shouldReturnTrueAndShowTooltipView() {
165         Settings.Secure.putInt(mContext.getContentResolver(),
166                 Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED, OFF);
167         mSwitchPreference.setChecked(false);
168         mFragment.onAttach(mContext);
169         mFragment.onCreateView(LayoutInflater.from(mContext), mock(ViewGroup.class), Bundle.EMPTY);
170         mFragment.onViewCreated(mFragment.getView(), Bundle.EMPTY);
171 
172         mFragment.onPreferenceToggled(mSwitchPreference.getKey(), true);
173 
174         final boolean isEnabled = Settings.Secure.getInt(mContext.getContentResolver(),
175                 Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED, OFF) == ON;
176         assertThat(isEnabled).isTrue();
177         assertThat(getLatestPopupWindow()).isNotNull();
178         assertThat(getLatestPopupWindow().isShowing()).isTrue();
179     }
180 
181     @Test
onPreferenceToggled_colorCorrectEnabled_shouldReturnFalseAndNotShowTooltipView()182     public void onPreferenceToggled_colorCorrectEnabled_shouldReturnFalseAndNotShowTooltipView() {
183         Settings.Secure.putInt(mContext.getContentResolver(),
184                 Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED, ON);
185         mSwitchPreference.setChecked(true);
186         mFragment.onAttach(mContext);
187         mFragment.onCreate(Bundle.EMPTY);
188 
189         mFragment.onPreferenceToggled(mSwitchPreference.getKey(), false);
190 
191         final boolean isEnabled = Settings.Secure.getInt(mContext.getContentResolver(),
192                 Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED, OFF) == ON;
193         assertThat(isEnabled).isFalse();
194         assertThat(getLatestPopupWindow()).isNull();
195     }
196 
197     @Test
getMetricsCategory_returnsCorrectCategory()198     public void getMetricsCategory_returnsCorrectCategory() {
199         assertThat(mFragment.getMetricsCategory()).isEqualTo(
200                 SettingsEnums.ACCESSIBILITY_TOGGLE_DALTONIZER);
201     }
202 
203     @Test
getPreferenceScreenResId_returnsCorrectXml()204     public void getPreferenceScreenResId_returnsCorrectXml() {
205         assertThat(mFragment.getPreferenceScreenResId()).isEqualTo(
206                 R.xml.accessibility_daltonizer_settings);
207     }
208 
209     @Test
getHelpResource_returnsCorrectHelpResource()210     public void getHelpResource_returnsCorrectHelpResource() {
211         assertThat(mFragment.getHelpResource()).isEqualTo(R.string.help_url_color_correction);
212     }
213 
214     @Test
getNonIndexableKeys_existInXmlLayout()215     public void getNonIndexableKeys_existInXmlLayout() {
216         final List<String> niks = ToggleDaltonizerPreferenceFragment.SEARCH_INDEX_DATA_PROVIDER
217                 .getNonIndexableKeys(mContext);
218         final List<String> keys =
219                 XmlTestUtils.getKeysFromPreferenceXml(mContext,
220                         R.xml.accessibility_daltonizer_settings);
221 
222         assertThat(keys).containsAtLeastElementsIn(niks);
223     }
224 
getLatestPopupWindow()225     private static PopupWindow getLatestPopupWindow() {
226         final ShadowApplication shadowApplication =
227                 Shadow.extract(ApplicationProvider.getApplicationContext());
228         return shadowApplication.getLatestPopupWindow();
229     }
230 
231     private static class TestToggleDaltonizerPreferenceFragment extends
232             ToggleDaltonizerPreferenceFragment {
233         private static final String PLACEHOLDER_PACKAGE_NAME = "com.placeholder.example";
234         private static final String PLACEHOLDER_CLASS_NAME =
235                 PLACEHOLDER_PACKAGE_NAME + ".placeholder";
236         private static final ComponentName PLACEHOLDER_COMPONENT_NAME = new ComponentName(
237                 PLACEHOLDER_PACKAGE_NAME, PLACEHOLDER_CLASS_NAME);
238         private static final String PLACEHOLDER_TILE_TOOLTIP_CONTENT =
239                 PLACEHOLDER_PACKAGE_NAME + "tooltip_content";
240 
TestToggleDaltonizerPreferenceFragment(Context context)241         TestToggleDaltonizerPreferenceFragment(Context context) {
242             super();
243             mComponentName = PLACEHOLDER_COMPONENT_NAME;
244             final SettingsMainSwitchPreference switchPreference =
245                     new SettingsMainSwitchPreference(context);
246             switchPreference.setKey(KEY_USE_SERVICE_PREFERENCE);
247             mToggleServiceSwitchPreference = switchPreference;
248             setArguments(new Bundle());
249         }
250 
251         @Override
onViewCreated(View view, Bundle savedInstanceState)252         public void onViewCreated(View view, Bundle savedInstanceState) {
253             // do nothing
254         }
255 
256         @Override
onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)257         public View onCreateView(LayoutInflater inflater, ViewGroup container,
258                 Bundle savedInstanceState) {
259             return mock(View.class);
260         }
261 
262         @Override
updateShortcutPreference()263         protected void updateShortcutPreference() {
264             // UI related function, do nothing in tests
265         }
266 
267         @Override
getTileComponentName()268         ComponentName getTileComponentName() {
269             return PLACEHOLDER_COMPONENT_NAME;
270         }
271 
272         @Override
getTileTooltipContent(@uickSettingsTooltipType int type)273         protected CharSequence getTileTooltipContent(@QuickSettingsTooltipType int type) {
274             return PLACEHOLDER_TILE_TOOLTIP_CONTENT;
275         }
276 
277         @Override
getView()278         public View getView() {
279             return mock(View.class);
280         }
281     }
282 }
283