Loading android/app/src/com/android/bluetooth/mapclient/MapClientService.java +7 −1 Original line number Original line Diff line number Diff line Loading @@ -295,7 +295,13 @@ public class MapClientService extends ProfileService { setMapClientService(null); setMapClientService(null); } } void cleanupDevice(BluetoothDevice device) { /** * cleanupDevice removes the associated state machine from the instance map * * @param device BluetoothDevice address of remote device */ @VisibleForTesting public void cleanupDevice(BluetoothDevice device) { if (DBG) { if (DBG) { StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder(); dump(sb); dump(sb); Loading android/app/src/com/android/bluetooth/mapclient/MceStateMachine.java +4 −0 Original line number Original line Diff line number Diff line Loading @@ -563,6 +563,10 @@ final class MceStateMachine extends StateMachine { switch (msg.what) { switch (msg.what) { case MSG_NOTIFICATION: case MSG_NOTIFICATION: EventReport ev = (EventReport) msg.obj; EventReport ev = (EventReport) msg.obj; if (ev == null) { Log.w(TAG, "MSG_NOTIFICATION event is null"); return; } if (DBG) { if (DBG) { Log.d(TAG, "Message Type = " + ev.getType() Log.d(TAG, "Message Type = " + ev.getType() + ", Message handle = " + ev.getHandle()); + ", Message handle = " + ev.getHandle()); Loading android/app/tests/unit/src/com/android/bluetooth/mapclient/MapClientStateMachineTest.java +52 −55 Original line number Original line Diff line number Diff line Loading @@ -31,10 +31,10 @@ import android.util.Log; import androidx.test.InstrumentationRegistry; import androidx.test.InstrumentationRegistry; import androidx.test.filters.MediumTest; import androidx.test.filters.MediumTest; import androidx.test.filters.Suppress; import androidx.test.runner.AndroidJUnit4; import androidx.test.runner.AndroidJUnit4; import com.android.bluetooth.R; import com.android.bluetooth.R; import com.android.bluetooth.btservice.ProfileService; import org.junit.After; import org.junit.After; import org.junit.Assert; import org.junit.Assert; Loading @@ -42,32 +42,31 @@ import org.junit.Assume; import org.junit.Before; import org.junit.Before; import org.junit.Test; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.mockito.MockitoAnnotations; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; @Suppress // TODO: enable when b/74609188 is debugged @MediumTest @MediumTest @RunWith(AndroidJUnit4.class) @RunWith(AndroidJUnit4.class) public class MapClientStateMachineTest { public class MapClientStateMachineTest { private static final String TAG = "MapStateMachineTest"; private static final String TAG = "MapStateMachineTest"; private static final Integer TIMEOUT = 3000; private static final int ASYNC_CALL_TIMEOUT_MILLIS = 100; private BluetoothAdapter mAdapter; private BluetoothAdapter mAdapter; private MceStateMachine mMceStateMachine = null; private MceStateMachine mMceStateMachine = null; private BluetoothDevice mTestDevice; private BluetoothDevice mTestDevice; private Context mTargetContext; private Context mTargetContext; private FakeMapClientService mFakeMapClientService; private CountDownLatch mConnectedLatch = null; private CountDownLatch mDisconnectedLatch = null; private Handler mHandler; private Handler mHandler; private ArgumentCaptor<Intent> mIntentArgument = ArgumentCaptor.forClass(Intent.class); @Mock @Mock private MasClient mMockMasClient; private MapClientService mMockMapClientService; @Mock private MasClient mMockMasClient; @Before @Before public void setUp() { public void setUp() { Loading @@ -76,16 +75,15 @@ public class MapClientStateMachineTest { Assume.assumeTrue("Ignore test when MapClientService is not enabled", Assume.assumeTrue("Ignore test when MapClientService is not enabled", mTargetContext.getResources().getBoolean(R.bool.profile_supported_mapmce)); mTargetContext.getResources().getBoolean(R.bool.profile_supported_mapmce)); doReturn(mTargetContext.getResources()).when(mMockMapClientService).getResources(); // This line must be called to make sure relevant objects are initialized properly // This line must be called to make sure relevant objects are initialized properly mAdapter = BluetoothAdapter.getDefaultAdapter(); mAdapter = BluetoothAdapter.getDefaultAdapter(); // Get a device for testing // Get a device for testing mTestDevice = mAdapter.getRemoteDevice("00:01:02:03:04:05"); mTestDevice = mAdapter.getRemoteDevice("00:01:02:03:04:05"); mConnectedLatch = new CountDownLatch(1); mDisconnectedLatch = new CountDownLatch(1); mFakeMapClientService = new FakeMapClientService(); when(mMockMasClient.makeRequest(any(Request.class))).thenReturn(true); when(mMockMasClient.makeRequest(any(Request.class))).thenReturn(true); mMceStateMachine = new MceStateMachine(mFakeMapClientService, mTestDevice, mMockMasClient); mMceStateMachine = new MceStateMachine(mMockMapClientService, mTestDevice, mMockMasClient); Assert.assertNotNull(mMceStateMachine); Assert.assertNotNull(mMceStateMachine); if (Looper.myLooper() == null) { if (Looper.myLooper() == null) { Looper.prepare(); Looper.prepare(); Loading Loading @@ -121,22 +119,15 @@ public class MapClientStateMachineTest { Log.i(TAG, "in testStateTransitionFromConnectingToDisconnected"); Log.i(TAG, "in testStateTransitionFromConnectingToDisconnected"); setupSdpRecordReceipt(); setupSdpRecordReceipt(); Message msg = Message.obtain(mHandler, MceStateMachine.MSG_MAS_DISCONNECTED); Message msg = Message.obtain(mHandler, MceStateMachine.MSG_MAS_DISCONNECTED); mMceStateMachine.getCurrentState().processMessage(msg); mMceStateMachine.sendMessage(msg); // Wait until the message is processed and a broadcast request is sent to // Wait until the message is processed and a broadcast request is sent to // to MapClientService to change // to MapClientService to change // state from STATE_CONNECTING to STATE_DISCONNECTED // state from STATE_CONNECTING to STATE_DISCONNECTED boolean result = false; verify(mMockMapClientService, try { timeout(ASYNC_CALL_TIMEOUT_MILLIS).times(2)).sendBroadcast( result = mDisconnectedLatch.await(TIMEOUT, TimeUnit.MILLISECONDS); mIntentArgument.capture(), eq(ProfileService.BLUETOOTH_PERM)); } catch (InterruptedException e) { Assert.assertEquals(BluetoothProfile.STATE_DISCONNECTED, mMceStateMachine.getState()); e.printStackTrace(); } // Test that the latch reached zero; i.e., that a broadcast of state-change was received. Assert.assertTrue(result); // When the state reaches STATE_DISCONNECTED, MceStateMachine object is in the process of // being dismantled; i.e., can't rely on getting its current state. That means can't // test its current state = STATE_DISCONNECTED. } } /** /** Loading @@ -148,45 +139,51 @@ public class MapClientStateMachineTest { setupSdpRecordReceipt(); setupSdpRecordReceipt(); Message msg = Message.obtain(mHandler, MceStateMachine.MSG_MAS_CONNECTED); Message msg = Message.obtain(mHandler, MceStateMachine.MSG_MAS_CONNECTED); mMceStateMachine.getCurrentState().processMessage(msg); mMceStateMachine.sendMessage(msg); // Wait until the message is processed and a broadcast request is sent to // Wait until the message is processed and a broadcast request is sent to // to MapClientService to change // to MapClientService to change // state from STATE_CONNECTING to STATE_CONNECTED // state from STATE_CONNECTING to STATE_CONNECTED boolean result = false; verify(mMockMapClientService, try { timeout(ASYNC_CALL_TIMEOUT_MILLIS).times(2)).sendBroadcast( result = mConnectedLatch.await(TIMEOUT, TimeUnit.MILLISECONDS); mIntentArgument.capture(), eq(ProfileService.BLUETOOTH_PERM)); } catch (InterruptedException e) { Assert.assertEquals(BluetoothProfile.STATE_CONNECTED, mMceStateMachine.getState()); e.printStackTrace(); } } // Test that the latch reached zero; i.e., that a broadcast of state-change was received. Assert.assertTrue(result); /** * Test receiving an empty event report */ @Test public void testReceiveEmptyEvent() { setupSdpRecordReceipt(); Message msg = Message.obtain(mHandler, MceStateMachine.MSG_MAS_CONNECTED); mMceStateMachine.sendMessage(msg); // Wait until the message is processed and a broadcast request is sent to // to MapClientService to change // state from STATE_CONNECTING to STATE_CONNECTED verify(mMockMapClientService, timeout(ASYNC_CALL_TIMEOUT_MILLIS).times(2)).sendBroadcast( mIntentArgument.capture(), eq(ProfileService.BLUETOOTH_PERM)); Assert.assertEquals(BluetoothProfile.STATE_CONNECTED, mMceStateMachine.getState()); // Send an empty notification event, verify the mMceStateMachine is still connected Message notification = Message.obtain(mHandler, MceStateMachine.MSG_NOTIFICATION); mMceStateMachine.getCurrentState().processMessage(msg); Assert.assertEquals(BluetoothProfile.STATE_CONNECTED, mMceStateMachine.getState()); Assert.assertEquals(BluetoothProfile.STATE_CONNECTED, mMceStateMachine.getState()); } } private void setupSdpRecordReceipt() { private void setupSdpRecordReceipt() { // Perform first part of MAP connection logic. verify(mMockMapClientService, timeout(ASYNC_CALL_TIMEOUT_MILLIS).times(1)).sendBroadcast( mIntentArgument.capture(), eq(ProfileService.BLUETOOTH_PERM)); Assert.assertEquals(BluetoothProfile.STATE_CONNECTING, mMceStateMachine.getState()); // Setup receipt of SDP record // Setup receipt of SDP record SdpMasRecord record = new SdpMasRecord(1, 1, 1, 1, 1, 1, "blah"); SdpMasRecord record = new SdpMasRecord(1, 1, 1, 1, 1, 1, "MasRecord"); Message msg = Message.obtain(mHandler, MceStateMachine.MSG_MAS_SDP_DONE, record); Message msg = Message.obtain(mHandler, MceStateMachine.MSG_MAS_SDP_DONE, record); mMceStateMachine.getCurrentState().processMessage(msg); mMceStateMachine.sendMessage(msg); } } private class FakeMapClientService extends MapClientService { @Override void cleanupDevice(BluetoothDevice device) {} @Override public void sendBroadcast(Intent intent, String receiverPermission) { int prevState = intent.getIntExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, -1); int state = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1); Log.i(TAG, "received broadcast: prevState = " + prevState + ", state = " + state); if (prevState == BluetoothProfile.STATE_CONNECTING && state == BluetoothProfile.STATE_CONNECTED) { mConnectedLatch.countDown(); } else if (prevState == BluetoothProfile.STATE_CONNECTING && state == BluetoothProfile.STATE_DISCONNECTED) { mDisconnectedLatch.countDown(); } } } } } Loading
android/app/src/com/android/bluetooth/mapclient/MapClientService.java +7 −1 Original line number Original line Diff line number Diff line Loading @@ -295,7 +295,13 @@ public class MapClientService extends ProfileService { setMapClientService(null); setMapClientService(null); } } void cleanupDevice(BluetoothDevice device) { /** * cleanupDevice removes the associated state machine from the instance map * * @param device BluetoothDevice address of remote device */ @VisibleForTesting public void cleanupDevice(BluetoothDevice device) { if (DBG) { if (DBG) { StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder(); dump(sb); dump(sb); Loading
android/app/src/com/android/bluetooth/mapclient/MceStateMachine.java +4 −0 Original line number Original line Diff line number Diff line Loading @@ -563,6 +563,10 @@ final class MceStateMachine extends StateMachine { switch (msg.what) { switch (msg.what) { case MSG_NOTIFICATION: case MSG_NOTIFICATION: EventReport ev = (EventReport) msg.obj; EventReport ev = (EventReport) msg.obj; if (ev == null) { Log.w(TAG, "MSG_NOTIFICATION event is null"); return; } if (DBG) { if (DBG) { Log.d(TAG, "Message Type = " + ev.getType() Log.d(TAG, "Message Type = " + ev.getType() + ", Message handle = " + ev.getHandle()); + ", Message handle = " + ev.getHandle()); Loading
android/app/tests/unit/src/com/android/bluetooth/mapclient/MapClientStateMachineTest.java +52 −55 Original line number Original line Diff line number Diff line Loading @@ -31,10 +31,10 @@ import android.util.Log; import androidx.test.InstrumentationRegistry; import androidx.test.InstrumentationRegistry; import androidx.test.filters.MediumTest; import androidx.test.filters.MediumTest; import androidx.test.filters.Suppress; import androidx.test.runner.AndroidJUnit4; import androidx.test.runner.AndroidJUnit4; import com.android.bluetooth.R; import com.android.bluetooth.R; import com.android.bluetooth.btservice.ProfileService; import org.junit.After; import org.junit.After; import org.junit.Assert; import org.junit.Assert; Loading @@ -42,32 +42,31 @@ import org.junit.Assume; import org.junit.Before; import org.junit.Before; import org.junit.Test; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.mockito.MockitoAnnotations; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; @Suppress // TODO: enable when b/74609188 is debugged @MediumTest @MediumTest @RunWith(AndroidJUnit4.class) @RunWith(AndroidJUnit4.class) public class MapClientStateMachineTest { public class MapClientStateMachineTest { private static final String TAG = "MapStateMachineTest"; private static final String TAG = "MapStateMachineTest"; private static final Integer TIMEOUT = 3000; private static final int ASYNC_CALL_TIMEOUT_MILLIS = 100; private BluetoothAdapter mAdapter; private BluetoothAdapter mAdapter; private MceStateMachine mMceStateMachine = null; private MceStateMachine mMceStateMachine = null; private BluetoothDevice mTestDevice; private BluetoothDevice mTestDevice; private Context mTargetContext; private Context mTargetContext; private FakeMapClientService mFakeMapClientService; private CountDownLatch mConnectedLatch = null; private CountDownLatch mDisconnectedLatch = null; private Handler mHandler; private Handler mHandler; private ArgumentCaptor<Intent> mIntentArgument = ArgumentCaptor.forClass(Intent.class); @Mock @Mock private MasClient mMockMasClient; private MapClientService mMockMapClientService; @Mock private MasClient mMockMasClient; @Before @Before public void setUp() { public void setUp() { Loading @@ -76,16 +75,15 @@ public class MapClientStateMachineTest { Assume.assumeTrue("Ignore test when MapClientService is not enabled", Assume.assumeTrue("Ignore test when MapClientService is not enabled", mTargetContext.getResources().getBoolean(R.bool.profile_supported_mapmce)); mTargetContext.getResources().getBoolean(R.bool.profile_supported_mapmce)); doReturn(mTargetContext.getResources()).when(mMockMapClientService).getResources(); // This line must be called to make sure relevant objects are initialized properly // This line must be called to make sure relevant objects are initialized properly mAdapter = BluetoothAdapter.getDefaultAdapter(); mAdapter = BluetoothAdapter.getDefaultAdapter(); // Get a device for testing // Get a device for testing mTestDevice = mAdapter.getRemoteDevice("00:01:02:03:04:05"); mTestDevice = mAdapter.getRemoteDevice("00:01:02:03:04:05"); mConnectedLatch = new CountDownLatch(1); mDisconnectedLatch = new CountDownLatch(1); mFakeMapClientService = new FakeMapClientService(); when(mMockMasClient.makeRequest(any(Request.class))).thenReturn(true); when(mMockMasClient.makeRequest(any(Request.class))).thenReturn(true); mMceStateMachine = new MceStateMachine(mFakeMapClientService, mTestDevice, mMockMasClient); mMceStateMachine = new MceStateMachine(mMockMapClientService, mTestDevice, mMockMasClient); Assert.assertNotNull(mMceStateMachine); Assert.assertNotNull(mMceStateMachine); if (Looper.myLooper() == null) { if (Looper.myLooper() == null) { Looper.prepare(); Looper.prepare(); Loading Loading @@ -121,22 +119,15 @@ public class MapClientStateMachineTest { Log.i(TAG, "in testStateTransitionFromConnectingToDisconnected"); Log.i(TAG, "in testStateTransitionFromConnectingToDisconnected"); setupSdpRecordReceipt(); setupSdpRecordReceipt(); Message msg = Message.obtain(mHandler, MceStateMachine.MSG_MAS_DISCONNECTED); Message msg = Message.obtain(mHandler, MceStateMachine.MSG_MAS_DISCONNECTED); mMceStateMachine.getCurrentState().processMessage(msg); mMceStateMachine.sendMessage(msg); // Wait until the message is processed and a broadcast request is sent to // Wait until the message is processed and a broadcast request is sent to // to MapClientService to change // to MapClientService to change // state from STATE_CONNECTING to STATE_DISCONNECTED // state from STATE_CONNECTING to STATE_DISCONNECTED boolean result = false; verify(mMockMapClientService, try { timeout(ASYNC_CALL_TIMEOUT_MILLIS).times(2)).sendBroadcast( result = mDisconnectedLatch.await(TIMEOUT, TimeUnit.MILLISECONDS); mIntentArgument.capture(), eq(ProfileService.BLUETOOTH_PERM)); } catch (InterruptedException e) { Assert.assertEquals(BluetoothProfile.STATE_DISCONNECTED, mMceStateMachine.getState()); e.printStackTrace(); } // Test that the latch reached zero; i.e., that a broadcast of state-change was received. Assert.assertTrue(result); // When the state reaches STATE_DISCONNECTED, MceStateMachine object is in the process of // being dismantled; i.e., can't rely on getting its current state. That means can't // test its current state = STATE_DISCONNECTED. } } /** /** Loading @@ -148,45 +139,51 @@ public class MapClientStateMachineTest { setupSdpRecordReceipt(); setupSdpRecordReceipt(); Message msg = Message.obtain(mHandler, MceStateMachine.MSG_MAS_CONNECTED); Message msg = Message.obtain(mHandler, MceStateMachine.MSG_MAS_CONNECTED); mMceStateMachine.getCurrentState().processMessage(msg); mMceStateMachine.sendMessage(msg); // Wait until the message is processed and a broadcast request is sent to // Wait until the message is processed and a broadcast request is sent to // to MapClientService to change // to MapClientService to change // state from STATE_CONNECTING to STATE_CONNECTED // state from STATE_CONNECTING to STATE_CONNECTED boolean result = false; verify(mMockMapClientService, try { timeout(ASYNC_CALL_TIMEOUT_MILLIS).times(2)).sendBroadcast( result = mConnectedLatch.await(TIMEOUT, TimeUnit.MILLISECONDS); mIntentArgument.capture(), eq(ProfileService.BLUETOOTH_PERM)); } catch (InterruptedException e) { Assert.assertEquals(BluetoothProfile.STATE_CONNECTED, mMceStateMachine.getState()); e.printStackTrace(); } } // Test that the latch reached zero; i.e., that a broadcast of state-change was received. Assert.assertTrue(result); /** * Test receiving an empty event report */ @Test public void testReceiveEmptyEvent() { setupSdpRecordReceipt(); Message msg = Message.obtain(mHandler, MceStateMachine.MSG_MAS_CONNECTED); mMceStateMachine.sendMessage(msg); // Wait until the message is processed and a broadcast request is sent to // to MapClientService to change // state from STATE_CONNECTING to STATE_CONNECTED verify(mMockMapClientService, timeout(ASYNC_CALL_TIMEOUT_MILLIS).times(2)).sendBroadcast( mIntentArgument.capture(), eq(ProfileService.BLUETOOTH_PERM)); Assert.assertEquals(BluetoothProfile.STATE_CONNECTED, mMceStateMachine.getState()); // Send an empty notification event, verify the mMceStateMachine is still connected Message notification = Message.obtain(mHandler, MceStateMachine.MSG_NOTIFICATION); mMceStateMachine.getCurrentState().processMessage(msg); Assert.assertEquals(BluetoothProfile.STATE_CONNECTED, mMceStateMachine.getState()); Assert.assertEquals(BluetoothProfile.STATE_CONNECTED, mMceStateMachine.getState()); } } private void setupSdpRecordReceipt() { private void setupSdpRecordReceipt() { // Perform first part of MAP connection logic. verify(mMockMapClientService, timeout(ASYNC_CALL_TIMEOUT_MILLIS).times(1)).sendBroadcast( mIntentArgument.capture(), eq(ProfileService.BLUETOOTH_PERM)); Assert.assertEquals(BluetoothProfile.STATE_CONNECTING, mMceStateMachine.getState()); // Setup receipt of SDP record // Setup receipt of SDP record SdpMasRecord record = new SdpMasRecord(1, 1, 1, 1, 1, 1, "blah"); SdpMasRecord record = new SdpMasRecord(1, 1, 1, 1, 1, 1, "MasRecord"); Message msg = Message.obtain(mHandler, MceStateMachine.MSG_MAS_SDP_DONE, record); Message msg = Message.obtain(mHandler, MceStateMachine.MSG_MAS_SDP_DONE, record); mMceStateMachine.getCurrentState().processMessage(msg); mMceStateMachine.sendMessage(msg); } } private class FakeMapClientService extends MapClientService { @Override void cleanupDevice(BluetoothDevice device) {} @Override public void sendBroadcast(Intent intent, String receiverPermission) { int prevState = intent.getIntExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, -1); int state = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1); Log.i(TAG, "received broadcast: prevState = " + prevState + ", state = " + state); if (prevState == BluetoothProfile.STATE_CONNECTING && state == BluetoothProfile.STATE_CONNECTED) { mConnectedLatch.countDown(); } else if (prevState == BluetoothProfile.STATE_CONNECTING && state == BluetoothProfile.STATE_DISCONNECTED) { mDisconnectedLatch.countDown(); } } } } }