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.accessibility; 18 19 import static com.android.settings.accessibility.ToggleFeaturePreferenceFragment.KEY_SAVED_USER_SHORTCUT_TYPE; 20 21 import static com.google.common.truth.Truth.assertThat; 22 23 import static org.mockito.Mockito.doReturn; 24 import static org.mockito.Mockito.mock; 25 import static org.mockito.Mockito.spy; 26 import static org.mockito.Mockito.verify; 27 import static org.mockito.Mockito.when; 28 29 import android.content.ComponentName; 30 import android.content.Context; 31 import android.content.DialogInterface; 32 import android.os.Bundle; 33 import android.provider.Settings; 34 import android.view.LayoutInflater; 35 import android.view.View; 36 import android.view.ViewGroup; 37 38 import androidx.annotation.XmlRes; 39 import androidx.appcompat.app.AlertDialog; 40 import androidx.fragment.app.FragmentActivity; 41 import androidx.preference.PreferenceManager; 42 import androidx.preference.PreferenceScreen; 43 import androidx.test.core.app.ApplicationProvider; 44 45 import com.android.settings.R; 46 import com.android.settings.accessibility.AccessibilityDialogUtils.DialogType; 47 import com.android.settings.accessibility.AccessibilityUtil.UserShortcutType; 48 import com.android.settings.testutils.shadow.ShadowFragment; 49 50 import org.junit.Before; 51 import org.junit.Test; 52 import org.junit.runner.RunWith; 53 import org.mockito.Answers; 54 import org.mockito.Mock; 55 import org.mockito.MockitoAnnotations; 56 import org.robolectric.RobolectricTestRunner; 57 import org.robolectric.annotation.Config; 58 import org.robolectric.shadows.androidx.fragment.FragmentController; 59 60 /** Tests for {@link ToggleFeaturePreferenceFragment} */ 61 @RunWith(RobolectricTestRunner.class) 62 public class ToggleFeaturePreferenceFragmentTest { 63 64 private static final String PLACEHOLDER_PACKAGE_NAME = "com.placeholder.example"; 65 private static final String PLACEHOLDER_CLASS_NAME = PLACEHOLDER_PACKAGE_NAME + ".placeholder"; 66 private static final ComponentName PLACEHOLDER_COMPONENT_NAME = new ComponentName( 67 PLACEHOLDER_PACKAGE_NAME, PLACEHOLDER_CLASS_NAME); 68 private static final String PLACEHOLDER_DIALOG_TITLE = "title"; 69 private static final String DEFAULT_SUMMARY = "default summary"; 70 private static final String DEFAULT_DESCRIPTION = "default description"; 71 72 private static final String SOFTWARE_SHORTCUT_KEY = 73 Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS; 74 private static final String HARDWARE_SHORTCUT_KEY = 75 Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE; 76 77 private TestToggleFeaturePreferenceFragment mFragment; 78 private PreferenceScreen mScreen; 79 private Context mContext = ApplicationProvider.getApplicationContext(); 80 81 @Mock(answer = Answers.RETURNS_DEEP_STUBS) 82 private PreferenceManager mPreferenceManager; 83 84 @Before setUpTestFragment()85 public void setUpTestFragment() { 86 MockitoAnnotations.initMocks(this); 87 88 mFragment = spy(new TestToggleFeaturePreferenceFragment()); 89 when(mFragment.getPreferenceManager()).thenReturn(mPreferenceManager); 90 when(mFragment.getPreferenceManager().getContext()).thenReturn(mContext); 91 when(mFragment.getContext()).thenReturn(mContext); 92 mScreen = spy(new PreferenceScreen(mContext, null)); 93 when(mScreen.getPreferenceManager()).thenReturn(mPreferenceManager); 94 doReturn(mScreen).when(mFragment).getPreferenceScreen(); 95 } 96 97 @Test createFragment_shouldOnlyAddPreferencesOnce()98 public void createFragment_shouldOnlyAddPreferencesOnce() { 99 FragmentController.setupFragment(mFragment, FragmentActivity.class, 100 /* containerViewId= */ 0, /* bundle= */ null); 101 102 // execute exactly once 103 verify(mFragment).addPreferencesFromResource(R.xml.placeholder_prefs); 104 } 105 106 @Test updateShortcutPreferenceData_assignDefaultValueToVariable()107 public void updateShortcutPreferenceData_assignDefaultValueToVariable() { 108 mFragment.mComponentName = PLACEHOLDER_COMPONENT_NAME; 109 110 mFragment.updateShortcutPreferenceData(); 111 112 final int expectedType = PreferredShortcuts.retrieveUserShortcutType(mContext, 113 mFragment.mComponentName.flattenToString(), UserShortcutType.SOFTWARE); 114 // Compare to default UserShortcutType 115 assertThat(expectedType).isEqualTo(UserShortcutType.SOFTWARE); 116 } 117 118 @Test updateShortcutPreferenceData_hasValueInSettings_assignToVariable()119 public void updateShortcutPreferenceData_hasValueInSettings_assignToVariable() { 120 mFragment.mComponentName = PLACEHOLDER_COMPONENT_NAME; 121 putStringIntoSettings(SOFTWARE_SHORTCUT_KEY, PLACEHOLDER_COMPONENT_NAME.flattenToString()); 122 putStringIntoSettings(HARDWARE_SHORTCUT_KEY, PLACEHOLDER_COMPONENT_NAME.flattenToString()); 123 124 mFragment.updateShortcutPreferenceData(); 125 126 final int expectedType = PreferredShortcuts.retrieveUserShortcutType(mContext, 127 mFragment.mComponentName.flattenToString(), UserShortcutType.SOFTWARE); 128 assertThat(expectedType).isEqualTo(UserShortcutType.SOFTWARE | UserShortcutType.HARDWARE); 129 } 130 131 @Test updateShortcutPreferenceData_hasValueInSharedPreference_assignToVariable()132 public void updateShortcutPreferenceData_hasValueInSharedPreference_assignToVariable() { 133 mFragment.mComponentName = PLACEHOLDER_COMPONENT_NAME; 134 final PreferredShortcut hardwareShortcut = new PreferredShortcut( 135 PLACEHOLDER_COMPONENT_NAME.flattenToString(), UserShortcutType.HARDWARE); 136 137 putUserShortcutTypeIntoSharedPreference(mContext, hardwareShortcut); 138 mFragment.updateShortcutPreferenceData(); 139 140 final int expectedType = PreferredShortcuts.retrieveUserShortcutType(mContext, 141 mFragment.mComponentName.flattenToString(), UserShortcutType.SOFTWARE); 142 assertThat(expectedType).isEqualTo(UserShortcutType.HARDWARE); 143 } 144 145 @Test setupEditShortcutDialog_shortcutPreferenceOff_checkboxIsEmptyValue()146 public void setupEditShortcutDialog_shortcutPreferenceOff_checkboxIsEmptyValue() { 147 mContext.setTheme(R.style.Theme_AppCompat); 148 final AlertDialog dialog = AccessibilityDialogUtils.showEditShortcutDialog( 149 mContext, DialogType.EDIT_SHORTCUT_GENERIC, PLACEHOLDER_DIALOG_TITLE, 150 this::callEmptyOnClicked); 151 final ShortcutPreference shortcutPreference = new ShortcutPreference(mContext, /* attrs= */ 152 null); 153 mFragment.mComponentName = PLACEHOLDER_COMPONENT_NAME; 154 mFragment.mShortcutPreference = shortcutPreference; 155 156 mFragment.mShortcutPreference.setChecked(false); 157 mFragment.setupEditShortcutDialog(dialog); 158 159 final int checkboxValue = mFragment.getShortcutTypeCheckBoxValue(); 160 assertThat(checkboxValue).isEqualTo(UserShortcutType.EMPTY); 161 } 162 163 @Test setupEditShortcutDialog_shortcutPreferenceOn_checkboxIsSavedValue()164 public void setupEditShortcutDialog_shortcutPreferenceOn_checkboxIsSavedValue() { 165 mContext.setTheme(R.style.Theme_AppCompat); 166 final AlertDialog dialog = AccessibilityDialogUtils.showEditShortcutDialog( 167 mContext, DialogType.EDIT_SHORTCUT_GENERIC, PLACEHOLDER_DIALOG_TITLE, 168 this::callEmptyOnClicked); 169 final ShortcutPreference shortcutPreference = new ShortcutPreference(mContext, /* attrs= */ 170 null); 171 final PreferredShortcut hardwareShortcut = new PreferredShortcut( 172 PLACEHOLDER_COMPONENT_NAME.flattenToString(), UserShortcutType.HARDWARE); 173 mFragment.mComponentName = PLACEHOLDER_COMPONENT_NAME; 174 mFragment.mShortcutPreference = shortcutPreference; 175 176 PreferredShortcuts.saveUserShortcutType(mContext, hardwareShortcut); 177 mFragment.mShortcutPreference.setChecked(true); 178 mFragment.setupEditShortcutDialog(dialog); 179 180 final int checkboxValue = mFragment.getShortcutTypeCheckBoxValue(); 181 assertThat(checkboxValue).isEqualTo(UserShortcutType.HARDWARE); 182 } 183 184 @Test 185 @Config(shadows = ShadowFragment.class) restoreValueFromSavedInstanceState_assignToVariable()186 public void restoreValueFromSavedInstanceState_assignToVariable() { 187 mContext.setTheme(R.style.Theme_AppCompat); 188 final AlertDialog dialog = AccessibilityDialogUtils.showEditShortcutDialog( 189 mContext, DialogType.EDIT_SHORTCUT_GENERIC, PLACEHOLDER_DIALOG_TITLE, 190 this::callEmptyOnClicked); 191 final Bundle savedInstanceState = new Bundle(); 192 final ShortcutPreference shortcutPreference = new ShortcutPreference(mContext, /* attrs= */ 193 null); 194 mFragment.mComponentName = PLACEHOLDER_COMPONENT_NAME; 195 mFragment.mShortcutPreference = shortcutPreference; 196 197 savedInstanceState.putInt(KEY_SAVED_USER_SHORTCUT_TYPE, 198 UserShortcutType.SOFTWARE | UserShortcutType.HARDWARE); 199 mFragment.onCreate(savedInstanceState); 200 mFragment.setupEditShortcutDialog(dialog); 201 final int value = mFragment.getShortcutTypeCheckBoxValue(); 202 mFragment.saveNonEmptyUserShortcutType(value); 203 204 final int expectedType = PreferredShortcuts.retrieveUserShortcutType(mContext, 205 mFragment.mComponentName.flattenToString(), UserShortcutType.SOFTWARE); 206 assertThat(expectedType).isEqualTo(UserShortcutType.SOFTWARE | UserShortcutType.HARDWARE); 207 } 208 209 @Test createFooterPreference_shouldSetAsExpectedValue()210 public void createFooterPreference_shouldSetAsExpectedValue() { 211 mFragment.createFooterPreference(mFragment.getPreferenceScreen(), 212 DEFAULT_SUMMARY, DEFAULT_DESCRIPTION); 213 214 AccessibilityFooterPreference accessibilityFooterPreference = 215 (AccessibilityFooterPreference) mFragment.getPreferenceScreen().getPreference( 216 mFragment.getPreferenceScreen().getPreferenceCount() - 1); 217 assertThat(accessibilityFooterPreference.getSummary()).isEqualTo(DEFAULT_SUMMARY); 218 assertThat(accessibilityFooterPreference.isSelectable()).isEqualTo(true); 219 assertThat(accessibilityFooterPreference.getOrder()).isEqualTo(Integer.MAX_VALUE - 1); 220 } 221 putStringIntoSettings(String key, String componentName)222 private void putStringIntoSettings(String key, String componentName) { 223 Settings.Secure.putString(mContext.getContentResolver(), key, componentName); 224 } 225 putUserShortcutTypeIntoSharedPreference(Context context, PreferredShortcut shortcut)226 private void putUserShortcutTypeIntoSharedPreference(Context context, 227 PreferredShortcut shortcut) { 228 PreferredShortcuts.saveUserShortcutType(context, shortcut); 229 } 230 callEmptyOnClicked(DialogInterface dialog, int which)231 private void callEmptyOnClicked(DialogInterface dialog, int which) {} 232 233 public static class TestToggleFeaturePreferenceFragment 234 extends ToggleFeaturePreferenceFragment { 235 236 @Override onPreferenceToggled(String preferenceKey, boolean enabled)237 protected void onPreferenceToggled(String preferenceKey, boolean enabled) { 238 } 239 240 @Override getMetricsCategory()241 public int getMetricsCategory() { 242 return 0; 243 } 244 245 @Override getUserShortcutTypes()246 int getUserShortcutTypes() { 247 return 0; 248 } 249 250 @Override getPreferenceScreenResId()251 public int getPreferenceScreenResId() { 252 return R.xml.placeholder_prefs; 253 } 254 255 @Override onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)256 public View onCreateView(LayoutInflater inflater, ViewGroup container, 257 Bundle savedInstanceState) { 258 return mock(View.class); 259 } 260 261 @Override onViewCreated(View view, Bundle savedInstanceState)262 public void onViewCreated(View view, Bundle savedInstanceState) { 263 // do nothing 264 } 265 266 @Override onDestroyView()267 public void onDestroyView() { 268 // do nothing 269 } 270 271 @Override addPreferencesFromResource(@mlRes int preferencesResId)272 public void addPreferencesFromResource(@XmlRes int preferencesResId) { 273 // do nothing 274 } 275 276 @Override updateShortcutPreference()277 protected void updateShortcutPreference() { 278 // UI related function, do nothing in tests 279 } 280 281 } 282 } 283