1/*
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 */
16package com.android.server.usb;
17
18import static org.junit.Assert.assertEquals;
19import static org.junit.Assert.assertFalse;
20import static org.junit.Assert.assertNotEquals;
21import static org.junit.Assert.assertTrue;
22import static org.mockito.Mockito.verify;
23import static org.mockito.Mockito.when;
24
25import android.app.ActivityManager;
26import android.content.ContentResolver;
27import android.content.Context;
28import android.content.Intent;
29import android.content.SharedPreferences;
30import android.hardware.usb.UsbManager;
31import android.os.Handler;
32import android.os.Looper;
33import android.os.Message;
34import android.os.UserHandle;
35import android.provider.Settings;
36import android.support.test.InstrumentationRegistry;
37import android.support.test.filters.SmallTest;
38import android.support.test.runner.AndroidJUnit4;
39
40import com.android.server.FgThread;
41
42import org.junit.Before;
43import org.junit.Test;
44import org.junit.runner.RunWith;
45import org.mockito.Mock;
46import org.mockito.MockitoAnnotations;
47
48import java.util.HashMap;
49import java.util.Locale;
50import java.util.Map;
51
52/**
53 * Tests for UsbHandler state changes.
54 */
55@RunWith(AndroidJUnit4.class)
56public class UsbHandlerTest {
57    private static final String TAG = UsbHandlerTest.class.getSimpleName();
58
59    @Mock
60    private UsbDeviceManager mUsbDeviceManager;
61    @Mock
62    private UsbDebuggingManager mUsbDebuggingManager;
63    @Mock
64    private UsbAlsaManager mUsbAlsaManager;
65    @Mock
66    private UsbSettingsManager mUsbSettingsManager;
67    @Mock
68    private SharedPreferences mSharedPreferences;
69    @Mock
70    private SharedPreferences.Editor mEditor;
71
72    private MockUsbHandler mUsbHandler;
73
74    private static final int MSG_UPDATE_STATE = 0;
75    private static final int MSG_ENABLE_ADB = 1;
76    private static final int MSG_SET_CURRENT_FUNCTIONS = 2;
77    private static final int MSG_SYSTEM_READY = 3;
78    private static final int MSG_BOOT_COMPLETED = 4;
79    private static final int MSG_USER_SWITCHED = 5;
80    private static final int MSG_UPDATE_USER_RESTRICTIONS = 6;
81    private static final int MSG_SET_SCREEN_UNLOCKED_FUNCTIONS = 12;
82    private static final int MSG_UPDATE_SCREEN_LOCK = 13;
83
84    private Map<String, String> mMockProperties;
85    private Map<String, Integer> mMockGlobalSettings;
86
87    private class MockUsbHandler extends UsbDeviceManager.UsbHandler {
88        boolean mIsUsbTransferAllowed;
89        Intent mBroadcastedIntent;
90
91        MockUsbHandler(Looper looper, Context context, UsbDeviceManager deviceManager,
92                UsbDebuggingManager debuggingManager, UsbAlsaManager alsaManager,
93                UsbSettingsManager settingsManager) {
94            super(looper, context, deviceManager, debuggingManager, alsaManager, settingsManager);
95            mUseUsbNotification = false;
96            mIsUsbTransferAllowed = true;
97            mCurrentUsbFunctionsReceived = true;
98        }
99
100        @Override
101        protected void setEnabledFunctions(long functions, boolean force) {
102            mCurrentFunctions = functions;
103        }
104
105        @Override
106        protected void setSystemProperty(String property, String value) {
107            mMockProperties.put(property, value);
108        }
109
110        @Override
111        protected void putGlobalSettings(ContentResolver resolver, String setting, int val) {
112            mMockGlobalSettings.put(setting, val);
113        }
114
115        @Override
116        protected String getSystemProperty(String property, String def) {
117            if (mMockProperties.containsKey(property)) {
118                return mMockProperties.get(property);
119            }
120            return def;
121        }
122
123        @Override
124        protected boolean isUsbTransferAllowed() {
125            return mIsUsbTransferAllowed;
126        }
127
128        @Override
129        protected SharedPreferences getPinnedSharedPrefs(Context context) {
130            return mSharedPreferences;
131        }
132
133        @Override
134        protected void sendStickyBroadcast(Intent intent) {
135            mBroadcastedIntent = intent;
136        }
137    }
138
139    @Before
140    public void before() {
141        MockitoAnnotations.initMocks(this);
142        mMockProperties = new HashMap<>();
143        mMockGlobalSettings = new HashMap<>();
144        when(mSharedPreferences.edit()).thenReturn(mEditor);
145
146        mUsbHandler = new MockUsbHandler(FgThread.get().getLooper(),
147                InstrumentationRegistry.getContext(), mUsbDeviceManager, mUsbDebuggingManager,
148                mUsbAlsaManager, mUsbSettingsManager);
149    }
150
151    @SmallTest
152    @Test
153    public void setFunctionsMtp() {
154        mUsbHandler.handleMessage(mUsbHandler.obtainMessage(MSG_SET_CURRENT_FUNCTIONS,
155                UsbManager.FUNCTION_MTP));
156        assertNotEquals(mUsbHandler.getEnabledFunctions() & UsbManager.FUNCTION_MTP, 0);
157    }
158
159    @SmallTest
160    @Test
161    public void setFunctionsPtp() {
162        mUsbHandler.handleMessage(mUsbHandler.obtainMessage(MSG_SET_CURRENT_FUNCTIONS,
163                UsbManager.FUNCTION_PTP));
164        assertNotEquals(mUsbHandler.getEnabledFunctions() & UsbManager.FUNCTION_PTP, 0);
165    }
166
167    @SmallTest
168    @Test
169    public void setFunctionsMidi() {
170        mUsbHandler.handleMessage(mUsbHandler.obtainMessage(MSG_SET_CURRENT_FUNCTIONS,
171                UsbManager.FUNCTION_MIDI));
172        assertNotEquals(mUsbHandler.getEnabledFunctions() & UsbManager.FUNCTION_MIDI, 0);
173    }
174
175    @SmallTest
176    @Test
177    public void setFunctionsRndis() {
178        mUsbHandler.handleMessage(mUsbHandler.obtainMessage(MSG_SET_CURRENT_FUNCTIONS,
179                UsbManager.FUNCTION_RNDIS));
180        assertNotEquals(mUsbHandler.getEnabledFunctions() & UsbManager.FUNCTION_RNDIS, 0);
181    }
182
183    @SmallTest
184    @Test
185    public void enableAdb() {
186        sendBootCompleteMessages(mUsbHandler);
187        Message msg = mUsbHandler.obtainMessage(MSG_ENABLE_ADB);
188        msg.arg1 = 1;
189        mUsbHandler.handleMessage(msg);
190        assertEquals(mUsbHandler.getEnabledFunctions(), UsbManager.FUNCTION_NONE);
191        assertEquals(mMockProperties.get(UsbDeviceManager.UsbHandler
192                .USB_PERSISTENT_CONFIG_PROPERTY), UsbManager.USB_FUNCTION_ADB);
193        verify(mUsbDebuggingManager).setAdbEnabled(true);
194        assertTrue(mUsbHandler.mAdbEnabled);
195
196        mUsbHandler.handleMessage(mUsbHandler.obtainMessage(MSG_UPDATE_STATE, 1, 1));
197
198        assertTrue(mUsbHandler.mBroadcastedIntent.getBooleanExtra(UsbManager.USB_CONNECTED, false));
199        assertTrue(mUsbHandler.mBroadcastedIntent
200                .getBooleanExtra(UsbManager.USB_CONFIGURED, false));
201        assertTrue(mUsbHandler.mBroadcastedIntent
202                .getBooleanExtra(UsbManager.USB_FUNCTION_ADB, false));
203    }
204
205    @SmallTest
206    @Test
207    public void disableAdb() {
208        mMockProperties.put(UsbDeviceManager.UsbHandler.USB_PERSISTENT_CONFIG_PROPERTY,
209                UsbManager.USB_FUNCTION_ADB);
210        mUsbHandler = new MockUsbHandler(FgThread.get().getLooper(),
211                InstrumentationRegistry.getContext(), mUsbDeviceManager, mUsbDebuggingManager,
212                mUsbAlsaManager, mUsbSettingsManager);
213
214        sendBootCompleteMessages(mUsbHandler);
215        mUsbHandler.handleMessage(mUsbHandler.obtainMessage(MSG_ENABLE_ADB, 0));
216        assertEquals(mUsbHandler.getEnabledFunctions(), UsbManager.FUNCTION_NONE);
217        assertFalse(mUsbHandler.mAdbEnabled);
218        assertEquals(mMockProperties.get(UsbDeviceManager.UsbHandler
219                .USB_PERSISTENT_CONFIG_PROPERTY), "");
220        verify(mUsbDebuggingManager).setAdbEnabled(false);
221    }
222
223    @SmallTest
224    @Test
225    public void bootCompletedCharging() {
226        sendBootCompleteMessages(mUsbHandler);
227        assertEquals(mUsbHandler.getEnabledFunctions(), UsbManager.FUNCTION_NONE);
228    }
229
230    @SmallTest
231    @Test
232    public void bootCompletedAdbEnabled() {
233        mMockProperties.put(UsbDeviceManager.UsbHandler.USB_PERSISTENT_CONFIG_PROPERTY, "adb");
234        mUsbHandler = new MockUsbHandler(FgThread.get().getLooper(),
235                InstrumentationRegistry.getContext(), mUsbDeviceManager, mUsbDebuggingManager,
236                mUsbAlsaManager, mUsbSettingsManager);
237
238        sendBootCompleteMessages(mUsbHandler);
239        assertEquals(mUsbHandler.getEnabledFunctions(), UsbManager.FUNCTION_NONE);
240        assertEquals(mMockGlobalSettings.get(Settings.Global.ADB_ENABLED).intValue(), 1);
241        assertTrue(mUsbHandler.mAdbEnabled);
242        verify(mUsbDebuggingManager).setAdbEnabled(true);
243    }
244
245    @SmallTest
246    @Test
247    public void userSwitchedDisablesMtp() {
248        mUsbHandler.handleMessage(mUsbHandler.obtainMessage(MSG_SET_CURRENT_FUNCTIONS,
249                UsbManager.FUNCTION_MTP));
250        assertNotEquals(mUsbHandler.getEnabledFunctions() & UsbManager.FUNCTION_MTP, 0);
251
252        Message msg = mUsbHandler.obtainMessage(MSG_USER_SWITCHED);
253        msg.arg1 = ActivityManager.getCurrentUser() + 1;
254        mUsbHandler.handleMessage(msg);
255        assertEquals(mUsbHandler.getEnabledFunctions(), UsbManager.FUNCTION_NONE);
256    }
257
258    @SmallTest
259    @Test
260    public void changedRestrictionsDisablesMtp() {
261        mUsbHandler.handleMessage(mUsbHandler.obtainMessage(MSG_SET_CURRENT_FUNCTIONS,
262                UsbManager.FUNCTION_MTP));
263        assertNotEquals(mUsbHandler.getEnabledFunctions() & UsbManager.FUNCTION_MTP, 0);
264
265        mUsbHandler.mIsUsbTransferAllowed = false;
266        mUsbHandler.handleMessage(mUsbHandler.obtainMessage(MSG_UPDATE_USER_RESTRICTIONS));
267        assertEquals(mUsbHandler.getEnabledFunctions(), UsbManager.FUNCTION_NONE);
268    }
269
270    @SmallTest
271    @Test
272    public void disconnectResetsCharging() {
273        sendBootCompleteMessages(mUsbHandler);
274
275        mUsbHandler.handleMessage(mUsbHandler.obtainMessage(MSG_SET_CURRENT_FUNCTIONS,
276                UsbManager.FUNCTION_MTP));
277        assertNotEquals(mUsbHandler.getEnabledFunctions() & UsbManager.FUNCTION_MTP, 0);
278
279        mUsbHandler.handleMessage(mUsbHandler.obtainMessage(MSG_UPDATE_STATE, 0, 0));
280
281        assertEquals(mUsbHandler.getEnabledFunctions(), UsbManager.FUNCTION_NONE);
282    }
283
284    @SmallTest
285    @Test
286    public void configuredSendsBroadcast() {
287        sendBootCompleteMessages(mUsbHandler);
288        mUsbHandler.handleMessage(mUsbHandler.obtainMessage(MSG_SET_CURRENT_FUNCTIONS,
289                UsbManager.FUNCTION_MTP));
290        assertNotEquals(mUsbHandler.getEnabledFunctions() & UsbManager.FUNCTION_MTP, 0);
291
292        mUsbHandler.handleMessage(mUsbHandler.obtainMessage(MSG_UPDATE_STATE, 1, 1));
293
294        assertNotEquals(mUsbHandler.getEnabledFunctions() & UsbManager.FUNCTION_MTP, 0);
295        assertTrue(mUsbHandler.mBroadcastedIntent.getBooleanExtra(UsbManager.USB_CONNECTED, false));
296        assertTrue(mUsbHandler.mBroadcastedIntent
297                .getBooleanExtra(UsbManager.USB_CONFIGURED, false));
298        assertTrue(mUsbHandler.mBroadcastedIntent
299                .getBooleanExtra(UsbManager.USB_FUNCTION_MTP, false));
300    }
301
302    @SmallTest
303    @Test
304    public void setScreenUnlockedFunctions() {
305        sendBootCompleteMessages(mUsbHandler);
306        mUsbHandler.handleMessage(mUsbHandler.obtainMessage(MSG_UPDATE_SCREEN_LOCK, 0));
307
308        mUsbHandler.handleMessage(mUsbHandler.obtainMessage(MSG_SET_SCREEN_UNLOCKED_FUNCTIONS,
309                UsbManager.FUNCTION_MTP));
310        assertNotEquals(mUsbHandler.getScreenUnlockedFunctions() & UsbManager.FUNCTION_MTP, 0);
311        assertNotEquals(mUsbHandler.getEnabledFunctions() & UsbManager.FUNCTION_MTP, 0);
312        verify(mEditor).putString(String.format(Locale.ENGLISH,
313                UsbDeviceManager.UNLOCKED_CONFIG_PREF, mUsbHandler.mCurrentUser),
314                UsbManager.USB_FUNCTION_MTP);
315    }
316
317    @SmallTest
318    @Test
319    public void unlockScreen() {
320        when(mSharedPreferences.getString(String.format(Locale.ENGLISH,
321                UsbDeviceManager.UNLOCKED_CONFIG_PREF, mUsbHandler.mCurrentUser), ""))
322                .thenReturn(UsbManager.USB_FUNCTION_MTP);
323        mUsbHandler = new MockUsbHandler(FgThread.get().getLooper(),
324                InstrumentationRegistry.getContext(), mUsbDeviceManager, mUsbDebuggingManager,
325                mUsbAlsaManager, mUsbSettingsManager);
326        sendBootCompleteMessages(mUsbHandler);
327        mUsbHandler.handleMessage(mUsbHandler.obtainMessage(MSG_UPDATE_SCREEN_LOCK, 1));
328        mUsbHandler.handleMessage(mUsbHandler.obtainMessage(MSG_UPDATE_SCREEN_LOCK, 0));
329
330        assertNotEquals(mUsbHandler.getScreenUnlockedFunctions() & UsbManager.FUNCTION_MTP, 0);
331        assertNotEquals(mUsbHandler.getEnabledFunctions() & UsbManager.FUNCTION_MTP, 0);
332    }
333
334    private static void sendBootCompleteMessages(Handler handler) {
335        handler.handleMessage(handler.obtainMessage(MSG_BOOT_COMPLETED));
336        handler.handleMessage(handler.obtainMessage(MSG_SYSTEM_READY));
337    }
338}