Loading android/app/src/com/android/bluetooth/hfp/HeadsetService.java +45 −21 Original line number Diff line number Diff line Loading @@ -2017,31 +2017,55 @@ public class HeadsetService extends ProfileService { @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void onConnectionStateChangedFromStateMachine(BluetoothDevice device, int fromState, int toState) { synchronized (mStateMachines) { List<BluetoothDevice> audioConnectableDevices = getConnectedDevices(); if (fromState != BluetoothProfile.STATE_CONNECTED && toState == BluetoothProfile.STATE_CONNECTED) { if (audioConnectableDevices.size() > 1) { mInbandRingingRuntimeDisable = true; doForEachConnectedStateMachine( stateMachine -> stateMachine.sendMessage(HeadsetStateMachine.SEND_BSIR, 0)); } updateInbandRinging(device, true); MetricsLogger.logProfileConnectionEvent(BluetoothMetricsProto.ProfileId.HEADSET); } if (fromState != BluetoothProfile.STATE_DISCONNECTED && toState == BluetoothProfile.STATE_DISCONNECTED) { if (audioConnectableDevices.size() <= 1) { mInbandRingingRuntimeDisable = false; doForEachConnectedStateMachine( stateMachine -> stateMachine.sendMessage(HeadsetStateMachine.SEND_BSIR, 1)); } updateInbandRinging(device, false); if (device.equals(mActiveDevice)) { setActiveDevice(null); } } } /** * Called from {@link HeadsetClientStateMachine} to update inband ringing status. */ public void updateInbandRinging(BluetoothDevice device, boolean connected) { synchronized (mStateMachines) { List<BluetoothDevice> audioConnectableDevices = getConnectedDevices(); final int enabled; final boolean inbandRingingRuntimeDisable = mInbandRingingRuntimeDisable; if (audioConnectableDevices.size() > 1 || isHeadsetClientConnected()) { mInbandRingingRuntimeDisable = true; enabled = 0; } else { mInbandRingingRuntimeDisable = false; enabled = 1; } final boolean updateAll = inbandRingingRuntimeDisable != mInbandRingingRuntimeDisable; Log.i(TAG, "updateInbandRinging():" + " Device=" + device + " enabled=" + enabled + " connected=" + connected + " Update all=" + updateAll); StateMachineTask sendBsirTask = stateMachine -> stateMachine .sendMessage(HeadsetStateMachine.SEND_BSIR, enabled); if (updateAll) { doForEachConnectedStateMachine(sendBsirTask); } else if (connected) { // Same Inband ringing status, send +BSIR only to the new connected device doForStateMachine(device, sendBsirTask); } } } /** Loading android/app/src/com/android/bluetooth/hfpclient/HeadsetClientStateMachine.java +16 −6 Original line number Diff line number Diff line Loading @@ -64,6 +64,7 @@ import com.android.bluetooth.Utils; import com.android.bluetooth.btservice.AdapterService; import com.android.bluetooth.btservice.MetricsLogger; import com.android.bluetooth.btservice.ProfileService; import com.android.bluetooth.hfp.HeadsetService; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.IState; import com.android.internal.util.State; Loading Loading @@ -148,6 +149,7 @@ public class HeadsetClientStateMachine extends StateMachine { private long mClccTimer = 0; private final HeadsetClientService mService; private final HeadsetService mHeadsetService; // Set of calls that represent the accurate state of calls that exists on AG and the calls that // are currently in process of being notified to the AG from HF. Loading Loading @@ -860,12 +862,13 @@ public class HeadsetClientStateMachine extends StateMachine { return (bitfield & mask) == mask; } HeadsetClientStateMachine(HeadsetClientService context, Looper looper, NativeInterface nativeInterface) { HeadsetClientStateMachine(HeadsetClientService context, HeadsetService headsetService, Looper looper, NativeInterface nativeInterface) { super(TAG, looper); mService = context; mNativeInterface = nativeInterface; mAudioManager = mService.getAudioManager(); mHeadsetService = headsetService; mVendorProcessor = new VendorCommandResponseProcessor(mService, mNativeInterface); Loading Loading @@ -909,11 +912,12 @@ public class HeadsetClientStateMachine extends StateMachine { setInitialState(mDisconnected); } static HeadsetClientStateMachine make(HeadsetClientService context, Looper looper, NativeInterface nativeInterface) { static HeadsetClientStateMachine make(HeadsetClientService context, HeadsetService headsetService, Looper looper, NativeInterface nativeInterface) { logD("make"); HeadsetClientStateMachine hfcsm = new HeadsetClientStateMachine(context, looper, nativeInterface); HeadsetClientStateMachine hfcsm = new HeadsetClientStateMachine(context, headsetService, looper, nativeInterface); hfcsm.start(); return hfcsm; } Loading Loading @@ -1022,6 +1026,9 @@ public class HeadsetClientStateMachine extends StateMachine { Log.e(TAG, "Disconnected: Illegal state transition from " + mPrevState.getName() + " to Disconnected, mCurrentDevice=" + mCurrentDevice); } if (mHeadsetService != null && mCurrentDevice != null) { mHeadsetService.updateInbandRinging(mCurrentDevice, false); } mCurrentDevice = null; } Loading Loading @@ -1309,6 +1316,9 @@ public class HeadsetClientStateMachine extends StateMachine { if (mPrevState == mConnecting) { broadcastConnectionState(mCurrentDevice, BluetoothProfile.STATE_CONNECTED, BluetoothProfile.STATE_CONNECTING); if (mHeadsetService != null) { mHeadsetService.updateInbandRinging(mCurrentDevice, true); } MetricsLogger.logProfileConnectionEvent( BluetoothMetricsProto.ProfileId.HEADSET_CLIENT); } else if (mPrevState != mAudioOn) { Loading android/app/src/com/android/bluetooth/hfpclient/HeadsetClientStateMachineFactory.java +4 −1 Original line number Diff line number Diff line Loading @@ -18,6 +18,8 @@ package com.android.bluetooth.hfpclient; import android.os.HandlerThread; import com.android.bluetooth.hfp.HeadsetService; // Factory so that StateMachine objected can be mocked public class HeadsetClientStateMachineFactory { /** Loading @@ -26,6 +28,7 @@ public class HeadsetClientStateMachineFactory { */ public HeadsetClientStateMachine make(HeadsetClientService context, HandlerThread t, NativeInterface nativeInterface) { return HeadsetClientStateMachine.make(context, t.getLooper(), nativeInterface); return HeadsetClientStateMachine.make(context, HeadsetService.getHeadsetService(), t.getLooper(), nativeInterface); } } android/app/tests/unit/src/com/android/bluetooth/hfp/HeadsetServiceAndStateMachineTest.java +23 −8 Original line number Diff line number Diff line Loading @@ -67,6 +67,7 @@ import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.mockito.Spy; import org.mockito.InOrder; import java.lang.reflect.Method; import java.util.Collections; Loading Loading @@ -666,6 +667,7 @@ public class HeadsetServiceAndStateMachineTest { Assert.assertTrue(mHeadsetService.setActiveDevice(device)); verify(mNativeInterface).setActiveDevice(device); Assert.assertEquals(device, mHeadsetService.getActiveDevice()); verify(mNativeInterface).sendBsir(eq(device), eq(true)); // Start voice recognition startVoiceRecognitionFromHf(device); } Loading @@ -689,6 +691,7 @@ public class HeadsetServiceAndStateMachineTest { Assert.assertTrue(mHeadsetService.setActiveDevice(device)); verify(mNativeInterface).setActiveDevice(device); Assert.assertEquals(device, mHeadsetService.getActiveDevice()); verify(mNativeInterface).sendBsir(eq(device), eq(true)); // Start voice recognition startVoiceRecognitionFromHf(device); // Stop voice recognition Loading Loading @@ -723,6 +726,7 @@ public class HeadsetServiceAndStateMachineTest { Assert.assertTrue(mHeadsetService.setActiveDevice(device)); verify(mNativeInterface).setActiveDevice(device); Assert.assertEquals(device, mHeadsetService.getActiveDevice()); verify(mNativeInterface).sendBsir(eq(device), eq(true)); // Start voice recognition HeadsetStackEvent startVrEvent = new HeadsetStackEvent(HeadsetStackEvent.EVENT_TYPE_VR_STATE_CHANGED, Loading Loading @@ -755,6 +759,7 @@ public class HeadsetServiceAndStateMachineTest { Assert.assertTrue(mHeadsetService.setActiveDevice(device)); verify(mNativeInterface).setActiveDevice(device); Assert.assertEquals(device, mHeadsetService.getActiveDevice()); verify(mNativeInterface).sendBsir(eq(device), eq(true)); // Start voice recognition HeadsetStackEvent startVrEvent = new HeadsetStackEvent(HeadsetStackEvent.EVENT_TYPE_VR_STATE_CHANGED, Loading Loading @@ -787,6 +792,7 @@ public class HeadsetServiceAndStateMachineTest { Assert.assertTrue(mHeadsetService.setActiveDevice(device)); verify(mNativeInterface).setActiveDevice(device); Assert.assertEquals(device, mHeadsetService.getActiveDevice()); verify(mNativeInterface).sendBsir(eq(device), eq(true)); // Start voice recognition startVoiceRecognitionFromAg(); } Loading Loading @@ -860,6 +866,7 @@ public class HeadsetServiceAndStateMachineTest { Assert.assertTrue(mHeadsetService.setActiveDevice(device)); verify(mNativeInterface).setActiveDevice(device); Assert.assertEquals(device, mHeadsetService.getActiveDevice()); verify(mNativeInterface).sendBsir(eq(device), eq(true)); // Start voice recognition startVoiceRecognitionFromAg(); // Stop voice recognition Loading Loading @@ -908,8 +915,10 @@ public class HeadsetServiceAndStateMachineTest { connectTestDevice(deviceA); BluetoothDevice deviceB = TestUtils.getTestDevice(mAdapter, 1); connectTestDevice(deviceB); verify(mNativeInterface, timeout(ASYNC_CALL_TIMEOUT_MILLIS)).sendBsir(deviceA, false); verify(mNativeInterface, timeout(ASYNC_CALL_TIMEOUT_MILLIS)).sendBsir(deviceB, false); InOrder inOrder = inOrder(mNativeInterface); inOrder.verify(mNativeInterface).sendBsir(eq(deviceA), eq(true)); inOrder.verify(mNativeInterface).sendBsir(eq(deviceB), eq(false)); inOrder.verify(mNativeInterface).sendBsir(eq(deviceA), eq(false)); // Set active device to device B Assert.assertTrue(mHeadsetService.setActiveDevice(deviceB)); verify(mNativeInterface).setActiveDevice(deviceB); Loading Loading @@ -960,8 +969,10 @@ public class HeadsetServiceAndStateMachineTest { connectTestDevice(deviceA); BluetoothDevice deviceB = TestUtils.getTestDevice(mAdapter, 1); connectTestDevice(deviceB); verify(mNativeInterface, timeout(ASYNC_CALL_TIMEOUT_MILLIS)).sendBsir(deviceA, false); verify(mNativeInterface, timeout(ASYNC_CALL_TIMEOUT_MILLIS)).sendBsir(deviceB, false); InOrder inOrder = inOrder(mNativeInterface); inOrder.verify(mNativeInterface).sendBsir(eq(deviceA), eq(true)); inOrder.verify(mNativeInterface).sendBsir(eq(deviceB), eq(false)); inOrder.verify(mNativeInterface).sendBsir(eq(deviceA), eq(false)); // Set active device to device B Assert.assertTrue(mHeadsetService.setActiveDevice(deviceB)); verify(mNativeInterface).setActiveDevice(deviceB); Loading Loading @@ -1012,8 +1023,10 @@ public class HeadsetServiceAndStateMachineTest { connectTestDevice(deviceA); BluetoothDevice deviceB = TestUtils.getTestDevice(mAdapter, 1); connectTestDevice(deviceB); verify(mNativeInterface, timeout(ASYNC_CALL_TIMEOUT_MILLIS)).sendBsir(deviceA, false); verify(mNativeInterface, timeout(ASYNC_CALL_TIMEOUT_MILLIS)).sendBsir(deviceB, false); InOrder inOrder = inOrder(mNativeInterface); inOrder.verify(mNativeInterface).sendBsir(eq(deviceA), eq(true)); inOrder.verify(mNativeInterface).sendBsir(eq(deviceB), eq(false)); inOrder.verify(mNativeInterface).sendBsir(eq(deviceA), eq(false)); // Set active device to device B Assert.assertTrue(mHeadsetService.setActiveDevice(deviceB)); verify(mNativeInterface).setActiveDevice(deviceB); Loading Loading @@ -1051,8 +1064,10 @@ public class HeadsetServiceAndStateMachineTest { connectTestDevice(deviceA); BluetoothDevice deviceB = TestUtils.getTestDevice(mAdapter, 1); connectTestDevice(deviceB); verify(mNativeInterface, timeout(ASYNC_CALL_TIMEOUT_MILLIS)).sendBsir(deviceA, false); verify(mNativeInterface, timeout(ASYNC_CALL_TIMEOUT_MILLIS)).sendBsir(deviceB, false); InOrder inOrder = inOrder(mNativeInterface); inOrder.verify(mNativeInterface).sendBsir(eq(deviceA), eq(true)); inOrder.verify(mNativeInterface).sendBsir(eq(deviceB), eq(false)); inOrder.verify(mNativeInterface).sendBsir(eq(deviceA), eq(false)); // Set active device to device B Assert.assertTrue(mHeadsetService.setActiveDevice(deviceB)); verify(mNativeInterface).setActiveDevice(deviceB); Loading android/app/tests/unit/src/com/android/bluetooth/hfpclient/HeadsetClientStateMachineTest.java +20 −5 Original line number Diff line number Diff line Loading @@ -58,6 +58,7 @@ import com.android.bluetooth.R; import com.android.bluetooth.TestUtils; import com.android.bluetooth.Utils; import com.android.bluetooth.btservice.AdapterService; import com.android.bluetooth.hfp.HeadsetService; import com.android.bluetooth.hfp.HeadsetStackEvent; import org.hamcrest.core.AllOf; Loading Loading @@ -94,6 +95,8 @@ public class HeadsetClientStateMachineTest { @Mock private Resources mMockHfpResources; @Mock private HeadsetService mHeadsetService; @Mock private HeadsetClientService mHeadsetClientService; @Mock private AudioManager mAudioManager; Loading Loading @@ -138,7 +141,7 @@ public class HeadsetClientStateMachineTest { mHandlerThread.start(); // Manage looper execution in main test thread explicitly to guarantee timing consistency mHeadsetClientStateMachine = new TestHeadsetClientStateMachine(mHeadsetClientService, mHandlerThread.getLooper(), mNativeInterface); mHeadsetService, mHandlerThread.getLooper(), mNativeInterface); mHeadsetClientStateMachine.start(); TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper()); } Loading @@ -149,10 +152,12 @@ public class HeadsetClientStateMachineTest { return; } TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper()); TestUtils.clearAdapterService(mAdapterService); mHeadsetClientStateMachine.allowConnect = null; mHeadsetClientStateMachine.doQuit(); TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper()); mHandlerThread.quit(); TestUtils.clearAdapterService(mAdapterService); verifyNoMoreInteractions(mHeadsetService); } /** Loading Loading @@ -245,6 +250,7 @@ public class HeadsetClientStateMachineTest { // Check we are in connecting state now. Assert.assertThat(mHeadsetClientStateMachine.getCurrentState(), IsInstanceOf.instanceOf(HeadsetClientStateMachine.Connected.class)); verify(mHeadsetService).updateInbandRinging(eq(mTestDevice), eq(true)); } /** Loading Loading @@ -287,6 +293,7 @@ public class HeadsetClientStateMachineTest { // Check we are in connecting state now. Assert.assertThat(mHeadsetClientStateMachine.getCurrentState(), IsInstanceOf.instanceOf(HeadsetClientStateMachine.Disconnected.class)); verify(mHeadsetService).updateInbandRinging(eq(mTestDevice), eq(false)); } /** Loading Loading @@ -338,6 +345,8 @@ public class HeadsetClientStateMachineTest { Assert.assertEquals(BluetoothProfile.STATE_CONNECTED, intentArgument.getValue().getIntExtra(BluetoothProfile.EXTRA_STATE, -1)); verify(mHeadsetService).updateInbandRinging(eq(mTestDevice), eq(true)); StackEvent event = new StackEvent(StackEvent.EVENT_TYPE_IN_BAND_RINGTONE); event.valueInt = 0; event.device = mTestDevice; Loading Loading @@ -455,6 +464,7 @@ public class HeadsetClientStateMachineTest { intentArgument.getValue().getIntExtra(BluetoothProfile.EXTRA_STATE, -1)); Assert.assertThat(mHeadsetClientStateMachine.getCurrentState(), IsInstanceOf.instanceOf(HeadsetClientStateMachine.Connected.class)); verify(mHeadsetService).updateInbandRinging(eq(mTestDevice), eq(true)); startBroadcastIndex++; return startBroadcastIndex; Loading Loading @@ -1164,6 +1174,7 @@ public class HeadsetClientStateMachineTest { sendMessageAndVerifyTransition( mHeadsetClientStateMachine.obtainMessage(StackEvent.STACK_EVENT, event), HeadsetClientStateMachine.Disconnected.class); verify(mHeadsetService).updateInbandRinging(eq(mTestDevice), eq(false)); } @Test Loading Loading @@ -1228,6 +1239,7 @@ public class HeadsetClientStateMachineTest { TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper()); Assert.assertThat(mHeadsetClientStateMachine.getCurrentState(), IsInstanceOf.instanceOf(HeadsetClientStateMachine.Connected.class)); verify(mHeadsetService).updateInbandRinging(eq(mTestDevice), eq(true)); } @Test Loading @@ -1236,6 +1248,7 @@ public class HeadsetClientStateMachineTest { Message msg = mHeadsetClientStateMachine .obtainMessage(HeadsetClientStateMachine.CONNECTING_TIMEOUT); sendMessageAndVerifyTransition(msg, HeadsetClientStateMachine.Disconnected.class); verify(mHeadsetService).updateInbandRinging(eq(mTestDevice), eq(false)); } @Test Loading Loading @@ -1324,6 +1337,7 @@ public class HeadsetClientStateMachineTest { TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper()); Assert.assertThat(mHeadsetClientStateMachine.getCurrentState(), IsInstanceOf.instanceOf(HeadsetClientStateMachine.Disconnected.class)); verify(mHeadsetService).updateInbandRinging(eq(mTestDevice), eq(false)); } @Test Loading Loading @@ -1369,6 +1383,7 @@ public class HeadsetClientStateMachineTest { TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper()); Assert.assertThat(mHeadsetClientStateMachine.getCurrentState(), IsInstanceOf.instanceOf(HeadsetClientStateMachine.Connected.class)); verify(mHeadsetService).updateInbandRinging(eq(mTestDevice), eq(true)); } private void initToAudioOnState() { Loading Loading @@ -1399,9 +1414,9 @@ public class HeadsetClientStateMachineTest { Boolean allowConnect = null; TestHeadsetClientStateMachine(HeadsetClientService context, Looper looper, NativeInterface nativeInterface) { super(context, looper, nativeInterface); TestHeadsetClientStateMachine(HeadsetClientService context, HeadsetService headsetService, Looper looper, NativeInterface nativeInterface) { super(context, headsetService, looper, nativeInterface); } public boolean doesSuperHaveDeferredMessages(int what) { Loading Loading
android/app/src/com/android/bluetooth/hfp/HeadsetService.java +45 −21 Original line number Diff line number Diff line Loading @@ -2017,31 +2017,55 @@ public class HeadsetService extends ProfileService { @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void onConnectionStateChangedFromStateMachine(BluetoothDevice device, int fromState, int toState) { synchronized (mStateMachines) { List<BluetoothDevice> audioConnectableDevices = getConnectedDevices(); if (fromState != BluetoothProfile.STATE_CONNECTED && toState == BluetoothProfile.STATE_CONNECTED) { if (audioConnectableDevices.size() > 1) { mInbandRingingRuntimeDisable = true; doForEachConnectedStateMachine( stateMachine -> stateMachine.sendMessage(HeadsetStateMachine.SEND_BSIR, 0)); } updateInbandRinging(device, true); MetricsLogger.logProfileConnectionEvent(BluetoothMetricsProto.ProfileId.HEADSET); } if (fromState != BluetoothProfile.STATE_DISCONNECTED && toState == BluetoothProfile.STATE_DISCONNECTED) { if (audioConnectableDevices.size() <= 1) { mInbandRingingRuntimeDisable = false; doForEachConnectedStateMachine( stateMachine -> stateMachine.sendMessage(HeadsetStateMachine.SEND_BSIR, 1)); } updateInbandRinging(device, false); if (device.equals(mActiveDevice)) { setActiveDevice(null); } } } /** * Called from {@link HeadsetClientStateMachine} to update inband ringing status. */ public void updateInbandRinging(BluetoothDevice device, boolean connected) { synchronized (mStateMachines) { List<BluetoothDevice> audioConnectableDevices = getConnectedDevices(); final int enabled; final boolean inbandRingingRuntimeDisable = mInbandRingingRuntimeDisable; if (audioConnectableDevices.size() > 1 || isHeadsetClientConnected()) { mInbandRingingRuntimeDisable = true; enabled = 0; } else { mInbandRingingRuntimeDisable = false; enabled = 1; } final boolean updateAll = inbandRingingRuntimeDisable != mInbandRingingRuntimeDisable; Log.i(TAG, "updateInbandRinging():" + " Device=" + device + " enabled=" + enabled + " connected=" + connected + " Update all=" + updateAll); StateMachineTask sendBsirTask = stateMachine -> stateMachine .sendMessage(HeadsetStateMachine.SEND_BSIR, enabled); if (updateAll) { doForEachConnectedStateMachine(sendBsirTask); } else if (connected) { // Same Inband ringing status, send +BSIR only to the new connected device doForStateMachine(device, sendBsirTask); } } } /** Loading
android/app/src/com/android/bluetooth/hfpclient/HeadsetClientStateMachine.java +16 −6 Original line number Diff line number Diff line Loading @@ -64,6 +64,7 @@ import com.android.bluetooth.Utils; import com.android.bluetooth.btservice.AdapterService; import com.android.bluetooth.btservice.MetricsLogger; import com.android.bluetooth.btservice.ProfileService; import com.android.bluetooth.hfp.HeadsetService; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.IState; import com.android.internal.util.State; Loading Loading @@ -148,6 +149,7 @@ public class HeadsetClientStateMachine extends StateMachine { private long mClccTimer = 0; private final HeadsetClientService mService; private final HeadsetService mHeadsetService; // Set of calls that represent the accurate state of calls that exists on AG and the calls that // are currently in process of being notified to the AG from HF. Loading Loading @@ -860,12 +862,13 @@ public class HeadsetClientStateMachine extends StateMachine { return (bitfield & mask) == mask; } HeadsetClientStateMachine(HeadsetClientService context, Looper looper, NativeInterface nativeInterface) { HeadsetClientStateMachine(HeadsetClientService context, HeadsetService headsetService, Looper looper, NativeInterface nativeInterface) { super(TAG, looper); mService = context; mNativeInterface = nativeInterface; mAudioManager = mService.getAudioManager(); mHeadsetService = headsetService; mVendorProcessor = new VendorCommandResponseProcessor(mService, mNativeInterface); Loading Loading @@ -909,11 +912,12 @@ public class HeadsetClientStateMachine extends StateMachine { setInitialState(mDisconnected); } static HeadsetClientStateMachine make(HeadsetClientService context, Looper looper, NativeInterface nativeInterface) { static HeadsetClientStateMachine make(HeadsetClientService context, HeadsetService headsetService, Looper looper, NativeInterface nativeInterface) { logD("make"); HeadsetClientStateMachine hfcsm = new HeadsetClientStateMachine(context, looper, nativeInterface); HeadsetClientStateMachine hfcsm = new HeadsetClientStateMachine(context, headsetService, looper, nativeInterface); hfcsm.start(); return hfcsm; } Loading Loading @@ -1022,6 +1026,9 @@ public class HeadsetClientStateMachine extends StateMachine { Log.e(TAG, "Disconnected: Illegal state transition from " + mPrevState.getName() + " to Disconnected, mCurrentDevice=" + mCurrentDevice); } if (mHeadsetService != null && mCurrentDevice != null) { mHeadsetService.updateInbandRinging(mCurrentDevice, false); } mCurrentDevice = null; } Loading Loading @@ -1309,6 +1316,9 @@ public class HeadsetClientStateMachine extends StateMachine { if (mPrevState == mConnecting) { broadcastConnectionState(mCurrentDevice, BluetoothProfile.STATE_CONNECTED, BluetoothProfile.STATE_CONNECTING); if (mHeadsetService != null) { mHeadsetService.updateInbandRinging(mCurrentDevice, true); } MetricsLogger.logProfileConnectionEvent( BluetoothMetricsProto.ProfileId.HEADSET_CLIENT); } else if (mPrevState != mAudioOn) { Loading
android/app/src/com/android/bluetooth/hfpclient/HeadsetClientStateMachineFactory.java +4 −1 Original line number Diff line number Diff line Loading @@ -18,6 +18,8 @@ package com.android.bluetooth.hfpclient; import android.os.HandlerThread; import com.android.bluetooth.hfp.HeadsetService; // Factory so that StateMachine objected can be mocked public class HeadsetClientStateMachineFactory { /** Loading @@ -26,6 +28,7 @@ public class HeadsetClientStateMachineFactory { */ public HeadsetClientStateMachine make(HeadsetClientService context, HandlerThread t, NativeInterface nativeInterface) { return HeadsetClientStateMachine.make(context, t.getLooper(), nativeInterface); return HeadsetClientStateMachine.make(context, HeadsetService.getHeadsetService(), t.getLooper(), nativeInterface); } }
android/app/tests/unit/src/com/android/bluetooth/hfp/HeadsetServiceAndStateMachineTest.java +23 −8 Original line number Diff line number Diff line Loading @@ -67,6 +67,7 @@ import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.mockito.Spy; import org.mockito.InOrder; import java.lang.reflect.Method; import java.util.Collections; Loading Loading @@ -666,6 +667,7 @@ public class HeadsetServiceAndStateMachineTest { Assert.assertTrue(mHeadsetService.setActiveDevice(device)); verify(mNativeInterface).setActiveDevice(device); Assert.assertEquals(device, mHeadsetService.getActiveDevice()); verify(mNativeInterface).sendBsir(eq(device), eq(true)); // Start voice recognition startVoiceRecognitionFromHf(device); } Loading @@ -689,6 +691,7 @@ public class HeadsetServiceAndStateMachineTest { Assert.assertTrue(mHeadsetService.setActiveDevice(device)); verify(mNativeInterface).setActiveDevice(device); Assert.assertEquals(device, mHeadsetService.getActiveDevice()); verify(mNativeInterface).sendBsir(eq(device), eq(true)); // Start voice recognition startVoiceRecognitionFromHf(device); // Stop voice recognition Loading Loading @@ -723,6 +726,7 @@ public class HeadsetServiceAndStateMachineTest { Assert.assertTrue(mHeadsetService.setActiveDevice(device)); verify(mNativeInterface).setActiveDevice(device); Assert.assertEquals(device, mHeadsetService.getActiveDevice()); verify(mNativeInterface).sendBsir(eq(device), eq(true)); // Start voice recognition HeadsetStackEvent startVrEvent = new HeadsetStackEvent(HeadsetStackEvent.EVENT_TYPE_VR_STATE_CHANGED, Loading Loading @@ -755,6 +759,7 @@ public class HeadsetServiceAndStateMachineTest { Assert.assertTrue(mHeadsetService.setActiveDevice(device)); verify(mNativeInterface).setActiveDevice(device); Assert.assertEquals(device, mHeadsetService.getActiveDevice()); verify(mNativeInterface).sendBsir(eq(device), eq(true)); // Start voice recognition HeadsetStackEvent startVrEvent = new HeadsetStackEvent(HeadsetStackEvent.EVENT_TYPE_VR_STATE_CHANGED, Loading Loading @@ -787,6 +792,7 @@ public class HeadsetServiceAndStateMachineTest { Assert.assertTrue(mHeadsetService.setActiveDevice(device)); verify(mNativeInterface).setActiveDevice(device); Assert.assertEquals(device, mHeadsetService.getActiveDevice()); verify(mNativeInterface).sendBsir(eq(device), eq(true)); // Start voice recognition startVoiceRecognitionFromAg(); } Loading Loading @@ -860,6 +866,7 @@ public class HeadsetServiceAndStateMachineTest { Assert.assertTrue(mHeadsetService.setActiveDevice(device)); verify(mNativeInterface).setActiveDevice(device); Assert.assertEquals(device, mHeadsetService.getActiveDevice()); verify(mNativeInterface).sendBsir(eq(device), eq(true)); // Start voice recognition startVoiceRecognitionFromAg(); // Stop voice recognition Loading Loading @@ -908,8 +915,10 @@ public class HeadsetServiceAndStateMachineTest { connectTestDevice(deviceA); BluetoothDevice deviceB = TestUtils.getTestDevice(mAdapter, 1); connectTestDevice(deviceB); verify(mNativeInterface, timeout(ASYNC_CALL_TIMEOUT_MILLIS)).sendBsir(deviceA, false); verify(mNativeInterface, timeout(ASYNC_CALL_TIMEOUT_MILLIS)).sendBsir(deviceB, false); InOrder inOrder = inOrder(mNativeInterface); inOrder.verify(mNativeInterface).sendBsir(eq(deviceA), eq(true)); inOrder.verify(mNativeInterface).sendBsir(eq(deviceB), eq(false)); inOrder.verify(mNativeInterface).sendBsir(eq(deviceA), eq(false)); // Set active device to device B Assert.assertTrue(mHeadsetService.setActiveDevice(deviceB)); verify(mNativeInterface).setActiveDevice(deviceB); Loading Loading @@ -960,8 +969,10 @@ public class HeadsetServiceAndStateMachineTest { connectTestDevice(deviceA); BluetoothDevice deviceB = TestUtils.getTestDevice(mAdapter, 1); connectTestDevice(deviceB); verify(mNativeInterface, timeout(ASYNC_CALL_TIMEOUT_MILLIS)).sendBsir(deviceA, false); verify(mNativeInterface, timeout(ASYNC_CALL_TIMEOUT_MILLIS)).sendBsir(deviceB, false); InOrder inOrder = inOrder(mNativeInterface); inOrder.verify(mNativeInterface).sendBsir(eq(deviceA), eq(true)); inOrder.verify(mNativeInterface).sendBsir(eq(deviceB), eq(false)); inOrder.verify(mNativeInterface).sendBsir(eq(deviceA), eq(false)); // Set active device to device B Assert.assertTrue(mHeadsetService.setActiveDevice(deviceB)); verify(mNativeInterface).setActiveDevice(deviceB); Loading Loading @@ -1012,8 +1023,10 @@ public class HeadsetServiceAndStateMachineTest { connectTestDevice(deviceA); BluetoothDevice deviceB = TestUtils.getTestDevice(mAdapter, 1); connectTestDevice(deviceB); verify(mNativeInterface, timeout(ASYNC_CALL_TIMEOUT_MILLIS)).sendBsir(deviceA, false); verify(mNativeInterface, timeout(ASYNC_CALL_TIMEOUT_MILLIS)).sendBsir(deviceB, false); InOrder inOrder = inOrder(mNativeInterface); inOrder.verify(mNativeInterface).sendBsir(eq(deviceA), eq(true)); inOrder.verify(mNativeInterface).sendBsir(eq(deviceB), eq(false)); inOrder.verify(mNativeInterface).sendBsir(eq(deviceA), eq(false)); // Set active device to device B Assert.assertTrue(mHeadsetService.setActiveDevice(deviceB)); verify(mNativeInterface).setActiveDevice(deviceB); Loading Loading @@ -1051,8 +1064,10 @@ public class HeadsetServiceAndStateMachineTest { connectTestDevice(deviceA); BluetoothDevice deviceB = TestUtils.getTestDevice(mAdapter, 1); connectTestDevice(deviceB); verify(mNativeInterface, timeout(ASYNC_CALL_TIMEOUT_MILLIS)).sendBsir(deviceA, false); verify(mNativeInterface, timeout(ASYNC_CALL_TIMEOUT_MILLIS)).sendBsir(deviceB, false); InOrder inOrder = inOrder(mNativeInterface); inOrder.verify(mNativeInterface).sendBsir(eq(deviceA), eq(true)); inOrder.verify(mNativeInterface).sendBsir(eq(deviceB), eq(false)); inOrder.verify(mNativeInterface).sendBsir(eq(deviceA), eq(false)); // Set active device to device B Assert.assertTrue(mHeadsetService.setActiveDevice(deviceB)); verify(mNativeInterface).setActiveDevice(deviceB); Loading
android/app/tests/unit/src/com/android/bluetooth/hfpclient/HeadsetClientStateMachineTest.java +20 −5 Original line number Diff line number Diff line Loading @@ -58,6 +58,7 @@ import com.android.bluetooth.R; import com.android.bluetooth.TestUtils; import com.android.bluetooth.Utils; import com.android.bluetooth.btservice.AdapterService; import com.android.bluetooth.hfp.HeadsetService; import com.android.bluetooth.hfp.HeadsetStackEvent; import org.hamcrest.core.AllOf; Loading Loading @@ -94,6 +95,8 @@ public class HeadsetClientStateMachineTest { @Mock private Resources mMockHfpResources; @Mock private HeadsetService mHeadsetService; @Mock private HeadsetClientService mHeadsetClientService; @Mock private AudioManager mAudioManager; Loading Loading @@ -138,7 +141,7 @@ public class HeadsetClientStateMachineTest { mHandlerThread.start(); // Manage looper execution in main test thread explicitly to guarantee timing consistency mHeadsetClientStateMachine = new TestHeadsetClientStateMachine(mHeadsetClientService, mHandlerThread.getLooper(), mNativeInterface); mHeadsetService, mHandlerThread.getLooper(), mNativeInterface); mHeadsetClientStateMachine.start(); TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper()); } Loading @@ -149,10 +152,12 @@ public class HeadsetClientStateMachineTest { return; } TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper()); TestUtils.clearAdapterService(mAdapterService); mHeadsetClientStateMachine.allowConnect = null; mHeadsetClientStateMachine.doQuit(); TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper()); mHandlerThread.quit(); TestUtils.clearAdapterService(mAdapterService); verifyNoMoreInteractions(mHeadsetService); } /** Loading Loading @@ -245,6 +250,7 @@ public class HeadsetClientStateMachineTest { // Check we are in connecting state now. Assert.assertThat(mHeadsetClientStateMachine.getCurrentState(), IsInstanceOf.instanceOf(HeadsetClientStateMachine.Connected.class)); verify(mHeadsetService).updateInbandRinging(eq(mTestDevice), eq(true)); } /** Loading Loading @@ -287,6 +293,7 @@ public class HeadsetClientStateMachineTest { // Check we are in connecting state now. Assert.assertThat(mHeadsetClientStateMachine.getCurrentState(), IsInstanceOf.instanceOf(HeadsetClientStateMachine.Disconnected.class)); verify(mHeadsetService).updateInbandRinging(eq(mTestDevice), eq(false)); } /** Loading Loading @@ -338,6 +345,8 @@ public class HeadsetClientStateMachineTest { Assert.assertEquals(BluetoothProfile.STATE_CONNECTED, intentArgument.getValue().getIntExtra(BluetoothProfile.EXTRA_STATE, -1)); verify(mHeadsetService).updateInbandRinging(eq(mTestDevice), eq(true)); StackEvent event = new StackEvent(StackEvent.EVENT_TYPE_IN_BAND_RINGTONE); event.valueInt = 0; event.device = mTestDevice; Loading Loading @@ -455,6 +464,7 @@ public class HeadsetClientStateMachineTest { intentArgument.getValue().getIntExtra(BluetoothProfile.EXTRA_STATE, -1)); Assert.assertThat(mHeadsetClientStateMachine.getCurrentState(), IsInstanceOf.instanceOf(HeadsetClientStateMachine.Connected.class)); verify(mHeadsetService).updateInbandRinging(eq(mTestDevice), eq(true)); startBroadcastIndex++; return startBroadcastIndex; Loading Loading @@ -1164,6 +1174,7 @@ public class HeadsetClientStateMachineTest { sendMessageAndVerifyTransition( mHeadsetClientStateMachine.obtainMessage(StackEvent.STACK_EVENT, event), HeadsetClientStateMachine.Disconnected.class); verify(mHeadsetService).updateInbandRinging(eq(mTestDevice), eq(false)); } @Test Loading Loading @@ -1228,6 +1239,7 @@ public class HeadsetClientStateMachineTest { TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper()); Assert.assertThat(mHeadsetClientStateMachine.getCurrentState(), IsInstanceOf.instanceOf(HeadsetClientStateMachine.Connected.class)); verify(mHeadsetService).updateInbandRinging(eq(mTestDevice), eq(true)); } @Test Loading @@ -1236,6 +1248,7 @@ public class HeadsetClientStateMachineTest { Message msg = mHeadsetClientStateMachine .obtainMessage(HeadsetClientStateMachine.CONNECTING_TIMEOUT); sendMessageAndVerifyTransition(msg, HeadsetClientStateMachine.Disconnected.class); verify(mHeadsetService).updateInbandRinging(eq(mTestDevice), eq(false)); } @Test Loading Loading @@ -1324,6 +1337,7 @@ public class HeadsetClientStateMachineTest { TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper()); Assert.assertThat(mHeadsetClientStateMachine.getCurrentState(), IsInstanceOf.instanceOf(HeadsetClientStateMachine.Disconnected.class)); verify(mHeadsetService).updateInbandRinging(eq(mTestDevice), eq(false)); } @Test Loading Loading @@ -1369,6 +1383,7 @@ public class HeadsetClientStateMachineTest { TestUtils.waitForLooperToFinishScheduledTask(mHandlerThread.getLooper()); Assert.assertThat(mHeadsetClientStateMachine.getCurrentState(), IsInstanceOf.instanceOf(HeadsetClientStateMachine.Connected.class)); verify(mHeadsetService).updateInbandRinging(eq(mTestDevice), eq(true)); } private void initToAudioOnState() { Loading Loading @@ -1399,9 +1414,9 @@ public class HeadsetClientStateMachineTest { Boolean allowConnect = null; TestHeadsetClientStateMachine(HeadsetClientService context, Looper looper, NativeInterface nativeInterface) { super(context, looper, nativeInterface); TestHeadsetClientStateMachine(HeadsetClientService context, HeadsetService headsetService, Looper looper, NativeInterface nativeInterface) { super(context, headsetService, looper, nativeInterface); } public boolean doesSuperHaveDeferredMessages(int what) { Loading