• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 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 android.os.cts;
18 
19 import static com.google.common.truth.Truth.assertThat;
20 import static com.google.common.truth.Truth.assertWithMessage;
21 
22 import static org.junit.Assume.assumeTrue;
23 import static org.mockito.ArgumentMatchers.eq;
24 import static org.mockito.Mockito.clearInvocations;
25 import static org.mockito.Mockito.mock;
26 import static org.mockito.Mockito.timeout;
27 import static org.mockito.Mockito.verify;
28 
29 import android.content.Context;
30 import android.os.CombinedVibration;
31 import android.os.SystemClock;
32 import android.os.VibrationAttributes;
33 import android.os.VibrationEffect;
34 import android.os.Vibrator;
35 import android.os.Vibrator.OnVibratorStateChangedListener;
36 import android.os.VibratorManager;
37 import android.provider.Settings;
38 import android.util.SparseArray;
39 
40 import androidx.test.filters.LargeTest;
41 import androidx.test.platform.app.InstrumentationRegistry;
42 import androidx.test.runner.AndroidJUnit4;
43 
44 import com.android.compatibility.common.util.AdoptShellPermissionsRule;
45 
46 import org.junit.After;
47 import org.junit.Before;
48 import org.junit.Rule;
49 import org.junit.Test;
50 import org.junit.runner.RunWith;
51 import org.mockito.junit.MockitoJUnit;
52 import org.mockito.junit.MockitoRule;
53 
54 import java.util.Arrays;
55 
56 @RunWith(AndroidJUnit4.class)
57 public class VibratorManagerTest {
58 
59     @Rule
60     public final AdoptShellPermissionsRule mAdoptShellPermissionsRule =
61             new AdoptShellPermissionsRule(
62                     InstrumentationRegistry.getInstrumentation().getUiAutomation(),
63                     android.Manifest.permission.ACCESS_VIBRATOR_STATE,
64                     android.Manifest.permission.WRITE_SETTINGS);
65 
66     @Rule
67     public final MockitoRule mMockitoRule = MockitoJUnit.rule();
68 
69     private static final long CALLBACK_TIMEOUT_MILLIS = 5_000;
70     private static final VibrationAttributes VIBRATION_ATTRIBUTES =
71             new VibrationAttributes.Builder()
72                     .setUsage(VibrationAttributes.USAGE_TOUCH)
73                     .build();
74 
75     /**
76      * These listeners are used for test helper methods like asserting it starts/stops vibrating.
77      * It's not strongly required that the interactions with these mocks are validated by all tests.
78      */
79     private final SparseArray<OnVibratorStateChangedListener> mStateListeners = new SparseArray<>();
80 
81     private VibratorManager mVibratorManager;
82 
83     @Before
setUp()84     public void setUp() {
85         Context context = InstrumentationRegistry.getInstrumentation().getContext();
86         Settings.System.putInt(context.getContentResolver(), Settings.System.VIBRATE_ON, 1);
87 
88         mVibratorManager = context.getSystemService(VibratorManager.class);
89         for (int vibratorId : mVibratorManager.getVibratorIds()) {
90             OnVibratorStateChangedListener listener = mock(OnVibratorStateChangedListener.class);
91             mVibratorManager.getVibrator(vibratorId).addVibratorStateListener(listener);
92             mStateListeners.put(vibratorId, listener);
93             // Adding a listener to the Vibrator should trigger the callback once with the current
94             // vibrator state, so reset mocks to clear it for tests.
95             assertVibratorStateChangesTo(vibratorId, false);
96             clearInvocations(listener);
97         }
98     }
99 
100     @After
cleanUp()101     public void cleanUp() {
102         // Clearing invocations so we can use these listeners to wait for the vibrator to
103         // asynchronously cancel the ongoing vibration, if any was left pending by a test.
104         for (int i = 0; i < mStateListeners.size(); i++) {
105             clearInvocations(mStateListeners.valueAt(i));
106         }
107         mVibratorManager.cancel();
108 
109         for (int i = 0; i < mStateListeners.size(); i++) {
110             int vibratorId = mStateListeners.keyAt(i);
111 
112             // Wait for cancel to take effect, if device is still vibrating.
113             if (mVibratorManager.getVibrator(vibratorId).isVibrating()) {
114                 assertStopsVibrating(vibratorId);
115             }
116 
117             // Remove all listeners added by the tests.
118             mVibratorManager.getVibrator(vibratorId).removeVibratorStateListener(
119                     mStateListeners.valueAt(i));
120         }
121     }
122 
123     @Test
testGetVibratorIds()124     public void testGetVibratorIds() {
125         // Just make sure it doesn't crash or return null when this is called; we don't really have
126         // a way to test which vibrators will be returned.
127         assertThat(mVibratorManager.getVibratorIds()).isNotNull();
128         assertThat(mVibratorManager.getVibratorIds()).asList().containsNoDuplicates();
129     }
130 
131     @Test
testGetNonExistentVibratorId()132     public void testGetNonExistentVibratorId() {
133         int missingId = Arrays.stream(mVibratorManager.getVibratorIds()).max().orElse(0) + 1;
134         Vibrator vibrator = mVibratorManager.getVibrator(missingId);
135         assertThat(vibrator).isNotNull();
136         assertThat(vibrator.hasVibrator()).isFalse();
137     }
138 
139     @Test
testGetDefaultVibratorIsSameAsVibratorService()140     public void testGetDefaultVibratorIsSameAsVibratorService() {
141         // Note that VibratorTest parameterization relies on these two vibrators being identical.
142         // It only runs vibrator tests on the result of one of the APIs.
143         Vibrator systemVibrator =
144                 InstrumentationRegistry.getInstrumentation().getContext().getSystemService(
145                         Vibrator.class);
146         assertThat(mVibratorManager.getDefaultVibrator()).isSameInstanceAs(systemVibrator);
147     }
148 
149     @Test
testCancel()150     public void testCancel() {
151         mVibratorManager.vibrate(CombinedVibration.createParallel(
152                 VibrationEffect.createOneShot(10_000, VibrationEffect.DEFAULT_AMPLITUDE)));
153         assertStartsVibrating();
154 
155         mVibratorManager.cancel();
156         assertStopsVibrating();
157     }
158 
159     @LargeTest
160     @Test
testCombinedVibrationOneShotStartsAndFinishesVibration()161     public void testCombinedVibrationOneShotStartsAndFinishesVibration() {
162         VibrationEffect oneShot =
163                 VibrationEffect.createOneShot(300, VibrationEffect.DEFAULT_AMPLITUDE);
164         mVibratorManager.vibrate(CombinedVibration.createParallel(oneShot));
165         assertStartsThenStopsVibrating(300);
166     }
167 
168     @Test
testCombinedVibrationOneShotMaxAmplitude()169     public void testCombinedVibrationOneShotMaxAmplitude() {
170         VibrationEffect oneShot = VibrationEffect.createOneShot(500, 255 /* Max amplitude */);
171         mVibratorManager.vibrate(CombinedVibration.createParallel(oneShot));
172         assertStartsVibrating();
173 
174         mVibratorManager.cancel();
175         assertStopsVibrating();
176     }
177 
178     @Test
testCombinedVibrationOneShotMinAmplitude()179     public void testCombinedVibrationOneShotMinAmplitude() {
180         VibrationEffect oneShot = VibrationEffect.createOneShot(100, 1 /* Min amplitude */);
181         mVibratorManager.vibrate(CombinedVibration.createParallel(oneShot),
182                 VIBRATION_ATTRIBUTES);
183         assertStartsVibrating();
184     }
185 
186     @LargeTest
187     @Test
testCombinedVibrationWaveformStartsAndFinishesVibration()188     public void testCombinedVibrationWaveformStartsAndFinishesVibration() {
189         final long[] timings = new long[]{100, 200, 300, 400, 500};
190         final int[] amplitudes = new int[]{64, 128, 255, 128, 64};
191         VibrationEffect waveform = VibrationEffect.createWaveform(timings, amplitudes, -1);
192         mVibratorManager.vibrate(CombinedVibration.createParallel(waveform));
193         assertStartsThenStopsVibrating(1500);
194     }
195 
196     @LargeTest
197     @Test
testCombinedVibrationWaveformRepeats()198     public void testCombinedVibrationWaveformRepeats() {
199         final long[] timings = new long[]{100, 200, 300, 400, 500};
200         final int[] amplitudes = new int[]{64, 128, 255, 128, 64};
201         VibrationEffect waveform = VibrationEffect.createWaveform(timings, amplitudes, 0);
202         mVibratorManager.vibrate(CombinedVibration.createParallel(waveform));
203         assertStartsVibrating();
204 
205         SystemClock.sleep(2000);
206         int[] vibratorIds = mVibratorManager.getVibratorIds();
207         for (int vibratorId : vibratorIds) {
208             assertWithMessage(
209                     "Expected repeating parallel waveform to continue vibrating on vibrator %s"
210                             + " after initial duration", vibratorId)
211                     .that(mVibratorManager.getVibrator(vibratorId).isVibrating()).isTrue();
212         }
213 
214         mVibratorManager.cancel();
215         assertStopsVibrating();
216     }
217 
218     @Test
testCombinedVibrationTargetingSingleVibrator()219     public void testCombinedVibrationTargetingSingleVibrator() {
220         int[] vibratorIds = mVibratorManager.getVibratorIds();
221         assumeTrue(vibratorIds.length >= 2);
222 
223         VibrationEffect oneShot =
224                 VibrationEffect.createOneShot(10_000, VibrationEffect.DEFAULT_AMPLITUDE);
225 
226         // Vibrate each vibrator in turn, and assert that all the others are off.
227         for (int vibratorId : vibratorIds) {
228             Vibrator vibrator = mVibratorManager.getVibrator(vibratorId);
229             mVibratorManager.vibrate(
230                     CombinedVibration.startParallel()
231                             .addVibrator(vibratorId, oneShot)
232                             .combine());
233             assertStartsVibrating(vibratorId);
234 
235             for (int otherVibratorId : vibratorIds) {
236                 if (otherVibratorId != vibratorId) {
237                     assertWithMessage(
238                             "Expected vibrator %s not vibrating when combined vibration started"
239                                     + " on vibrator %s", otherVibratorId, vibratorId)
240                             .that(mVibratorManager.getVibrator(otherVibratorId).isVibrating())
241                             .isFalse();
242                 }
243             }
244 
245             vibrator.cancel();
246             assertStopsVibrating(vibratorId);
247         }
248     }
249 
assertStartsThenStopsVibrating(long duration)250     private void assertStartsThenStopsVibrating(long duration) {
251         for (int i = 0; i < mStateListeners.size(); i++) {
252             assertStartsVibrating(mStateListeners.keyAt(i));
253         }
254         SystemClock.sleep(duration);
255         assertStopsVibrating();
256     }
257 
assertStartsVibrating()258     private void assertStartsVibrating() {
259         assertVibratorStateChangesTo(true);
260     }
261 
assertStartsVibrating(int vibratorId)262     private void assertStartsVibrating(int vibratorId) {
263         assertVibratorStateChangesTo(vibratorId, true);
264     }
265 
assertStopsVibrating()266     private void assertStopsVibrating() {
267         assertVibratorStateChangesTo(false);
268     }
269 
assertStopsVibrating(int vibratorId)270     private void assertStopsVibrating(int vibratorId) {
271         assertVibratorStateChangesTo(vibratorId, false);
272     }
273 
assertVibratorStateChangesTo(boolean expected)274     private void assertVibratorStateChangesTo(boolean expected) {
275         for (int i = 0; i < mStateListeners.size(); i++) {
276             assertVibratorStateChangesTo(mStateListeners.keyAt(i), expected);
277         }
278     }
279 
assertVibratorStateChangesTo(int vibratorId, boolean expected)280     private void assertVibratorStateChangesTo(int vibratorId, boolean expected) {
281         OnVibratorStateChangedListener listener = mStateListeners.get(vibratorId);
282         verify(listener,
283                 timeout(CALLBACK_TIMEOUT_MILLIS).atLeastOnce().description(
284                         "Vibrator " + vibratorId + " expected to turn "
285                                 + (expected ? "on" : "off")))
286                 .onVibratorStateChanged(eq(expected));
287     }
288 }
289