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