• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 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.server.power;
18 
19 import static com.android.server.power.ShutdownThread.DEFAULT_SHUTDOWN_VIBRATE_MS;
20 import static org.junit.Assert.assertEquals;
21 import static org.mockito.ArgumentMatchers.any;
22 import static org.mockito.ArgumentMatchers.anyString;
23 import static org.mockito.ArgumentMatchers.eq;
24 import static org.mockito.Mockito.mock;
25 import static org.mockito.Mockito.never;
26 import static org.mockito.Mockito.verify;
27 import static org.mockito.Mockito.when;
28 
29 import android.content.Context;
30 import android.os.VibrationAttributes;
31 import android.os.VibrationEffect;
32 import android.os.Vibrator;
33 import android.os.VibratorInfo;
34 import android.util.AtomicFile;
35 
36 import androidx.test.InstrumentationRegistry;
37 
38 import org.junit.Before;
39 import org.junit.Test;
40 import org.mockito.Mock;
41 import org.mockito.MockitoAnnotations;
42 
43 import java.io.File;
44 import java.io.FileOutputStream;
45 import java.io.IOException;
46 
47 /**
48  * Tests for {@link com.android.server.power.ShutdownThread}
49  */
50 public class ShutdownThreadTest {
51 
52     private static final String WAVEFORM_VIB_10MS_SERIALIZATION =
53             """
54             <vibration-effect>
55                 <waveform-effect>
56                     <waveform-entry durationMs="10" amplitude="100"/>
57                 </waveform-effect>
58             </vibration-effect>
59             """;
60 
61     private static final VibrationEffect WAVEFORM_VIB_10MS = VibrationEffect.createOneShot(10, 100);
62 
63     private static final String REPEATING_VIB_SERIALIZATION =
64             """
65             <vibration-effect>
66                 <waveform-effect>
67                     <repeating>
68                         <waveform-entry durationMs="10" amplitude="100"/>
69                     </repeating>
70                 </waveform-effect>
71             </vibration-effect>
72             """;
73 
74     private static final String CLICK_VIB_SERIALIZATION =
75             """
76             <vibration-effect>
77                 <predefined-effect name="click"/>
78             </vibration-effect>
79             """;
80 
81     private static final VibrationEffect CLILCK_VIB =
82             VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK);
83 
84     private static final String BAD_VIB_SERIALIZATION = "BAD SERIALIZATION";
85 
86     @Mock private Context mContextMock;
87     @Mock private Vibrator mVibratorMock;
88     @Mock private VibratorInfo mVibratorInfoMock;
89 
90     private String mDefaultShutdownVibrationFilePath;
91     private long mLastSleepDurationMs;
92 
93     private ShutdownThread mShutdownThread;
94 
95     @Before
setUp()96     public void setUp() {
97         MockitoAnnotations.initMocks(this);
98         when(mVibratorMock.hasVibrator()).thenReturn(true);
99         when(mVibratorMock.getInfo()).thenReturn(mVibratorInfoMock);
100 
101         when(mVibratorInfoMock.areVibrationFeaturesSupported(any())).thenReturn(true);
102 
103         mShutdownThread = new ShutdownThread(new TestInjector());
104     }
105 
106     @Test
testSuccessfulShutdownVibrationFromFile()107     public void testSuccessfulShutdownVibrationFromFile() throws Exception {
108         setShutdownVibrationFileContent(WAVEFORM_VIB_10MS_SERIALIZATION);
109 
110         mShutdownThread.playShutdownVibration(mContextMock);
111 
112         assertShutdownVibration(WAVEFORM_VIB_10MS, /* vibrationSleepDuration= */ 10);
113     }
114 
115     @Test
testIOExceptionWhenParsingShutdownVibration()116     public void testIOExceptionWhenParsingShutdownVibration() throws Exception {
117         mDefaultShutdownVibrationFilePath = "non/existent/file_path";
118 
119         mShutdownThread.playShutdownVibration(mContextMock);
120 
121         assertDefaultShutdownVibration();
122     }
123 
124     @Test
testMalformedShutdownVibrationFileContent()125     public void testMalformedShutdownVibrationFileContent() throws Exception {
126         setShutdownVibrationFileContent(BAD_VIB_SERIALIZATION);
127 
128         mShutdownThread.playShutdownVibration(mContextMock);
129 
130         assertDefaultShutdownVibration();
131     }
132 
133     @Test
testVibratorUnsupportedShutdownVibrationEffect()134     public void testVibratorUnsupportedShutdownVibrationEffect() throws Exception {
135         setShutdownVibrationFileContent(WAVEFORM_VIB_10MS_SERIALIZATION);
136         when(mVibratorInfoMock.areVibrationFeaturesSupported(any())).thenReturn(false);
137 
138         mShutdownThread.playShutdownVibration(mContextMock);
139 
140         assertDefaultShutdownVibration();
141     }
142 
143     @Test
testRepeatinghutdownVibrationEffect()144     public void testRepeatinghutdownVibrationEffect() throws Exception {
145         setShutdownVibrationFileContent(REPEATING_VIB_SERIALIZATION);
146 
147         mShutdownThread.playShutdownVibration(mContextMock);
148 
149         assertDefaultShutdownVibration();
150     }
151 
152     @Test
testVibrationEffectWithUnknownDuration()153     public void testVibrationEffectWithUnknownDuration() throws Exception {
154         setShutdownVibrationFileContent(CLICK_VIB_SERIALIZATION);
155 
156         mShutdownThread.playShutdownVibration(mContextMock);
157 
158         assertShutdownVibration(CLILCK_VIB, DEFAULT_SHUTDOWN_VIBRATE_MS);
159     }
160 
161     @Test
testNoVibrator()162     public void testNoVibrator() {
163         when(mVibratorMock.hasVibrator()).thenReturn(false);
164 
165         mShutdownThread.playShutdownVibration(mContextMock);
166 
167         verify(mVibratorMock, never())
168                 .vibrate(any(VibrationEffect.class), any(VibrationAttributes.class));
169     }
170 
assertShutdownVibration(VibrationEffect effect, long vibrationSleepDuration)171     private void assertShutdownVibration(VibrationEffect effect, long vibrationSleepDuration)
172             throws Exception {
173         verify(mVibratorMock).vibrate(
174                 eq(effect),
175                 eq(VibrationAttributes.createForUsage(VibrationAttributes.USAGE_TOUCH)));
176         assertEquals(vibrationSleepDuration, mLastSleepDurationMs);
177     }
178 
assertDefaultShutdownVibration()179     private void assertDefaultShutdownVibration() throws Exception {
180         assertShutdownVibration(
181                 VibrationEffect.createOneShot(
182                         DEFAULT_SHUTDOWN_VIBRATE_MS, VibrationEffect.DEFAULT_AMPLITUDE),
183                 DEFAULT_SHUTDOWN_VIBRATE_MS);
184     }
185 
setShutdownVibrationFileContent(String content)186     private void setShutdownVibrationFileContent(String content) throws Exception {
187         mDefaultShutdownVibrationFilePath = createFileForContent(content).getAbsolutePath();
188     }
189 
createFileForContent(String content)190     private static File createFileForContent(String content) throws Exception {
191         File file = new File(InstrumentationRegistry.getContext().getCacheDir(), "test.xml");
192         file.createNewFile();
193 
194         AtomicFile atomicFile = new AtomicFile(file);
195         FileOutputStream fos = atomicFile.startWrite();
196         fos.write(content.getBytes());
197         atomicFile.finishWrite(fos);
198 
199         return file;
200     }
201 
202     private class TestInjector extends ShutdownThread.Injector {
203         @Override
getVibrator(Context context)204         public Vibrator getVibrator(Context context) {
205             return mVibratorMock;
206         }
207 
208         @Override
getDefaultShutdownVibrationEffectFilePath(Context context)209         public String getDefaultShutdownVibrationEffectFilePath(Context context) {
210             return mDefaultShutdownVibrationFilePath;
211         }
212 
213         @Override
sleep(long durationMs)214         public void sleep(long durationMs) {
215             mLastSleepDurationMs = durationMs;
216         }
217     }
218 }
219