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.ToggleFeaturePreferenceFragment.KEY_SAVED_QS_TOOLTIP_RESHOW; 20 21 import static com.google.common.truth.Truth.assertThat; 22 23 import static org.mockito.Mockito.doReturn; 24 import static org.mockito.Mockito.spy; 25 import static org.mockito.Mockito.when; 26 27 import android.content.ComponentName; 28 import android.content.Context; 29 import android.os.Bundle; 30 import android.view.LayoutInflater; 31 import android.widget.LinearLayout; 32 import android.widget.PopupWindow; 33 34 import androidx.preference.PreferenceManager; 35 import androidx.preference.PreferenceScreen; 36 import androidx.preference.PreferenceViewHolder; 37 import androidx.test.core.app.ApplicationProvider; 38 39 import com.android.settings.R; 40 import com.android.settings.SettingsPreferenceFragment; 41 import com.android.settings.testutils.shadow.ShadowFragment; 42 import com.android.settingslib.PrimarySwitchPreference; 43 44 import org.junit.Before; 45 import org.junit.Rule; 46 import org.junit.Test; 47 import org.junit.runner.RunWith; 48 import org.mockito.Answers; 49 import org.mockito.Mock; 50 import org.mockito.MockitoAnnotations; 51 import org.mockito.Spy; 52 import org.mockito.junit.MockitoJUnit; 53 import org.mockito.junit.MockitoRule; 54 import org.robolectric.RobolectricTestRunner; 55 import org.robolectric.annotation.Config; 56 import org.robolectric.shadow.api.Shadow; 57 import org.robolectric.shadows.ShadowApplication; 58 import org.robolectric.shadows.ShadowLooper; 59 60 /** 61 * Tests for {@link AccessibilityQuickSettingsPrimarySwitchPreferenceController}. 62 */ 63 @RunWith(RobolectricTestRunner.class) 64 public class AccessibilityQuickSettingsPrimarySwitchPreferenceControllerTest { 65 66 private static final String PLACEHOLDER_PACKAGE_NAME = "com.placeholder.example"; 67 private static final String PLACEHOLDER_TILE_CLASS_NAME = 68 PLACEHOLDER_PACKAGE_NAME + "tile.placeholder"; 69 private static final ComponentName PLACEHOLDER_TILE_COMPONENT_NAME = new ComponentName( 70 PLACEHOLDER_PACKAGE_NAME, PLACEHOLDER_TILE_CLASS_NAME); 71 private static final CharSequence PLACEHOLDER_TILE_CONTENT = 72 PLACEHOLDER_TILE_CLASS_NAME + ".tile.content"; 73 private static final String TEST_KEY = "test_pref_key"; 74 private static final String TEST_TITLE = "test_title"; 75 76 @Rule 77 public final MockitoRule mockito = MockitoJUnit.rule(); 78 79 @Spy 80 private final Context mContext = ApplicationProvider.getApplicationContext(); 81 82 private TestAccessibilityQuickSettingsPrimarySwitchPreferenceController mController; 83 private PrimarySwitchPreference mPreference; 84 private TestFragment mFragment; 85 private PreferenceScreen mScreen; 86 private PreferenceViewHolder mHolder; 87 @Mock(answer = Answers.RETURNS_DEEP_STUBS) 88 private PreferenceManager mPreferenceManager; 89 getLatestPopupWindow()90 private static PopupWindow getLatestPopupWindow() { 91 final ShadowApplication shadowApplication = 92 Shadow.extract(ApplicationProvider.getApplicationContext()); 93 return shadowApplication.getLatestPopupWindow(); 94 } 95 96 @Before setUp()97 public void setUp() { 98 MockitoAnnotations.initMocks(this); 99 100 mContext.setTheme(androidx.appcompat.R.style.Theme_AppCompat); 101 mFragment = spy(new TestFragment()); 102 when(mFragment.getPreferenceManager()).thenReturn(mPreferenceManager); 103 when(mFragment.getPreferenceManager().getContext()).thenReturn(mContext); 104 when(mFragment.getContext()).thenReturn(mContext); 105 mScreen = spy(new PreferenceScreen(mContext, /* attrs= */ null)); 106 when(mScreen.getPreferenceManager()).thenReturn(mPreferenceManager); 107 doReturn(mScreen).when(mFragment).getPreferenceScreen(); 108 109 mPreference = new PrimarySwitchPreference(mContext); 110 mPreference.setKey(TEST_KEY); 111 mPreference.setTitle(TEST_TITLE); 112 LayoutInflater inflater = LayoutInflater.from(mContext); 113 mHolder = PreferenceViewHolder.createInstanceForTests(inflater.inflate( 114 com.android.settingslib.widget.preference.twotarget.R.layout.preference_two_target, null)); 115 LinearLayout mWidgetView = mHolder.itemView.findViewById(android.R.id.widget_frame); 116 inflater.inflate(R.layout.preference_widget_primary_switch, mWidgetView, true); 117 mPreference.onBindViewHolder(mHolder); 118 119 mController = new TestAccessibilityQuickSettingsPrimarySwitchPreferenceController(mContext, 120 TEST_KEY); 121 when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mPreference); 122 } 123 124 @Test setChecked_showTooltipView()125 public void setChecked_showTooltipView() { 126 mController.displayPreference(mScreen); 127 128 mController.setChecked(true); 129 130 assertThat(getLatestPopupWindow().isShowing()).isTrue(); 131 } 132 133 @Test setChecked_notCallDisplayPreference_notShowTooltipView()134 public void setChecked_notCallDisplayPreference_notShowTooltipView() { 135 // Simulates the slice highlight menu that does not call {@link #displayPreference} before 136 // {@link #setChecked} called. 137 mController.setChecked(true); 138 139 assertThat(getLatestPopupWindow()).isNull(); 140 } 141 142 @Test setChecked_tooltipViewShown_notShowTooltipView()143 public void setChecked_tooltipViewShown_notShowTooltipView() { 144 mController.displayPreference(mScreen); 145 mController.setChecked(true); 146 getLatestPopupWindow().dismiss(); 147 mController.setChecked(false); 148 149 mController.setChecked(true); 150 151 assertThat(getLatestPopupWindow().isShowing()).isFalse(); 152 } 153 154 @Test 155 @Config(shadows = ShadowFragment.class) restoreValueFromSavedInstanceState_showTooltipView()156 public void restoreValueFromSavedInstanceState_showTooltipView() { 157 final Bundle savedInstanceState = new Bundle(); 158 savedInstanceState.putBoolean(KEY_SAVED_QS_TOOLTIP_RESHOW, /* value= */ true); 159 mController.onCreate(savedInstanceState); 160 161 mController.displayPreference(mScreen); 162 ShadowLooper.idleMainLooper(); 163 164 assertThat(getLatestPopupWindow().isShowing()).isTrue(); 165 } 166 167 public static class TestAccessibilityQuickSettingsPrimarySwitchPreferenceController 168 extends AccessibilityQuickSettingsPrimarySwitchPreferenceController { 169 TestAccessibilityQuickSettingsPrimarySwitchPreferenceController(Context context, String preferenceKey)170 public TestAccessibilityQuickSettingsPrimarySwitchPreferenceController(Context context, 171 String preferenceKey) { 172 super(context, preferenceKey); 173 } 174 175 @Override getTileComponentName()176 ComponentName getTileComponentName() { 177 return PLACEHOLDER_TILE_COMPONENT_NAME; 178 } 179 180 @Override getTileTooltipContent()181 CharSequence getTileTooltipContent() { 182 return PLACEHOLDER_TILE_CONTENT; 183 } 184 } 185 186 private static class TestFragment extends SettingsPreferenceFragment { 187 188 @Override shouldSkipForInitialSUW()189 protected boolean shouldSkipForInitialSUW() { 190 return false; 191 } 192 193 @Override getMetricsCategory()194 public int getMetricsCategory() { 195 return 0; 196 } 197 } 198 } 199