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