blob: 5f02fad06b50c48327d2fe94b67b81707c7d9a95 [file] [log] [blame]
Julia Reynolds561d3f42018-01-26 11:31:02 -05001/*
2 * Copyright (C) 2018 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
17package com.android.systemui.volume;
18
Julia Reynolds45d4ab02018-01-31 14:59:14 -050019import static android.media.AudioManager.RINGER_MODE_NORMAL;
20import static android.media.AudioManager.RINGER_MODE_SILENT;
21import static android.media.AudioManager.RINGER_MODE_VIBRATE;
22import static android.media.AudioManager.STREAM_RING;
23
Julia Reynolds561d3f42018-01-26 11:31:02 -050024import static com.android.systemui.volume.Events.DISMISS_REASON_UNKNOWN;
25import static com.android.systemui.volume.Events.SHOW_REASON_UNKNOWN;
26import static com.android.systemui.volume.VolumeDialogControllerImpl.STREAMS;
27
28import static junit.framework.Assert.assertTrue;
29
Rhed Jao46842232018-11-12 14:37:20 +080030import static org.mockito.ArgumentMatchers.any;
Julia Reynolds45d4ab02018-01-31 14:59:14 -050031import static org.mockito.Mockito.times;
32import static org.mockito.Mockito.verify;
33import static org.mockito.Mockito.when;
34
Julia Reynolds561d3f42018-01-26 11:31:02 -050035import android.app.KeyguardManager;
36import android.media.AudioManager;
Rhed Jao46842232018-11-12 14:37:20 +080037import android.os.SystemClock;
Julia Reynolds561d3f42018-01-26 11:31:02 -050038import android.support.test.filters.SmallTest;
39import android.testing.AndroidTestingRunner;
40import android.testing.TestableLooper;
41import android.text.TextUtils;
Rhed Jao46842232018-11-12 14:37:20 +080042import android.view.InputDevice;
43import android.view.MotionEvent;
Julia Reynolds561d3f42018-01-26 11:31:02 -050044import android.view.View;
45import android.view.ViewGroup;
Rhed Jao46842232018-11-12 14:37:20 +080046import android.view.accessibility.AccessibilityManager;
Julia Reynolds561d3f42018-01-26 11:31:02 -050047import android.widget.ImageView;
48
Julia Reynolds45d4ab02018-01-31 14:59:14 -050049import com.android.systemui.R;
Julia Reynolds561d3f42018-01-26 11:31:02 -050050import com.android.systemui.SysuiTestCase;
51import com.android.systemui.plugins.VolumeDialogController;
Julia Reynolds45d4ab02018-01-31 14:59:14 -050052import com.android.systemui.plugins.VolumeDialogController.State;
Julia Reynolds561d3f42018-01-26 11:31:02 -050053import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper;
54
55import org.junit.Before;
56import org.junit.Test;
57import org.junit.runner.RunWith;
Rhed Jao46842232018-11-12 14:37:20 +080058import org.mockito.ArgumentCaptor;
Julia Reynolds561d3f42018-01-26 11:31:02 -050059import org.mockito.Mock;
Rhed Jao46842232018-11-12 14:37:20 +080060import org.mockito.Mockito;
Julia Reynolds561d3f42018-01-26 11:31:02 -050061import org.mockito.MockitoAnnotations;
62
63import java.util.function.Predicate;
64
65@SmallTest
66@RunWith(AndroidTestingRunner.class)
67@TestableLooper.RunWithLooper
68public class VolumeDialogImplTest extends SysuiTestCase {
69
70 VolumeDialogImpl mDialog;
71
72 @Mock
73 VolumeDialogController mController;
74
75 @Mock
76 KeyguardManager mKeyguard;
77
78 @Mock
79 AccessibilityManagerWrapper mAccessibilityMgr;
80
81 @Before
82 public void setup() throws Exception {
83 MockitoAnnotations.initMocks(this);
84
85 mController = mDependency.injectMockDependency(VolumeDialogController.class);
86 mAccessibilityMgr = mDependency.injectMockDependency(AccessibilityManagerWrapper.class);
87 getContext().addMockSystemService(KeyguardManager.class, mKeyguard);
88
89 mDialog = new VolumeDialogImpl(getContext());
90 mDialog.init(0, null);
Julia Reynolds45d4ab02018-01-31 14:59:14 -050091 State state = createShellState();
92 mDialog.onStateChangedH(state);
93 }
94
95 private State createShellState() {
96 State state = new VolumeDialogController.State();
Julia Reynolds561d3f42018-01-26 11:31:02 -050097 for (int i = AudioManager.STREAM_VOICE_CALL; i <= AudioManager.STREAM_ACCESSIBILITY; i++) {
98 VolumeDialogController.StreamState ss = new VolumeDialogController.StreamState();
99 ss.name = STREAMS.get(i);
Julia Reynolds45d4ab02018-01-31 14:59:14 -0500100 ss.level = 1;
Julia Reynolds561d3f42018-01-26 11:31:02 -0500101 state.states.append(i, ss);
102 }
Julia Reynolds45d4ab02018-01-31 14:59:14 -0500103 return state;
Julia Reynolds561d3f42018-01-26 11:31:02 -0500104 }
105
106 private void navigateViews(View view, Predicate<View> condition) {
107 if (view instanceof ViewGroup) {
108 ViewGroup viewGroup = (ViewGroup) view;
109 for (int i = 0; i < viewGroup.getChildCount(); i++) {
110 navigateViews(viewGroup.getChildAt(i), condition);
111 }
112 } else {
113 String resourceName = null;
114 try {
115 resourceName = getContext().getResources().getResourceName(view.getId());
116 } catch (Exception e) {}
117 assertTrue("View " + resourceName != null ? resourceName : view.getId()
118 + " failed test", condition.test(view));
119 }
120 }
Rhed Jao46842232018-11-12 14:37:20 +0800121
122 @Test
123 public void testComputeTimeout() {
124 Mockito.reset(mAccessibilityMgr);
125 mDialog.rescheduleTimeoutH();
126 verify(mAccessibilityMgr).getRecommendedTimeoutMillis(
127 VolumeDialogImpl.DIALOG_TIMEOUT_MILLIS,
128 AccessibilityManager.FLAG_CONTENT_CONTROLS);
129 }
130
131 @Test
132 public void testComputeTimeout_withHovering() {
133 Mockito.reset(mAccessibilityMgr);
134 View dialog = mDialog.getDialogView();
135 long uptimeMillis = SystemClock.uptimeMillis();
136 MotionEvent event = MotionEvent.obtain(uptimeMillis, uptimeMillis,
137 MotionEvent.ACTION_HOVER_ENTER, 0, 0, 0);
138 event.setSource(InputDevice.SOURCE_TOUCHSCREEN);
139 dialog.dispatchGenericMotionEvent(event);
140 event.recycle();
141 verify(mAccessibilityMgr).getRecommendedTimeoutMillis(
142 VolumeDialogImpl.DIALOG_HOVERING_TIMEOUT_MILLIS,
143 AccessibilityManager.FLAG_CONTENT_CONTROLS);
144 }
145
146 @Test
147 public void testComputeTimeout_withSafetyWarningOn() {
148 Mockito.reset(mAccessibilityMgr);
149 ArgumentCaptor<VolumeDialogController.Callbacks> controllerCallbackCapture =
150 ArgumentCaptor.forClass(VolumeDialogController.Callbacks.class);
151 verify(mController).addCallback(controllerCallbackCapture.capture(), any());
152 VolumeDialogController.Callbacks callbacks = controllerCallbackCapture.getValue();
153 callbacks.onShowSafetyWarning(AudioManager.FLAG_SHOW_UI);
154 verify(mAccessibilityMgr).getRecommendedTimeoutMillis(
155 VolumeDialogImpl.DIALOG_SAFETYWARNING_TIMEOUT_MILLIS,
156 AccessibilityManager.FLAG_CONTENT_TEXT
157 | AccessibilityManager.FLAG_CONTENT_CONTROLS);
158 }
159
Julia Reynoldse904fb32018-02-01 09:27:13 -0500160/*
Julia Reynolds561d3f42018-01-26 11:31:02 -0500161 @Test
162 public void testContentDescriptions() {
163 mDialog.show(SHOW_REASON_UNKNOWN);
164 ViewGroup dialog = mDialog.getDialogView();
165
166 navigateViews(dialog, view -> {
167 if (view instanceof ImageView) {
168 return !TextUtils.isEmpty(view.getContentDescription());
169 } else {
170 return true;
171 }
172 });
173
174 mDialog.dismiss(DISMISS_REASON_UNKNOWN);
175 }
176
Julia Reynolds45d4ab02018-01-31 14:59:14 -0500177 @Test
178 public void testNoDuplicationOfParentState() {
179 mDialog.show(SHOW_REASON_UNKNOWN);
180 ViewGroup dialog = mDialog.getDialogView();
181
182 navigateViews(dialog, view -> !view.isDuplicateParentStateEnabled());
183
184 mDialog.dismiss(DISMISS_REASON_UNKNOWN);
185 }
186
187 @Test
188 public void testNoClickableViewGroups() {
189 mDialog.show(SHOW_REASON_UNKNOWN);
190 ViewGroup dialog = mDialog.getDialogView();
191
192 navigateViews(dialog, view -> {
193 if (view instanceof ViewGroup) {
194 return !view.isClickable();
195 } else {
196 return true;
197 }
198 });
199
200 mDialog.dismiss(DISMISS_REASON_UNKNOWN);
201 }
202
203 @Test
204 public void testTristateToggle_withVibrator() {
205 when(mController.hasVibrator()).thenReturn(true);
206
207 State state = createShellState();
208 state.ringerModeInternal = RINGER_MODE_NORMAL;
209 mDialog.onStateChangedH(state);
210
211 mDialog.show(SHOW_REASON_UNKNOWN);
212 ViewGroup dialog = mDialog.getDialogView();
213
214 // click once, verify updates to vibrate
215 dialog.findViewById(R.id.ringer_icon).performClick();
216 verify(mController, times(1)).setRingerMode(RINGER_MODE_VIBRATE, false);
217
218 // fake the update back to the dialog with the new ringer mode
219 state = createShellState();
220 state.ringerModeInternal = RINGER_MODE_VIBRATE;
221 mDialog.onStateChangedH(state);
222
223 // click once, verify updates to silent
224 dialog.findViewById(R.id.ringer_icon).performClick();
225 verify(mController, times(1)).setRingerMode(RINGER_MODE_SILENT, false);
226 verify(mController, times(1)).setStreamVolume(STREAM_RING, 0);
227
228 // fake the update back to the dialog with the new ringer mode
229 state = createShellState();
230 state.states.get(STREAM_RING).level = 0;
231 state.ringerModeInternal = RINGER_MODE_SILENT;
232 mDialog.onStateChangedH(state);
233
234 // click once, verify updates to normal
235 dialog.findViewById(R.id.ringer_icon).performClick();
236 verify(mController, times(1)).setRingerMode(RINGER_MODE_NORMAL, false);
237 verify(mController, times(1)).setStreamVolume(STREAM_RING, 0);
238 }
239
240 @Test
241 public void testTristateToggle_withoutVibrator() {
242 when(mController.hasVibrator()).thenReturn(false);
243
244 State state = createShellState();
245 state.ringerModeInternal = RINGER_MODE_NORMAL;
246 mDialog.onStateChangedH(state);
247
248 mDialog.show(SHOW_REASON_UNKNOWN);
249 ViewGroup dialog = mDialog.getDialogView();
250
251 // click once, verify updates to silent
252 dialog.findViewById(R.id.ringer_icon).performClick();
253 verify(mController, times(1)).setRingerMode(RINGER_MODE_SILENT, false);
254 verify(mController, times(1)).setStreamVolume(STREAM_RING, 0);
255
256 // fake the update back to the dialog with the new ringer mode
257 state = createShellState();
258 state.states.get(STREAM_RING).level = 0;
259 state.ringerModeInternal = RINGER_MODE_SILENT;
260 mDialog.onStateChangedH(state);
261
262 // click once, verify updates to normal
263 dialog.findViewById(R.id.ringer_icon).performClick();
264 verify(mController, times(1)).setRingerMode(RINGER_MODE_NORMAL, false);
265 verify(mController, times(1)).setStreamVolume(STREAM_RING, 0);
266 }
Julia Reynoldse904fb32018-02-01 09:27:13 -0500267 */
Julia Reynolds561d3f42018-01-26 11:31:02 -0500268}