1bd90909c4ef180602ac088758ffdc13d37d24629Jack He/* 2bd90909c4ef180602ac088758ffdc13d37d24629Jack He * Copyright 2018 The Android Open Source Project 3bd90909c4ef180602ac088758ffdc13d37d24629Jack He * 4bd90909c4ef180602ac088758ffdc13d37d24629Jack He * Licensed under the Apache License, Version 2.0 (the "License"); 5bd90909c4ef180602ac088758ffdc13d37d24629Jack He * you may not use this file except in compliance with the License. 6bd90909c4ef180602ac088758ffdc13d37d24629Jack He * You may obtain a copy of the License at 7bd90909c4ef180602ac088758ffdc13d37d24629Jack He * 8bd90909c4ef180602ac088758ffdc13d37d24629Jack He * http://www.apache.org/licenses/LICENSE-2.0 9bd90909c4ef180602ac088758ffdc13d37d24629Jack He * 10bd90909c4ef180602ac088758ffdc13d37d24629Jack He * Unless required by applicable law or agreed to in writing, software 11bd90909c4ef180602ac088758ffdc13d37d24629Jack He * distributed under the License is distributed on an "AS IS" BASIS, 12bd90909c4ef180602ac088758ffdc13d37d24629Jack He * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13bd90909c4ef180602ac088758ffdc13d37d24629Jack He * See the License for the specific language governing permissions and 14bd90909c4ef180602ac088758ffdc13d37d24629Jack He * limitations under the License. 15bd90909c4ef180602ac088758ffdc13d37d24629Jack He */ 16bd90909c4ef180602ac088758ffdc13d37d24629Jack Hepackage com.android.bluetooth; 17bd90909c4ef180602ac088758ffdc13d37d24629Jack He 18bd90909c4ef180602ac088758ffdc13d37d24629Jack Heimport static org.mockito.ArgumentMatchers.eq; 19bd90909c4ef180602ac088758ffdc13d37d24629Jack Heimport static org.mockito.Mockito.*; 20bd90909c4ef180602ac088758ffdc13d37d24629Jack He 21bd90909c4ef180602ac088758ffdc13d37d24629Jack Heimport android.bluetooth.BluetoothAdapter; 227b52eb7550500a570937c6164018005b14ea359bPavlin Radoslavovimport android.bluetooth.BluetoothDevice; 23bd90909c4ef180602ac088758ffdc13d37d24629Jack Heimport android.content.Intent; 243162432cb2cb1238c95123b412dd326f31ba1610Pavlin Radoslavovimport android.os.Handler; 253162432cb2cb1238c95123b412dd326f31ba1610Pavlin Radoslavovimport android.os.Looper; 26bd90909c4ef180602ac088758ffdc13d37d24629Jack Heimport android.support.test.InstrumentationRegistry; 27bd90909c4ef180602ac088758ffdc13d37d24629Jack Heimport android.support.test.rule.ServiceTestRule; 28bd90909c4ef180602ac088758ffdc13d37d24629Jack He 29bd90909c4ef180602ac088758ffdc13d37d24629Jack Heimport com.android.bluetooth.btservice.AdapterService; 30bd90909c4ef180602ac088758ffdc13d37d24629Jack Heimport com.android.bluetooth.btservice.ProfileService; 31bd90909c4ef180602ac088758ffdc13d37d24629Jack He 32bd90909c4ef180602ac088758ffdc13d37d24629Jack Heimport org.junit.Assert; 3335bbcaba2cfd2285e3897b501c34469043108a08Myles Watsonimport org.mockito.ArgumentCaptor; 34bd90909c4ef180602ac088758ffdc13d37d24629Jack Heimport org.mockito.internal.util.MockUtil; 35bd90909c4ef180602ac088758ffdc13d37d24629Jack He 36448309eada01c130b2fee8977f7fd74875978cbcJack Heimport java.lang.reflect.Field; 37bd90909c4ef180602ac088758ffdc13d37d24629Jack Heimport java.lang.reflect.InvocationTargetException; 38bd90909c4ef180602ac088758ffdc13d37d24629Jack Heimport java.lang.reflect.Method; 39a639b81f96c534c2f1066354b4a574c0dda2f713Jack Heimport java.util.concurrent.BlockingQueue; 40bd90909c4ef180602ac088758ffdc13d37d24629Jack Heimport java.util.concurrent.TimeUnit; 41bd90909c4ef180602ac088758ffdc13d37d24629Jack Heimport java.util.concurrent.TimeoutException; 42bd90909c4ef180602ac088758ffdc13d37d24629Jack He 43bd90909c4ef180602ac088758ffdc13d37d24629Jack He/** 44bd90909c4ef180602ac088758ffdc13d37d24629Jack He * A set of methods useful in Bluetooth instrumentation tests 45bd90909c4ef180602ac088758ffdc13d37d24629Jack He */ 46bd90909c4ef180602ac088758ffdc13d37d24629Jack Hepublic class TestUtils { 47bd90909c4ef180602ac088758ffdc13d37d24629Jack He private static final int SERVICE_TOGGLE_TIMEOUT_MS = 1000; // 1s 48bd90909c4ef180602ac088758ffdc13d37d24629Jack He 49bd90909c4ef180602ac088758ffdc13d37d24629Jack He /** 50448309eada01c130b2fee8977f7fd74875978cbcJack He * Utility method to replace obj.fieldName with newValue where obj is of type c 51448309eada01c130b2fee8977f7fd74875978cbcJack He * 52448309eada01c130b2fee8977f7fd74875978cbcJack He * @param c type of obj 53448309eada01c130b2fee8977f7fd74875978cbcJack He * @param fieldName field name to be replaced 54448309eada01c130b2fee8977f7fd74875978cbcJack He * @param obj instance of type c whose fieldName is to be replaced, null for static fields 55448309eada01c130b2fee8977f7fd74875978cbcJack He * @param newValue object used to replace fieldName 56448309eada01c130b2fee8977f7fd74875978cbcJack He * @return the old value of fieldName that got replaced, caller is responsible for restoring 57448309eada01c130b2fee8977f7fd74875978cbcJack He * it back to obj 58448309eada01c130b2fee8977f7fd74875978cbcJack He * @throws NoSuchFieldException when fieldName is not found in type c 59448309eada01c130b2fee8977f7fd74875978cbcJack He * @throws IllegalAccessException when fieldName cannot be accessed in type c 60bd90909c4ef180602ac088758ffdc13d37d24629Jack He */ 61448309eada01c130b2fee8977f7fd74875978cbcJack He public static Object replaceField(final Class c, final String fieldName, final Object obj, 62448309eada01c130b2fee8977f7fd74875978cbcJack He final Object newValue) throws NoSuchFieldException, IllegalAccessException { 63448309eada01c130b2fee8977f7fd74875978cbcJack He Field field = c.getDeclaredField(fieldName); 64448309eada01c130b2fee8977f7fd74875978cbcJack He field.setAccessible(true); 65448309eada01c130b2fee8977f7fd74875978cbcJack He 66448309eada01c130b2fee8977f7fd74875978cbcJack He Object oldValue = field.get(obj); 67448309eada01c130b2fee8977f7fd74875978cbcJack He field.set(obj, newValue); 68448309eada01c130b2fee8977f7fd74875978cbcJack He return oldValue; 69448309eada01c130b2fee8977f7fd74875978cbcJack He } 70bd90909c4ef180602ac088758ffdc13d37d24629Jack He 71bd90909c4ef180602ac088758ffdc13d37d24629Jack He /** 72bd90909c4ef180602ac088758ffdc13d37d24629Jack He * Set the return value of {@link AdapterService#getAdapterService()} to a test specified value 73bd90909c4ef180602ac088758ffdc13d37d24629Jack He * 74bd90909c4ef180602ac088758ffdc13d37d24629Jack He * @param adapterService the designated {@link AdapterService} in test, must not be null, can 75bd90909c4ef180602ac088758ffdc13d37d24629Jack He * be mocked or spied 76bd90909c4ef180602ac088758ffdc13d37d24629Jack He * @throws NoSuchMethodException when setAdapterService method is not found 77bd90909c4ef180602ac088758ffdc13d37d24629Jack He * @throws IllegalAccessException when setAdapterService method cannot be accessed 78bd90909c4ef180602ac088758ffdc13d37d24629Jack He * @throws InvocationTargetException when setAdapterService method cannot be invoked, which 79bd90909c4ef180602ac088758ffdc13d37d24629Jack He * should never happen since setAdapterService is a static method 80bd90909c4ef180602ac088758ffdc13d37d24629Jack He */ 81bd90909c4ef180602ac088758ffdc13d37d24629Jack He public static void setAdapterService(AdapterService adapterService) 82bd90909c4ef180602ac088758ffdc13d37d24629Jack He throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { 83bd90909c4ef180602ac088758ffdc13d37d24629Jack He Assert.assertNull("AdapterService.getAdapterService() must be null before setting another" 84bd90909c4ef180602ac088758ffdc13d37d24629Jack He + " AdapterService", AdapterService.getAdapterService()); 85bd90909c4ef180602ac088758ffdc13d37d24629Jack He Assert.assertNotNull(adapterService); 86bd90909c4ef180602ac088758ffdc13d37d24629Jack He // We cannot mock AdapterService.getAdapterService() with Mockito. 87bd90909c4ef180602ac088758ffdc13d37d24629Jack He // Hence we need to use reflection to call a private method to 88bd90909c4ef180602ac088758ffdc13d37d24629Jack He // initialize properly the AdapterService.sAdapterService field. 89bd90909c4ef180602ac088758ffdc13d37d24629Jack He Method method = 90bd90909c4ef180602ac088758ffdc13d37d24629Jack He AdapterService.class.getDeclaredMethod("setAdapterService", AdapterService.class); 91bd90909c4ef180602ac088758ffdc13d37d24629Jack He method.setAccessible(true); 92bd90909c4ef180602ac088758ffdc13d37d24629Jack He method.invoke(null, adapterService); 93bd90909c4ef180602ac088758ffdc13d37d24629Jack He } 94bd90909c4ef180602ac088758ffdc13d37d24629Jack He 95bd90909c4ef180602ac088758ffdc13d37d24629Jack He /** 96bd90909c4ef180602ac088758ffdc13d37d24629Jack He * Clear the return value of {@link AdapterService#getAdapterService()} to null 97bd90909c4ef180602ac088758ffdc13d37d24629Jack He * 98bd90909c4ef180602ac088758ffdc13d37d24629Jack He * @param adapterService the {@link AdapterService} used when calling 99bd90909c4ef180602ac088758ffdc13d37d24629Jack He * {@link TestUtils#setAdapterService(AdapterService)} 100bd90909c4ef180602ac088758ffdc13d37d24629Jack He * @throws NoSuchMethodException when clearAdapterService method is not found 101bd90909c4ef180602ac088758ffdc13d37d24629Jack He * @throws IllegalAccessException when clearAdapterService method cannot be accessed 102bd90909c4ef180602ac088758ffdc13d37d24629Jack He * @throws InvocationTargetException when clearAdappterService method cannot be invoked, 103bd90909c4ef180602ac088758ffdc13d37d24629Jack He * which should never happen since clearAdapterService is a static method 104bd90909c4ef180602ac088758ffdc13d37d24629Jack He */ 105bd90909c4ef180602ac088758ffdc13d37d24629Jack He public static void clearAdapterService(AdapterService adapterService) 106bd90909c4ef180602ac088758ffdc13d37d24629Jack He throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { 107bd90909c4ef180602ac088758ffdc13d37d24629Jack He Assert.assertSame("AdapterService.getAdapterService() must return the same object as the" 108bd90909c4ef180602ac088758ffdc13d37d24629Jack He + " supplied adapterService in this method", adapterService, 109bd90909c4ef180602ac088758ffdc13d37d24629Jack He AdapterService.getAdapterService()); 110bd90909c4ef180602ac088758ffdc13d37d24629Jack He Assert.assertNotNull(adapterService); 111bd90909c4ef180602ac088758ffdc13d37d24629Jack He Method method = 112bd90909c4ef180602ac088758ffdc13d37d24629Jack He AdapterService.class.getDeclaredMethod("clearAdapterService", AdapterService.class); 113bd90909c4ef180602ac088758ffdc13d37d24629Jack He method.setAccessible(true); 114bd90909c4ef180602ac088758ffdc13d37d24629Jack He method.invoke(null, adapterService); 115bd90909c4ef180602ac088758ffdc13d37d24629Jack He } 116bd90909c4ef180602ac088758ffdc13d37d24629Jack He 117bd90909c4ef180602ac088758ffdc13d37d24629Jack He /** 118bd90909c4ef180602ac088758ffdc13d37d24629Jack He * Start a profile service using the given {@link ServiceTestRule} and verify through 119bd90909c4ef180602ac088758ffdc13d37d24629Jack He * {@link AdapterService#getAdapterService()} that the service is actually started within 120bd90909c4ef180602ac088758ffdc13d37d24629Jack He * {@link TestUtils#SERVICE_TOGGLE_TIMEOUT_MS} milliseconds. 121bd90909c4ef180602ac088758ffdc13d37d24629Jack He * {@link #setAdapterService(AdapterService)} must be called with a mocked 122bd90909c4ef180602ac088758ffdc13d37d24629Jack He * {@link AdapterService} before calling this method 123bd90909c4ef180602ac088758ffdc13d37d24629Jack He * 124bd90909c4ef180602ac088758ffdc13d37d24629Jack He * @param serviceTestRule the {@link ServiceTestRule} used to execute the service start request 125bd90909c4ef180602ac088758ffdc13d37d24629Jack He * @param profileServiceClass a class from one of {@link ProfileService}'s child classes 126bd90909c4ef180602ac088758ffdc13d37d24629Jack He * @throws TimeoutException when service failed to start within either default timeout of 127bd90909c4ef180602ac088758ffdc13d37d24629Jack He * {@link ServiceTestRule#DEFAULT_TIMEOUT} (normally 5s) or user specified time when creating 128bd90909c4ef180602ac088758ffdc13d37d24629Jack He * {@link ServiceTestRule} through {@link ServiceTestRule#withTimeout(long, TimeUnit)} method 129bd90909c4ef180602ac088758ffdc13d37d24629Jack He */ 130bd90909c4ef180602ac088758ffdc13d37d24629Jack He public static <T extends ProfileService> void startService(ServiceTestRule serviceTestRule, 131bd90909c4ef180602ac088758ffdc13d37d24629Jack He Class<T> profileServiceClass) throws TimeoutException { 132bd90909c4ef180602ac088758ffdc13d37d24629Jack He AdapterService adapterService = AdapterService.getAdapterService(); 133bd90909c4ef180602ac088758ffdc13d37d24629Jack He Assert.assertNotNull(adapterService); 134bd90909c4ef180602ac088758ffdc13d37d24629Jack He Assert.assertTrue("AdapterService.getAdapterService() must return a mocked or spied object" 135bd90909c4ef180602ac088758ffdc13d37d24629Jack He + " before calling this method", MockUtil.isMock(adapterService)); 136bd90909c4ef180602ac088758ffdc13d37d24629Jack He Intent startIntent = 137bd90909c4ef180602ac088758ffdc13d37d24629Jack He new Intent(InstrumentationRegistry.getTargetContext(), profileServiceClass); 138bd90909c4ef180602ac088758ffdc13d37d24629Jack He startIntent.putExtra(AdapterService.EXTRA_ACTION, 139bd90909c4ef180602ac088758ffdc13d37d24629Jack He AdapterService.ACTION_SERVICE_STATE_CHANGED); 140bd90909c4ef180602ac088758ffdc13d37d24629Jack He startIntent.putExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.STATE_ON); 141bd90909c4ef180602ac088758ffdc13d37d24629Jack He serviceTestRule.startService(startIntent); 14235bbcaba2cfd2285e3897b501c34469043108a08Myles Watson ArgumentCaptor<ProfileService> profile = ArgumentCaptor.forClass(profileServiceClass); 143bd90909c4ef180602ac088758ffdc13d37d24629Jack He verify(adapterService, timeout(SERVICE_TOGGLE_TIMEOUT_MS)).onProfileServiceStateChanged( 14435bbcaba2cfd2285e3897b501c34469043108a08Myles Watson profile.capture(), eq(BluetoothAdapter.STATE_ON)); 14535bbcaba2cfd2285e3897b501c34469043108a08Myles Watson Assert.assertEquals(profileServiceClass.getName(), profile.getValue().getClass().getName()); 146bd90909c4ef180602ac088758ffdc13d37d24629Jack He } 147bd90909c4ef180602ac088758ffdc13d37d24629Jack He 148bd90909c4ef180602ac088758ffdc13d37d24629Jack He /** 149bd90909c4ef180602ac088758ffdc13d37d24629Jack He * Stop a profile service using the given {@link ServiceTestRule} and verify through 150bd90909c4ef180602ac088758ffdc13d37d24629Jack He * {@link AdapterService#getAdapterService()} that the service is actually stopped within 151bd90909c4ef180602ac088758ffdc13d37d24629Jack He * {@link TestUtils#SERVICE_TOGGLE_TIMEOUT_MS} milliseconds. 152bd90909c4ef180602ac088758ffdc13d37d24629Jack He * {@link #setAdapterService(AdapterService)} must be called with a mocked 153bd90909c4ef180602ac088758ffdc13d37d24629Jack He * {@link AdapterService} before calling this method 154bd90909c4ef180602ac088758ffdc13d37d24629Jack He * 155bd90909c4ef180602ac088758ffdc13d37d24629Jack He * @param serviceTestRule the {@link ServiceTestRule} used to execute the service start request 156bd90909c4ef180602ac088758ffdc13d37d24629Jack He * @param profileServiceClass a class from one of {@link ProfileService}'s child classes 157bd90909c4ef180602ac088758ffdc13d37d24629Jack He * @throws TimeoutException when service failed to start within either default timeout of 158bd90909c4ef180602ac088758ffdc13d37d24629Jack He * {@link ServiceTestRule#DEFAULT_TIMEOUT} (normally 5s) or user specified time when creating 159bd90909c4ef180602ac088758ffdc13d37d24629Jack He * {@link ServiceTestRule} through {@link ServiceTestRule#withTimeout(long, TimeUnit)} method 160bd90909c4ef180602ac088758ffdc13d37d24629Jack He */ 161bd90909c4ef180602ac088758ffdc13d37d24629Jack He public static <T extends ProfileService> void stopService(ServiceTestRule serviceTestRule, 162bd90909c4ef180602ac088758ffdc13d37d24629Jack He Class<T> profileServiceClass) throws TimeoutException { 163bd90909c4ef180602ac088758ffdc13d37d24629Jack He AdapterService adapterService = AdapterService.getAdapterService(); 164bd90909c4ef180602ac088758ffdc13d37d24629Jack He Assert.assertNotNull(adapterService); 165bd90909c4ef180602ac088758ffdc13d37d24629Jack He Assert.assertTrue("AdapterService.getAdapterService() must return a mocked or spied object" 166bd90909c4ef180602ac088758ffdc13d37d24629Jack He + " before calling this method", MockUtil.isMock(adapterService)); 167bd90909c4ef180602ac088758ffdc13d37d24629Jack He Intent stopIntent = 168bd90909c4ef180602ac088758ffdc13d37d24629Jack He new Intent(InstrumentationRegistry.getTargetContext(), profileServiceClass); 169bd90909c4ef180602ac088758ffdc13d37d24629Jack He stopIntent.putExtra(AdapterService.EXTRA_ACTION, 170bd90909c4ef180602ac088758ffdc13d37d24629Jack He AdapterService.ACTION_SERVICE_STATE_CHANGED); 171bd90909c4ef180602ac088758ffdc13d37d24629Jack He stopIntent.putExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.STATE_OFF); 172bd90909c4ef180602ac088758ffdc13d37d24629Jack He serviceTestRule.startService(stopIntent); 17335bbcaba2cfd2285e3897b501c34469043108a08Myles Watson ArgumentCaptor<ProfileService> profile = ArgumentCaptor.forClass(profileServiceClass); 174bd90909c4ef180602ac088758ffdc13d37d24629Jack He verify(adapterService, timeout(SERVICE_TOGGLE_TIMEOUT_MS)).onProfileServiceStateChanged( 17535bbcaba2cfd2285e3897b501c34469043108a08Myles Watson profile.capture(), eq(BluetoothAdapter.STATE_OFF)); 17635bbcaba2cfd2285e3897b501c34469043108a08Myles Watson Assert.assertEquals(profileServiceClass.getName(), profile.getValue().getClass().getName()); 177bd90909c4ef180602ac088758ffdc13d37d24629Jack He } 1787b52eb7550500a570937c6164018005b14ea359bPavlin Radoslavov 1797b52eb7550500a570937c6164018005b14ea359bPavlin Radoslavov /** 1807b52eb7550500a570937c6164018005b14ea359bPavlin Radoslavov * Create a test device. 1817b52eb7550500a570937c6164018005b14ea359bPavlin Radoslavov * 1827b52eb7550500a570937c6164018005b14ea359bPavlin Radoslavov * @param bluetoothAdapter the Bluetooth adapter to use 1837b52eb7550500a570937c6164018005b14ea359bPavlin Radoslavov * @param id the test device ID. It must be an integer in the interval [0, 0xFF]. 1847b52eb7550500a570937c6164018005b14ea359bPavlin Radoslavov * @return {@link BluetoothDevice} test device for the device ID 1857b52eb7550500a570937c6164018005b14ea359bPavlin Radoslavov */ 1867b52eb7550500a570937c6164018005b14ea359bPavlin Radoslavov public static BluetoothDevice getTestDevice(BluetoothAdapter bluetoothAdapter, int id) { 1877b52eb7550500a570937c6164018005b14ea359bPavlin Radoslavov Assert.assertTrue(id <= 0xFF); 1887b52eb7550500a570937c6164018005b14ea359bPavlin Radoslavov Assert.assertNotNull(bluetoothAdapter); 1897b52eb7550500a570937c6164018005b14ea359bPavlin Radoslavov BluetoothDevice testDevice = 1907b52eb7550500a570937c6164018005b14ea359bPavlin Radoslavov bluetoothAdapter.getRemoteDevice(String.format("00:01:02:03:04:%02X", id)); 1917b52eb7550500a570937c6164018005b14ea359bPavlin Radoslavov Assert.assertNotNull(testDevice); 1927b52eb7550500a570937c6164018005b14ea359bPavlin Radoslavov return testDevice; 1937b52eb7550500a570937c6164018005b14ea359bPavlin Radoslavov } 1943162432cb2cb1238c95123b412dd326f31ba1610Pavlin Radoslavov 1953162432cb2cb1238c95123b412dd326f31ba1610Pavlin Radoslavov /** 196a639b81f96c534c2f1066354b4a574c0dda2f713Jack He * Wait and verify that an intent has been received. 197a639b81f96c534c2f1066354b4a574c0dda2f713Jack He * 198a639b81f96c534c2f1066354b4a574c0dda2f713Jack He * @param timeoutMs the time (in milliseconds) to wait for the intent 199a639b81f96c534c2f1066354b4a574c0dda2f713Jack He * @param queue the queue for the intent 200a639b81f96c534c2f1066354b4a574c0dda2f713Jack He * @return the received intent 201a639b81f96c534c2f1066354b4a574c0dda2f713Jack He */ 202a639b81f96c534c2f1066354b4a574c0dda2f713Jack He public static Intent waitForIntent(int timeoutMs, BlockingQueue<Intent> queue) { 203a639b81f96c534c2f1066354b4a574c0dda2f713Jack He try { 204a639b81f96c534c2f1066354b4a574c0dda2f713Jack He Intent intent = queue.poll(timeoutMs, TimeUnit.MILLISECONDS); 205a639b81f96c534c2f1066354b4a574c0dda2f713Jack He Assert.assertNotNull(intent); 206a639b81f96c534c2f1066354b4a574c0dda2f713Jack He return intent; 207a639b81f96c534c2f1066354b4a574c0dda2f713Jack He } catch (InterruptedException e) { 208a639b81f96c534c2f1066354b4a574c0dda2f713Jack He Assert.fail("Cannot obtain an Intent from the queue: " + e.getMessage()); 209a639b81f96c534c2f1066354b4a574c0dda2f713Jack He } 210a639b81f96c534c2f1066354b4a574c0dda2f713Jack He return null; 211a639b81f96c534c2f1066354b4a574c0dda2f713Jack He } 212a639b81f96c534c2f1066354b4a574c0dda2f713Jack He 213a639b81f96c534c2f1066354b4a574c0dda2f713Jack He /** 214a639b81f96c534c2f1066354b4a574c0dda2f713Jack He * Wait and verify that no intent has been received. 215a639b81f96c534c2f1066354b4a574c0dda2f713Jack He * 216a639b81f96c534c2f1066354b4a574c0dda2f713Jack He * @param timeoutMs the time (in milliseconds) to wait and verify no intent 217a639b81f96c534c2f1066354b4a574c0dda2f713Jack He * has been received 218a639b81f96c534c2f1066354b4a574c0dda2f713Jack He * @param queue the queue for the intent 219a639b81f96c534c2f1066354b4a574c0dda2f713Jack He * @return the received intent. Should be null under normal circumstances 220a639b81f96c534c2f1066354b4a574c0dda2f713Jack He */ 221a639b81f96c534c2f1066354b4a574c0dda2f713Jack He public static Intent waitForNoIntent(int timeoutMs, BlockingQueue<Intent> queue) { 222a639b81f96c534c2f1066354b4a574c0dda2f713Jack He try { 223a639b81f96c534c2f1066354b4a574c0dda2f713Jack He Intent intent = queue.poll(timeoutMs, TimeUnit.MILLISECONDS); 224a639b81f96c534c2f1066354b4a574c0dda2f713Jack He Assert.assertNull(intent); 225a639b81f96c534c2f1066354b4a574c0dda2f713Jack He return intent; 226a639b81f96c534c2f1066354b4a574c0dda2f713Jack He } catch (InterruptedException e) { 227a639b81f96c534c2f1066354b4a574c0dda2f713Jack He Assert.fail("Cannot obtain an Intent from the queue: " + e.getMessage()); 228a639b81f96c534c2f1066354b4a574c0dda2f713Jack He } 229a639b81f96c534c2f1066354b4a574c0dda2f713Jack He return null; 230a639b81f96c534c2f1066354b4a574c0dda2f713Jack He } 231a639b81f96c534c2f1066354b4a574c0dda2f713Jack He 232a639b81f96c534c2f1066354b4a574c0dda2f713Jack He /** 233a639b81f96c534c2f1066354b4a574c0dda2f713Jack He * Wait for looper to finish its current task and all tasks schedule before this 234a639b81f96c534c2f1066354b4a574c0dda2f713Jack He * 235a639b81f96c534c2f1066354b4a574c0dda2f713Jack He * @param looper looper of interest 236a639b81f96c534c2f1066354b4a574c0dda2f713Jack He */ 237a639b81f96c534c2f1066354b4a574c0dda2f713Jack He public static void waitForLooperToFinishScheduledTask(Looper looper) { 238a639b81f96c534c2f1066354b4a574c0dda2f713Jack He runOnLooperSync(looper, () -> { 239a639b81f96c534c2f1066354b4a574c0dda2f713Jack He // do nothing, just need to make sure looper finishes current task 240a639b81f96c534c2f1066354b4a574c0dda2f713Jack He }); 241a639b81f96c534c2f1066354b4a574c0dda2f713Jack He } 242a639b81f96c534c2f1066354b4a574c0dda2f713Jack He 243a639b81f96c534c2f1066354b4a574c0dda2f713Jack He /** 2443162432cb2cb1238c95123b412dd326f31ba1610Pavlin Radoslavov * Run synchronously a runnable action on a looper. 2453162432cb2cb1238c95123b412dd326f31ba1610Pavlin Radoslavov * The method will return after the action has been execution to completion. 2463162432cb2cb1238c95123b412dd326f31ba1610Pavlin Radoslavov * 2473162432cb2cb1238c95123b412dd326f31ba1610Pavlin Radoslavov * Example: 2483162432cb2cb1238c95123b412dd326f31ba1610Pavlin Radoslavov * <pre> 2493162432cb2cb1238c95123b412dd326f31ba1610Pavlin Radoslavov * {@code 2503162432cb2cb1238c95123b412dd326f31ba1610Pavlin Radoslavov * TestUtils.runOnMainSync(new Runnable() { 2513162432cb2cb1238c95123b412dd326f31ba1610Pavlin Radoslavov * public void run() { 2523162432cb2cb1238c95123b412dd326f31ba1610Pavlin Radoslavov * Assert.assertTrue(mA2dpService.stop()); 2533162432cb2cb1238c95123b412dd326f31ba1610Pavlin Radoslavov * } 2543162432cb2cb1238c95123b412dd326f31ba1610Pavlin Radoslavov * }); 2553162432cb2cb1238c95123b412dd326f31ba1610Pavlin Radoslavov * } 2563162432cb2cb1238c95123b412dd326f31ba1610Pavlin Radoslavov * </pre> 2573162432cb2cb1238c95123b412dd326f31ba1610Pavlin Radoslavov * 2583162432cb2cb1238c95123b412dd326f31ba1610Pavlin Radoslavov * @param looper the looper used to run the action 2593162432cb2cb1238c95123b412dd326f31ba1610Pavlin Radoslavov * @param action the action to run 2603162432cb2cb1238c95123b412dd326f31ba1610Pavlin Radoslavov */ 2613162432cb2cb1238c95123b412dd326f31ba1610Pavlin Radoslavov public static void runOnLooperSync(Looper looper, Runnable action) { 2623162432cb2cb1238c95123b412dd326f31ba1610Pavlin Radoslavov if (Looper.myLooper() == looper) { 2633162432cb2cb1238c95123b412dd326f31ba1610Pavlin Radoslavov // requested thread is the same as the current thread. call directly. 2643162432cb2cb1238c95123b412dd326f31ba1610Pavlin Radoslavov action.run(); 2653162432cb2cb1238c95123b412dd326f31ba1610Pavlin Radoslavov } else { 2663162432cb2cb1238c95123b412dd326f31ba1610Pavlin Radoslavov Handler handler = new Handler(looper); 2673162432cb2cb1238c95123b412dd326f31ba1610Pavlin Radoslavov SyncRunnable sr = new SyncRunnable(action); 2683162432cb2cb1238c95123b412dd326f31ba1610Pavlin Radoslavov handler.post(sr); 2693162432cb2cb1238c95123b412dd326f31ba1610Pavlin Radoslavov sr.waitForComplete(); 2703162432cb2cb1238c95123b412dd326f31ba1610Pavlin Radoslavov } 2713162432cb2cb1238c95123b412dd326f31ba1610Pavlin Radoslavov } 2723162432cb2cb1238c95123b412dd326f31ba1610Pavlin Radoslavov 2733162432cb2cb1238c95123b412dd326f31ba1610Pavlin Radoslavov /** 2743162432cb2cb1238c95123b412dd326f31ba1610Pavlin Radoslavov * Helper class used to run synchronously a runnable action on a looper. 2753162432cb2cb1238c95123b412dd326f31ba1610Pavlin Radoslavov */ 2763162432cb2cb1238c95123b412dd326f31ba1610Pavlin Radoslavov private static final class SyncRunnable implements Runnable { 2773162432cb2cb1238c95123b412dd326f31ba1610Pavlin Radoslavov private final Runnable mTarget; 2783162432cb2cb1238c95123b412dd326f31ba1610Pavlin Radoslavov private volatile boolean mComplete = false; 2793162432cb2cb1238c95123b412dd326f31ba1610Pavlin Radoslavov 2803162432cb2cb1238c95123b412dd326f31ba1610Pavlin Radoslavov SyncRunnable(Runnable target) { 2813162432cb2cb1238c95123b412dd326f31ba1610Pavlin Radoslavov mTarget = target; 2823162432cb2cb1238c95123b412dd326f31ba1610Pavlin Radoslavov } 2833162432cb2cb1238c95123b412dd326f31ba1610Pavlin Radoslavov 2843162432cb2cb1238c95123b412dd326f31ba1610Pavlin Radoslavov @Override 2853162432cb2cb1238c95123b412dd326f31ba1610Pavlin Radoslavov public void run() { 2863162432cb2cb1238c95123b412dd326f31ba1610Pavlin Radoslavov mTarget.run(); 2873162432cb2cb1238c95123b412dd326f31ba1610Pavlin Radoslavov synchronized (this) { 2883162432cb2cb1238c95123b412dd326f31ba1610Pavlin Radoslavov mComplete = true; 2893162432cb2cb1238c95123b412dd326f31ba1610Pavlin Radoslavov notifyAll(); 2903162432cb2cb1238c95123b412dd326f31ba1610Pavlin Radoslavov } 2913162432cb2cb1238c95123b412dd326f31ba1610Pavlin Radoslavov } 2923162432cb2cb1238c95123b412dd326f31ba1610Pavlin Radoslavov 2933162432cb2cb1238c95123b412dd326f31ba1610Pavlin Radoslavov public void waitForComplete() { 2943162432cb2cb1238c95123b412dd326f31ba1610Pavlin Radoslavov synchronized (this) { 2953162432cb2cb1238c95123b412dd326f31ba1610Pavlin Radoslavov while (!mComplete) { 2963162432cb2cb1238c95123b412dd326f31ba1610Pavlin Radoslavov try { 2973162432cb2cb1238c95123b412dd326f31ba1610Pavlin Radoslavov wait(); 2983162432cb2cb1238c95123b412dd326f31ba1610Pavlin Radoslavov } catch (InterruptedException e) { 2993162432cb2cb1238c95123b412dd326f31ba1610Pavlin Radoslavov } 3003162432cb2cb1238c95123b412dd326f31ba1610Pavlin Radoslavov } 3013162432cb2cb1238c95123b412dd326f31ba1610Pavlin Radoslavov } 3023162432cb2cb1238c95123b412dd326f31ba1610Pavlin Radoslavov } 3033162432cb2cb1238c95123b412dd326f31ba1610Pavlin Radoslavov } 304bd90909c4ef180602ac088758ffdc13d37d24629Jack He} 305