Loading src/com/android/server/telecom/CallAudioRouteStateMachine.java +1 −134 Original line number Diff line number Diff line Loading @@ -47,7 +47,6 @@ import com.android.server.telecom.bluetooth.BluetoothRouteManager; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Objects; import java.util.Set; import java.util.concurrent.Executor; Loading Loading @@ -235,9 +234,6 @@ public class CallAudioRouteStateMachine extends StateMachine { public static final String NAME = CallAudioRouteStateMachine.class.getName(); private boolean mActiveEarpieceSetAsCommunicationDevice = false; private boolean mActiveHeadsetSetAsCommunicationDevice = false; @Override protected void onPreHandleMessage(Message msg) { if (msg.obj != null && msg.obj instanceof SomeArgs) { Loading Loading @@ -375,7 +371,6 @@ public class CallAudioRouteStateMachine extends StateMachine { public void enter() { super.enter(); setSpeakerphoneOn(false); setActiveEarpieceCommunicationDevice(); CallAudioState newState = new CallAudioState(mIsMuted, ROUTE_EARPIECE, mAvailableRoutes, null, mBluetoothRouteManager.getConnectedDevices()); Loading Loading @@ -406,7 +401,6 @@ public class CallAudioRouteStateMachine extends StateMachine { case SWITCH_BLUETOOTH: case USER_SWITCH_BLUETOOTH: if ((mAvailableRoutes & ROUTE_BLUETOOTH) != 0) { clearActiveEarpieceCommunicationDevice(); if (mAudioFocusType == ACTIVE_FOCUS || mBluetoothRouteManager.isInbandRingingEnabled()) { String address = (msg.obj instanceof SomeArgs) ? Loading @@ -423,7 +417,6 @@ public class CallAudioRouteStateMachine extends StateMachine { case SWITCH_HEADSET: case USER_SWITCH_HEADSET: if ((mAvailableRoutes & ROUTE_WIRED_HEADSET) != 0) { clearActiveEarpieceCommunicationDevice(); transitionTo(mActiveHeadsetRoute); } else { Log.w(this, "Ignoring switch to headset command. Not available."); Loading @@ -433,7 +426,6 @@ public class CallAudioRouteStateMachine extends StateMachine { // fall through; we want to switch to speaker mode when docked and in a call. case SWITCH_SPEAKER: case USER_SWITCH_SPEAKER: clearActiveEarpieceCommunicationDevice(); setSpeakerphoneOn(true); // fall through case SPEAKER_ON: Loading Loading @@ -587,7 +579,6 @@ public class CallAudioRouteStateMachine extends StateMachine { public void enter() { super.enter(); setSpeakerphoneOn(false); setActiveHeadsetCommunicationDevice(); CallAudioState newState = new CallAudioState(mIsMuted, ROUTE_WIRED_HEADSET, mAvailableRoutes, null, mBluetoothRouteManager.getConnectedDevices()); setSystemAudioState(newState, true); Loading @@ -609,7 +600,6 @@ public class CallAudioRouteStateMachine extends StateMachine { case SWITCH_EARPIECE: case USER_SWITCH_EARPIECE: if ((mAvailableRoutes & ROUTE_EARPIECE) != 0) { clearActiveHeadsetCommunicationDevice(); transitionTo(mActiveEarpieceRoute); } else { Log.w(this, "Ignoring switch to earpiece command. Not available."); Loading @@ -625,7 +615,6 @@ public class CallAudioRouteStateMachine extends StateMachine { || mBluetoothRouteManager.isInbandRingingEnabled()) { String address = (msg.obj instanceof SomeArgs) ? (String) ((SomeArgs) msg.obj).arg2 : null; clearActiveHeadsetCommunicationDevice(); // Omit transition to ActiveBluetoothRoute until actual connection. setBluetoothOn(address); } else { Loading @@ -642,7 +631,6 @@ public class CallAudioRouteStateMachine extends StateMachine { return HANDLED; case SWITCH_SPEAKER: case USER_SWITCH_SPEAKER: clearActiveHeadsetCommunicationDevice(); setSpeakerphoneOn(true); // fall through case SPEAKER_ON: Loading Loading @@ -805,12 +793,6 @@ public class CallAudioRouteStateMachine extends StateMachine { public void enter() { super.enter(); setSpeakerphoneOn(false); // Try arbitrarily connecting to BT audio if we haven't already. This handles // the edge case of when the audio route is in a quiescent route while in-call and // the BT connection fails to be set. Previously, the logic was to setBluetoothOn in // ACTIVE_FOCUS but the route would still remain in a quiescent route, so instead we // should be transitioning directly into the active route. setBluetoothOn(null); CallAudioState newState = new CallAudioState(mIsMuted, ROUTE_BLUETOOTH, mAvailableRoutes, mBluetoothRouteManager.getBluetoothAudioConnectedDevice(), mBluetoothRouteManager.getConnectedDevices()); Loading Loading @@ -1083,9 +1065,7 @@ public class CallAudioRouteStateMachine extends StateMachine { return HANDLED; case SWITCH_FOCUS: if (msg.arg1 == ACTIVE_FOCUS) { // It is possible that the connection to BT will fail while in-call, in // which case, we want to transition into the active route. transitionTo(mActiveBluetoothRoute); setBluetoothOn(null); } else if (msg.arg1 == RINGING_FOCUS) { if (mBluetoothRouteManager.isInbandRingingEnabled()) { setBluetoothOn(null); Loading Loading @@ -1809,119 +1789,6 @@ public class CallAudioRouteStateMachine extends StateMachine { } } private void setActiveHeadsetCommunicationDevice() { Log.i(this, "setActiveHeadsetCommunicationDevice"); if (mActiveHeadsetSetAsCommunicationDevice) { Log.i(this, "mActiveHeadsetSetAsCommunicationDevice already set"); return; } AudioDeviceInfo activeHeadset = null; List<AudioDeviceInfo> devices = mAudioManager.getAvailableCommunicationDevices(); if (devices.size() == 0) { Log.w(this, "No communication devices available."); return; } for (AudioDeviceInfo device : devices) { Log.i(this, "Available device type: " + device.getType()); if (device.getType() == AudioDeviceInfo.TYPE_WIRED_HEADSET || device.getType() == AudioDeviceInfo.TYPE_USB_HEADSET) { activeHeadset = device; break; } } if (activeHeadset == null) { Log.w(this, "No activeHeadset device available"); return; } // Turn TYPE_WIRED_HEADSET ON. boolean result = mAudioManager.setCommunicationDevice(activeHeadset); if (!result) { Log.w(this, "Could not set activeHeadset device"); } else { Log.i(this, "activeHeadset device set"); mActiveHeadsetSetAsCommunicationDevice = true; } } private void setActiveEarpieceCommunicationDevice() { Log.i(this, "setActiveEarpieceCommunicationDevice"); if (mActiveEarpieceSetAsCommunicationDevice) { Log.i(this, "mActiveEarpieceSetAsCommunicationDevice already set"); return; } AudioDeviceInfo activeEarpiece = null; List<AudioDeviceInfo> devices = mAudioManager.getAvailableCommunicationDevices(); if (devices.size() == 0) { Log.w(this, "No communication devices available."); return; } for (AudioDeviceInfo device : devices) { Log.i(this, "Available device type: " + device.getType()); if (device.getType() == AudioDeviceInfo.TYPE_BUILTIN_EARPIECE) { activeEarpiece = device; break; } } if (activeEarpiece == null) { Log.w(this, "No active earpiece device available"); return; } // Turn TYPE_BUILTIN_EARPIECE ON. boolean result = mAudioManager.setCommunicationDevice(activeEarpiece); if (!result) { Log.w(this, "Could not set active earpiece device"); } else { Log.i(this, "Active earpiece device set"); mActiveEarpieceSetAsCommunicationDevice = true; } } public void clearActiveEarpieceCommunicationDevice() { Log.i(this, "clearActiveEarpieceCommunicationDevice:" + "mActiveEarpieceSetAsCommunicationDevice = " + mActiveEarpieceSetAsCommunicationDevice); if (!mActiveEarpieceSetAsCommunicationDevice) { return; } mActiveEarpieceSetAsCommunicationDevice = false; AudioDeviceInfo audioDeviceInfo = mAudioManager.getCommunicationDevice(); if (audioDeviceInfo != null && audioDeviceInfo.getType() == AudioDeviceInfo.TYPE_BUILTIN_EARPIECE) { mAudioManager.clearCommunicationDevice(); } } public void clearActiveHeadsetCommunicationDevice() { Log.i(this, "clearActiveHeadsetCommunicationDevice:" + "mActiveHeadsetSetAsCommunicationDevice = " + mActiveHeadsetSetAsCommunicationDevice); if (!mActiveHeadsetSetAsCommunicationDevice) { return; } mActiveHeadsetSetAsCommunicationDevice = false; AudioDeviceInfo audioDeviceInfo = mAudioManager.getCommunicationDevice(); if (audioDeviceInfo != null && (audioDeviceInfo.getType() == AudioDeviceInfo.TYPE_WIRED_HEADSET || audioDeviceInfo.getType() == AudioDeviceInfo.TYPE_USB_HEADSET)) { mAudioManager.clearCommunicationDevice(); } } private void setMuteOn(boolean mute) { mIsMuted = mute; Log.addEvent(mCallsManager.getForegroundCall(), mute ? Loading src/com/android/server/telecom/bluetooth/BluetoothDeviceManager.java +25 −130 Original line number Diff line number Diff line Loading @@ -189,9 +189,7 @@ public class BluetoothDeviceManager { private boolean mLeAudioSetAsCommunicationDevice = false; private String mLeAudioDevice; private String mHearingAidDevice; private String mScoDevice; private boolean mHearingAidSetAsCommunicationDevice = false; private boolean mScoSetAsCommunicationDevice = false; private BluetoothDevice mBluetoothHearingAidActiveDeviceCache; private BluetoothAdapter mBluetoothAdapter; private AudioManager mAudioManager; Loading Loading @@ -400,13 +398,12 @@ public class BluetoothDeviceManager { } public void disconnectAudio() { disconnectScoAudio(); disconnectSco(); clearLeAudioCommunicationDevice(); clearHearingAidCommunicationDevice(); } public void disconnectScoAudio() { clearScoAudioCommunicationDevice(); public void disconnectSco() { if (mBluetoothHeadset == null) { Log.w(this, "Trying to disconnect audio but no headset service exists."); } else { Loading @@ -422,10 +419,6 @@ public class BluetoothDeviceManager { return mHearingAidSetAsCommunicationDevice; } public boolean isScoSetAsCommunicationDevice() { return mScoSetAsCommunicationDevice; } public void clearLeAudioCommunicationDevice() { Log.i(this, "clearLeAudioCommunicationDevice: mLeAudioSetAsCommunicationDevice = " + mLeAudioSetAsCommunicationDevice + " device = " + mLeAudioDevice); Loading Loading @@ -475,36 +468,11 @@ public class BluetoothDeviceManager { } } public void clearScoAudioCommunicationDevice() { Log.i(this, "clearScoCommunicationDevice: mScoSetAsCommunicationDevice = " + mScoSetAsCommunicationDevice); if (!mScoSetAsCommunicationDevice) { return; } mScoSetAsCommunicationDevice = false; if (mScoDevice != null) { mBluetoothRouteManager.onAudioLost(mScoDevice); mScoDevice = null; } if (mAudioManager == null) { Log.i(this, "clearScoCommunicationDevice: mAudioManager is null"); return; } AudioDeviceInfo audioDeviceInfo = mAudioManager.getCommunicationDevice(); if (audioDeviceInfo != null && audioDeviceInfo.getType() == AudioDeviceInfo.TYPE_BLUETOOTH_SCO) { mAudioManager.clearCommunicationDevice(); } } public boolean setLeAudioCommunicationDevice(BluetoothDevice leAudioDevice) { public boolean setLeAudioCommunicationDevice() { Log.i(this, "setLeAudioCommunicationDevice"); // Ensure that the device being set isn't one we have set already. if (mLeAudioSetAsCommunicationDevice && leAudioDevice.getAddress().equals(mLeAudioDevice)) { Log.i(this, "No change in LE audio device."); if (mLeAudioSetAsCommunicationDevice) { Log.i(this, "setLeAudioCommunicationDevice already set"); return true; } Loading @@ -522,9 +490,7 @@ public class BluetoothDeviceManager { for (AudioDeviceInfo device : devices) { Log.i(this, " Available device type: " + device.getType()); // Make sure we find a device that hasn't been set already. if (device.getType() == AudioDeviceInfo.TYPE_BLE_HEADSET && !device.getAddress().equals(mLeAudioDevice)) { if (device.getType() == AudioDeviceInfo.TYPE_BLE_HEADSET) { bleHeadset = device; break; } Loading @@ -535,13 +501,8 @@ public class BluetoothDeviceManager { return false; } // Clear hearing aid or SCO communication device if set // clear hearing aid communication device if set clearHearingAidCommunicationDevice(); clearScoAudioCommunicationDevice(); // Check if another LE audio device was set as the communication device already and clear it if (mLeAudioDevice != null) { clearLeAudioCommunicationDevice(); } // Turn BLE_OUT_HEADSET ON. boolean result = mAudioManager.setCommunicationDevice(bleHeadset); Loading Loading @@ -589,9 +550,8 @@ public class BluetoothDeviceManager { return false; } // clear LE or SCO audio communication device if set // clear LE audio communication device if set clearLeAudioCommunicationDevice(); clearScoAudioCommunicationDevice(); // Turn hearing aid ON. boolean result = mAudioManager.setCommunicationDevice(hearingAid); Loading @@ -605,54 +565,6 @@ public class BluetoothDeviceManager { return result; } public boolean setScoAudioCommunicationDevice() { Log.i(this, "setScoCommunicationDevice"); if (mScoSetAsCommunicationDevice) { Log.i(this, "mScoSetAsCommunicationDevice already set"); return true; } if (mAudioManager == null) { Log.w(this, "mAudioManager is null"); return false; } AudioDeviceInfo scoAudio = null; List<AudioDeviceInfo> devices = mAudioManager.getAvailableCommunicationDevices(); if (devices.size() == 0) { Log.w(this, "No communication devices available."); return false; } for (AudioDeviceInfo device : devices) { Log.i(this, "Available device type: " + device.getType()); if (device.getType() == AudioDeviceInfo.TYPE_BLUETOOTH_SCO) { scoAudio = device; break; } } if (scoAudio == null) { Log.w(this, "No scoAudio device available"); return false; } // clear LE or hearing aid audio communication device if set clearLeAudioCommunicationDevice(); clearHearingAidCommunicationDevice(); // Set SCO communication device. boolean result = mAudioManager.setCommunicationDevice(scoAudio); if (!result) { Log.w(this, "Could not set scoAudio device"); return false; } mScoSetAsCommunicationDevice = true; mScoDevice = scoAudio.getAddress(); return true; } // Connect audio to the bluetooth device at address, checking to see whether it's // le audio, hearing aid or a HFP device, and using the proper BT API. public boolean connectAudio(String address, boolean switchingBtDevices) { Loading @@ -666,11 +578,10 @@ public class BluetoothDeviceManager { device, BluetoothAdapter.ACTIVE_DEVICE_ALL)) { /* ACTION_ACTIVE_DEVICE_CHANGED intent will trigger setting communication device. * Only after receiving ACTION_ACTIVE_DEVICE_CHANGED is it known that the device * that will be audio switched to is available to be chosen as communication device. */ * Only after receiving ACTION_ACTIVE_DEVICE_CHANGED it is known that device that * will be audio switched to is available to be choose as communication device */ if (!switchingBtDevices) { return setLeAudioCommunicationDevice(device); return setLeAudioCommunicationDevice(); } return true; Loading @@ -686,9 +597,8 @@ public class BluetoothDeviceManager { BluetoothAdapter.ACTIVE_DEVICE_ALL)) { /* ACTION_ACTIVE_DEVICE_CHANGED intent will trigger setting communication device. * Only after receiving ACTION_ACTIVE_DEVICE_CHANGED is it known that the device * that will be audio switched to is available to be chosen as communication device. */ * Only after receiving ACTION_ACTIVE_DEVICE_CHANGED it is known that device that * will be audio switched to is available to be choose as communication device */ if (!switchingBtDevices) { return setHearingAidCommunicationDevice(); } Loading @@ -708,24 +618,9 @@ public class BluetoothDeviceManager { Log.w(this, "Couldn't set active device to %s", address); return false; } /* ACTION_ACTIVE_DEVICE_CHANGED intent will trigger setting communication device. * Only after receiving ACTION_ACTIVE_DEVICE_CHANGED is it known that the device that * will be audio switched to is available to be chosen as communication device. */ if (!switchingBtDevices && !setScoAudioCommunicationDevice()) { // If the communication device cannot be set, we should not try connecting the SCO // audio device return false; } int scoConnectionRequest = mBluetoothHeadset.connectAudio(); boolean scoSuccessfulConnection = scoConnectionRequest == BluetoothStatusCodes.SUCCESS || scoConnectionRequest == BluetoothStatusCodes.ERROR_AUDIO_DEVICE_ALREADY_CONNECTED; if (!scoSuccessfulConnection) { // Clear communication device if we're unable to connect to BT headset audio clearScoAudioCommunicationDevice(); } return scoSuccessfulConnection; return scoConnectionRequest == BluetoothStatusCodes.SUCCESS || scoConnectionRequest == BluetoothStatusCodes.ERROR_AUDIO_DEVICE_ALREADY_CONNECTED; } else { Log.w(this, "Attempting to turn on audio for a disconnected device"); return false; Loading src/com/android/server/telecom/bluetooth/BluetoothRouteManager.java +11 −31 Original line number Diff line number Diff line Loading @@ -630,9 +630,6 @@ public class BluetoothRouteManager extends StateMachine { } } else if (deviceType == BluetoothDeviceManager.DEVICE_TYPE_HEADSET) { mHfpActiveDeviceCache = device; if (device == null) { mDeviceManager.clearScoAudioCommunicationDevice(); } } else { return; } Loading Loading @@ -786,19 +783,17 @@ public class BluetoothRouteManager extends StateMachine { int activeDevices = 0; if (bluetoothHeadset != null) { /* We can have a case where we have an active headset device but neither BluetoothDeviceManager#connectAudio nor BluetoothStateReceiver#handleActiveDeviceChanged have been called to set the communication device. In this case, we should count the active device and try to set the communication device. */ if (mDeviceManager.isScoSetAsCommunicationDevice() || bluetoothAdapter.getActiveDevices(BluetoothProfile.HEADSET) != null) { mDeviceManager.setScoAudioCommunicationDevice(); hfpAudioOnDevice = getHfpAudioOnDevice(bluetoothAdapter, bluetoothHeadset); if (hfpAudioOnDevice != null) { activeDevices++; for (BluetoothDevice device : bluetoothAdapter.getActiveDevices( BluetoothProfile.HEADSET)) { hfpAudioOnDevice = device; break; } if (hfpAudioOnDevice != null && bluetoothHeadset.getAudioState(hfpAudioOnDevice) == BluetoothHeadset.STATE_AUDIO_DISCONNECTED) { hfpAudioOnDevice = null; } else { activeDevices++; } } Loading Loading @@ -847,21 +842,6 @@ public class BluetoothRouteManager extends StateMachine { return hfpAudioOnDevice; } private BluetoothDevice getHfpAudioOnDevice(BluetoothAdapter bluetoothAdapter, BluetoothHeadset bluetoothHeadset) { BluetoothDevice hfpAudioOnDevice = null; for (BluetoothDevice device : bluetoothAdapter.getActiveDevices( BluetoothProfile.HEADSET)) { hfpAudioOnDevice = device; break; } if (hfpAudioOnDevice != null && bluetoothHeadset.getAudioState(hfpAudioOnDevice) == BluetoothHeadset.STATE_AUDIO_DISCONNECTED) { hfpAudioOnDevice = null; } return hfpAudioOnDevice; } /** * Check if in-band ringing is currently enabled. In-band ringing could be disabled during an * active connection. Loading src/com/android/server/telecom/bluetooth/BluetoothStateReceiver.java +31 −35 Original line number Diff line number Diff line Loading @@ -166,7 +166,8 @@ public class BluetoothStateReceiver extends BroadcastReceiver { BluetoothDeviceManager.getDeviceTypeString(deviceType)); mBluetoothRouteManager.onActiveDeviceChanged(device, deviceType); if (deviceType == BluetoothDeviceManager.DEVICE_TYPE_HEARING_AID || deviceType == BluetoothDeviceManager.DEVICE_TYPE_LE_AUDIO) { Session session = Log.createSubsession(); SomeArgs args = SomeArgs.obtain(); args.arg1 = session; Loading @@ -178,31 +179,26 @@ public class BluetoothStateReceiver extends BroadcastReceiver { return; } args.arg2 = device.getAddress(); if (deviceType == BluetoothDeviceManager.DEVICE_TYPE_LE_AUDIO) { /* In Le Audio case, once device got Active, the Telecom needs to make sure it * is set as communication device before we can say that BT_AUDIO_IS_ON */ if (!mBluetoothDeviceManager.setLeAudioCommunicationDevice(device)) { if (!mBluetoothDeviceManager.setLeAudioCommunicationDevice()) { Log.w(LOG_TAG, "Device %s cannot be used as LE audio communication device.", "Device %s cannot be use as LE audio communication device.", device); return; } } else if (deviceType == BluetoothDeviceManager.DEVICE_TYPE_HEARING_AID) { } else { /* deviceType == BluetoothDeviceManager.DEVICE_TYPE_HEARING_AID */ if (!mBluetoothDeviceManager.setHearingAidCommunicationDevice()) { Log.w(LOG_TAG, "Device %s cannot be used as hearing aid communication device.", "Device %s cannot be use as hearing aid communication device.", device); } else { mBluetoothRouteManager.sendMessage(BT_AUDIO_IS_ON, args); } } else { /* deviceType == BluetoothDeviceManager.DEVICE_TYPE_HEADSET */ if (!mBluetoothDeviceManager.setScoAudioCommunicationDevice()) { Log.w(LOG_TAG, "Device %s cannot be used as SCO audio communication device.", device); } } } Loading tests/src/com/android/server/telecom/tests/BasicCallTests.java +1 −1 Original line number Diff line number Diff line Loading @@ -641,7 +641,7 @@ public class BasicCallTests extends TelecomSystemTest { .getCallAudioRouteStateMachine().getHandler(), TEST_TIMEOUT); ArgumentCaptor<AudioDeviceInfo> infoArgumentCaptor = ArgumentCaptor.forClass(AudioDeviceInfo.class); verify(audioManager, timeout(TEST_TIMEOUT).atLeast(1)).setCommunicationDevice( verify(audioManager, timeout(TEST_TIMEOUT)).setCommunicationDevice( infoArgumentCaptor.capture()); assertEquals(AudioDeviceInfo.TYPE_BUILTIN_SPEAKER, infoArgumentCaptor.getValue().getType()); mInCallServiceFixtureX.mInCallAdapter.setAudioRoute(CallAudioState.ROUTE_EARPIECE, null); Loading Loading
src/com/android/server/telecom/CallAudioRouteStateMachine.java +1 −134 Original line number Diff line number Diff line Loading @@ -47,7 +47,6 @@ import com.android.server.telecom.bluetooth.BluetoothRouteManager; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Objects; import java.util.Set; import java.util.concurrent.Executor; Loading Loading @@ -235,9 +234,6 @@ public class CallAudioRouteStateMachine extends StateMachine { public static final String NAME = CallAudioRouteStateMachine.class.getName(); private boolean mActiveEarpieceSetAsCommunicationDevice = false; private boolean mActiveHeadsetSetAsCommunicationDevice = false; @Override protected void onPreHandleMessage(Message msg) { if (msg.obj != null && msg.obj instanceof SomeArgs) { Loading Loading @@ -375,7 +371,6 @@ public class CallAudioRouteStateMachine extends StateMachine { public void enter() { super.enter(); setSpeakerphoneOn(false); setActiveEarpieceCommunicationDevice(); CallAudioState newState = new CallAudioState(mIsMuted, ROUTE_EARPIECE, mAvailableRoutes, null, mBluetoothRouteManager.getConnectedDevices()); Loading Loading @@ -406,7 +401,6 @@ public class CallAudioRouteStateMachine extends StateMachine { case SWITCH_BLUETOOTH: case USER_SWITCH_BLUETOOTH: if ((mAvailableRoutes & ROUTE_BLUETOOTH) != 0) { clearActiveEarpieceCommunicationDevice(); if (mAudioFocusType == ACTIVE_FOCUS || mBluetoothRouteManager.isInbandRingingEnabled()) { String address = (msg.obj instanceof SomeArgs) ? Loading @@ -423,7 +417,6 @@ public class CallAudioRouteStateMachine extends StateMachine { case SWITCH_HEADSET: case USER_SWITCH_HEADSET: if ((mAvailableRoutes & ROUTE_WIRED_HEADSET) != 0) { clearActiveEarpieceCommunicationDevice(); transitionTo(mActiveHeadsetRoute); } else { Log.w(this, "Ignoring switch to headset command. Not available."); Loading @@ -433,7 +426,6 @@ public class CallAudioRouteStateMachine extends StateMachine { // fall through; we want to switch to speaker mode when docked and in a call. case SWITCH_SPEAKER: case USER_SWITCH_SPEAKER: clearActiveEarpieceCommunicationDevice(); setSpeakerphoneOn(true); // fall through case SPEAKER_ON: Loading Loading @@ -587,7 +579,6 @@ public class CallAudioRouteStateMachine extends StateMachine { public void enter() { super.enter(); setSpeakerphoneOn(false); setActiveHeadsetCommunicationDevice(); CallAudioState newState = new CallAudioState(mIsMuted, ROUTE_WIRED_HEADSET, mAvailableRoutes, null, mBluetoothRouteManager.getConnectedDevices()); setSystemAudioState(newState, true); Loading @@ -609,7 +600,6 @@ public class CallAudioRouteStateMachine extends StateMachine { case SWITCH_EARPIECE: case USER_SWITCH_EARPIECE: if ((mAvailableRoutes & ROUTE_EARPIECE) != 0) { clearActiveHeadsetCommunicationDevice(); transitionTo(mActiveEarpieceRoute); } else { Log.w(this, "Ignoring switch to earpiece command. Not available."); Loading @@ -625,7 +615,6 @@ public class CallAudioRouteStateMachine extends StateMachine { || mBluetoothRouteManager.isInbandRingingEnabled()) { String address = (msg.obj instanceof SomeArgs) ? (String) ((SomeArgs) msg.obj).arg2 : null; clearActiveHeadsetCommunicationDevice(); // Omit transition to ActiveBluetoothRoute until actual connection. setBluetoothOn(address); } else { Loading @@ -642,7 +631,6 @@ public class CallAudioRouteStateMachine extends StateMachine { return HANDLED; case SWITCH_SPEAKER: case USER_SWITCH_SPEAKER: clearActiveHeadsetCommunicationDevice(); setSpeakerphoneOn(true); // fall through case SPEAKER_ON: Loading Loading @@ -805,12 +793,6 @@ public class CallAudioRouteStateMachine extends StateMachine { public void enter() { super.enter(); setSpeakerphoneOn(false); // Try arbitrarily connecting to BT audio if we haven't already. This handles // the edge case of when the audio route is in a quiescent route while in-call and // the BT connection fails to be set. Previously, the logic was to setBluetoothOn in // ACTIVE_FOCUS but the route would still remain in a quiescent route, so instead we // should be transitioning directly into the active route. setBluetoothOn(null); CallAudioState newState = new CallAudioState(mIsMuted, ROUTE_BLUETOOTH, mAvailableRoutes, mBluetoothRouteManager.getBluetoothAudioConnectedDevice(), mBluetoothRouteManager.getConnectedDevices()); Loading Loading @@ -1083,9 +1065,7 @@ public class CallAudioRouteStateMachine extends StateMachine { return HANDLED; case SWITCH_FOCUS: if (msg.arg1 == ACTIVE_FOCUS) { // It is possible that the connection to BT will fail while in-call, in // which case, we want to transition into the active route. transitionTo(mActiveBluetoothRoute); setBluetoothOn(null); } else if (msg.arg1 == RINGING_FOCUS) { if (mBluetoothRouteManager.isInbandRingingEnabled()) { setBluetoothOn(null); Loading Loading @@ -1809,119 +1789,6 @@ public class CallAudioRouteStateMachine extends StateMachine { } } private void setActiveHeadsetCommunicationDevice() { Log.i(this, "setActiveHeadsetCommunicationDevice"); if (mActiveHeadsetSetAsCommunicationDevice) { Log.i(this, "mActiveHeadsetSetAsCommunicationDevice already set"); return; } AudioDeviceInfo activeHeadset = null; List<AudioDeviceInfo> devices = mAudioManager.getAvailableCommunicationDevices(); if (devices.size() == 0) { Log.w(this, "No communication devices available."); return; } for (AudioDeviceInfo device : devices) { Log.i(this, "Available device type: " + device.getType()); if (device.getType() == AudioDeviceInfo.TYPE_WIRED_HEADSET || device.getType() == AudioDeviceInfo.TYPE_USB_HEADSET) { activeHeadset = device; break; } } if (activeHeadset == null) { Log.w(this, "No activeHeadset device available"); return; } // Turn TYPE_WIRED_HEADSET ON. boolean result = mAudioManager.setCommunicationDevice(activeHeadset); if (!result) { Log.w(this, "Could not set activeHeadset device"); } else { Log.i(this, "activeHeadset device set"); mActiveHeadsetSetAsCommunicationDevice = true; } } private void setActiveEarpieceCommunicationDevice() { Log.i(this, "setActiveEarpieceCommunicationDevice"); if (mActiveEarpieceSetAsCommunicationDevice) { Log.i(this, "mActiveEarpieceSetAsCommunicationDevice already set"); return; } AudioDeviceInfo activeEarpiece = null; List<AudioDeviceInfo> devices = mAudioManager.getAvailableCommunicationDevices(); if (devices.size() == 0) { Log.w(this, "No communication devices available."); return; } for (AudioDeviceInfo device : devices) { Log.i(this, "Available device type: " + device.getType()); if (device.getType() == AudioDeviceInfo.TYPE_BUILTIN_EARPIECE) { activeEarpiece = device; break; } } if (activeEarpiece == null) { Log.w(this, "No active earpiece device available"); return; } // Turn TYPE_BUILTIN_EARPIECE ON. boolean result = mAudioManager.setCommunicationDevice(activeEarpiece); if (!result) { Log.w(this, "Could not set active earpiece device"); } else { Log.i(this, "Active earpiece device set"); mActiveEarpieceSetAsCommunicationDevice = true; } } public void clearActiveEarpieceCommunicationDevice() { Log.i(this, "clearActiveEarpieceCommunicationDevice:" + "mActiveEarpieceSetAsCommunicationDevice = " + mActiveEarpieceSetAsCommunicationDevice); if (!mActiveEarpieceSetAsCommunicationDevice) { return; } mActiveEarpieceSetAsCommunicationDevice = false; AudioDeviceInfo audioDeviceInfo = mAudioManager.getCommunicationDevice(); if (audioDeviceInfo != null && audioDeviceInfo.getType() == AudioDeviceInfo.TYPE_BUILTIN_EARPIECE) { mAudioManager.clearCommunicationDevice(); } } public void clearActiveHeadsetCommunicationDevice() { Log.i(this, "clearActiveHeadsetCommunicationDevice:" + "mActiveHeadsetSetAsCommunicationDevice = " + mActiveHeadsetSetAsCommunicationDevice); if (!mActiveHeadsetSetAsCommunicationDevice) { return; } mActiveHeadsetSetAsCommunicationDevice = false; AudioDeviceInfo audioDeviceInfo = mAudioManager.getCommunicationDevice(); if (audioDeviceInfo != null && (audioDeviceInfo.getType() == AudioDeviceInfo.TYPE_WIRED_HEADSET || audioDeviceInfo.getType() == AudioDeviceInfo.TYPE_USB_HEADSET)) { mAudioManager.clearCommunicationDevice(); } } private void setMuteOn(boolean mute) { mIsMuted = mute; Log.addEvent(mCallsManager.getForegroundCall(), mute ? Loading
src/com/android/server/telecom/bluetooth/BluetoothDeviceManager.java +25 −130 Original line number Diff line number Diff line Loading @@ -189,9 +189,7 @@ public class BluetoothDeviceManager { private boolean mLeAudioSetAsCommunicationDevice = false; private String mLeAudioDevice; private String mHearingAidDevice; private String mScoDevice; private boolean mHearingAidSetAsCommunicationDevice = false; private boolean mScoSetAsCommunicationDevice = false; private BluetoothDevice mBluetoothHearingAidActiveDeviceCache; private BluetoothAdapter mBluetoothAdapter; private AudioManager mAudioManager; Loading Loading @@ -400,13 +398,12 @@ public class BluetoothDeviceManager { } public void disconnectAudio() { disconnectScoAudio(); disconnectSco(); clearLeAudioCommunicationDevice(); clearHearingAidCommunicationDevice(); } public void disconnectScoAudio() { clearScoAudioCommunicationDevice(); public void disconnectSco() { if (mBluetoothHeadset == null) { Log.w(this, "Trying to disconnect audio but no headset service exists."); } else { Loading @@ -422,10 +419,6 @@ public class BluetoothDeviceManager { return mHearingAidSetAsCommunicationDevice; } public boolean isScoSetAsCommunicationDevice() { return mScoSetAsCommunicationDevice; } public void clearLeAudioCommunicationDevice() { Log.i(this, "clearLeAudioCommunicationDevice: mLeAudioSetAsCommunicationDevice = " + mLeAudioSetAsCommunicationDevice + " device = " + mLeAudioDevice); Loading Loading @@ -475,36 +468,11 @@ public class BluetoothDeviceManager { } } public void clearScoAudioCommunicationDevice() { Log.i(this, "clearScoCommunicationDevice: mScoSetAsCommunicationDevice = " + mScoSetAsCommunicationDevice); if (!mScoSetAsCommunicationDevice) { return; } mScoSetAsCommunicationDevice = false; if (mScoDevice != null) { mBluetoothRouteManager.onAudioLost(mScoDevice); mScoDevice = null; } if (mAudioManager == null) { Log.i(this, "clearScoCommunicationDevice: mAudioManager is null"); return; } AudioDeviceInfo audioDeviceInfo = mAudioManager.getCommunicationDevice(); if (audioDeviceInfo != null && audioDeviceInfo.getType() == AudioDeviceInfo.TYPE_BLUETOOTH_SCO) { mAudioManager.clearCommunicationDevice(); } } public boolean setLeAudioCommunicationDevice(BluetoothDevice leAudioDevice) { public boolean setLeAudioCommunicationDevice() { Log.i(this, "setLeAudioCommunicationDevice"); // Ensure that the device being set isn't one we have set already. if (mLeAudioSetAsCommunicationDevice && leAudioDevice.getAddress().equals(mLeAudioDevice)) { Log.i(this, "No change in LE audio device."); if (mLeAudioSetAsCommunicationDevice) { Log.i(this, "setLeAudioCommunicationDevice already set"); return true; } Loading @@ -522,9 +490,7 @@ public class BluetoothDeviceManager { for (AudioDeviceInfo device : devices) { Log.i(this, " Available device type: " + device.getType()); // Make sure we find a device that hasn't been set already. if (device.getType() == AudioDeviceInfo.TYPE_BLE_HEADSET && !device.getAddress().equals(mLeAudioDevice)) { if (device.getType() == AudioDeviceInfo.TYPE_BLE_HEADSET) { bleHeadset = device; break; } Loading @@ -535,13 +501,8 @@ public class BluetoothDeviceManager { return false; } // Clear hearing aid or SCO communication device if set // clear hearing aid communication device if set clearHearingAidCommunicationDevice(); clearScoAudioCommunicationDevice(); // Check if another LE audio device was set as the communication device already and clear it if (mLeAudioDevice != null) { clearLeAudioCommunicationDevice(); } // Turn BLE_OUT_HEADSET ON. boolean result = mAudioManager.setCommunicationDevice(bleHeadset); Loading Loading @@ -589,9 +550,8 @@ public class BluetoothDeviceManager { return false; } // clear LE or SCO audio communication device if set // clear LE audio communication device if set clearLeAudioCommunicationDevice(); clearScoAudioCommunicationDevice(); // Turn hearing aid ON. boolean result = mAudioManager.setCommunicationDevice(hearingAid); Loading @@ -605,54 +565,6 @@ public class BluetoothDeviceManager { return result; } public boolean setScoAudioCommunicationDevice() { Log.i(this, "setScoCommunicationDevice"); if (mScoSetAsCommunicationDevice) { Log.i(this, "mScoSetAsCommunicationDevice already set"); return true; } if (mAudioManager == null) { Log.w(this, "mAudioManager is null"); return false; } AudioDeviceInfo scoAudio = null; List<AudioDeviceInfo> devices = mAudioManager.getAvailableCommunicationDevices(); if (devices.size() == 0) { Log.w(this, "No communication devices available."); return false; } for (AudioDeviceInfo device : devices) { Log.i(this, "Available device type: " + device.getType()); if (device.getType() == AudioDeviceInfo.TYPE_BLUETOOTH_SCO) { scoAudio = device; break; } } if (scoAudio == null) { Log.w(this, "No scoAudio device available"); return false; } // clear LE or hearing aid audio communication device if set clearLeAudioCommunicationDevice(); clearHearingAidCommunicationDevice(); // Set SCO communication device. boolean result = mAudioManager.setCommunicationDevice(scoAudio); if (!result) { Log.w(this, "Could not set scoAudio device"); return false; } mScoSetAsCommunicationDevice = true; mScoDevice = scoAudio.getAddress(); return true; } // Connect audio to the bluetooth device at address, checking to see whether it's // le audio, hearing aid or a HFP device, and using the proper BT API. public boolean connectAudio(String address, boolean switchingBtDevices) { Loading @@ -666,11 +578,10 @@ public class BluetoothDeviceManager { device, BluetoothAdapter.ACTIVE_DEVICE_ALL)) { /* ACTION_ACTIVE_DEVICE_CHANGED intent will trigger setting communication device. * Only after receiving ACTION_ACTIVE_DEVICE_CHANGED is it known that the device * that will be audio switched to is available to be chosen as communication device. */ * Only after receiving ACTION_ACTIVE_DEVICE_CHANGED it is known that device that * will be audio switched to is available to be choose as communication device */ if (!switchingBtDevices) { return setLeAudioCommunicationDevice(device); return setLeAudioCommunicationDevice(); } return true; Loading @@ -686,9 +597,8 @@ public class BluetoothDeviceManager { BluetoothAdapter.ACTIVE_DEVICE_ALL)) { /* ACTION_ACTIVE_DEVICE_CHANGED intent will trigger setting communication device. * Only after receiving ACTION_ACTIVE_DEVICE_CHANGED is it known that the device * that will be audio switched to is available to be chosen as communication device. */ * Only after receiving ACTION_ACTIVE_DEVICE_CHANGED it is known that device that * will be audio switched to is available to be choose as communication device */ if (!switchingBtDevices) { return setHearingAidCommunicationDevice(); } Loading @@ -708,24 +618,9 @@ public class BluetoothDeviceManager { Log.w(this, "Couldn't set active device to %s", address); return false; } /* ACTION_ACTIVE_DEVICE_CHANGED intent will trigger setting communication device. * Only after receiving ACTION_ACTIVE_DEVICE_CHANGED is it known that the device that * will be audio switched to is available to be chosen as communication device. */ if (!switchingBtDevices && !setScoAudioCommunicationDevice()) { // If the communication device cannot be set, we should not try connecting the SCO // audio device return false; } int scoConnectionRequest = mBluetoothHeadset.connectAudio(); boolean scoSuccessfulConnection = scoConnectionRequest == BluetoothStatusCodes.SUCCESS || scoConnectionRequest == BluetoothStatusCodes.ERROR_AUDIO_DEVICE_ALREADY_CONNECTED; if (!scoSuccessfulConnection) { // Clear communication device if we're unable to connect to BT headset audio clearScoAudioCommunicationDevice(); } return scoSuccessfulConnection; return scoConnectionRequest == BluetoothStatusCodes.SUCCESS || scoConnectionRequest == BluetoothStatusCodes.ERROR_AUDIO_DEVICE_ALREADY_CONNECTED; } else { Log.w(this, "Attempting to turn on audio for a disconnected device"); return false; Loading
src/com/android/server/telecom/bluetooth/BluetoothRouteManager.java +11 −31 Original line number Diff line number Diff line Loading @@ -630,9 +630,6 @@ public class BluetoothRouteManager extends StateMachine { } } else if (deviceType == BluetoothDeviceManager.DEVICE_TYPE_HEADSET) { mHfpActiveDeviceCache = device; if (device == null) { mDeviceManager.clearScoAudioCommunicationDevice(); } } else { return; } Loading Loading @@ -786,19 +783,17 @@ public class BluetoothRouteManager extends StateMachine { int activeDevices = 0; if (bluetoothHeadset != null) { /* We can have a case where we have an active headset device but neither BluetoothDeviceManager#connectAudio nor BluetoothStateReceiver#handleActiveDeviceChanged have been called to set the communication device. In this case, we should count the active device and try to set the communication device. */ if (mDeviceManager.isScoSetAsCommunicationDevice() || bluetoothAdapter.getActiveDevices(BluetoothProfile.HEADSET) != null) { mDeviceManager.setScoAudioCommunicationDevice(); hfpAudioOnDevice = getHfpAudioOnDevice(bluetoothAdapter, bluetoothHeadset); if (hfpAudioOnDevice != null) { activeDevices++; for (BluetoothDevice device : bluetoothAdapter.getActiveDevices( BluetoothProfile.HEADSET)) { hfpAudioOnDevice = device; break; } if (hfpAudioOnDevice != null && bluetoothHeadset.getAudioState(hfpAudioOnDevice) == BluetoothHeadset.STATE_AUDIO_DISCONNECTED) { hfpAudioOnDevice = null; } else { activeDevices++; } } Loading Loading @@ -847,21 +842,6 @@ public class BluetoothRouteManager extends StateMachine { return hfpAudioOnDevice; } private BluetoothDevice getHfpAudioOnDevice(BluetoothAdapter bluetoothAdapter, BluetoothHeadset bluetoothHeadset) { BluetoothDevice hfpAudioOnDevice = null; for (BluetoothDevice device : bluetoothAdapter.getActiveDevices( BluetoothProfile.HEADSET)) { hfpAudioOnDevice = device; break; } if (hfpAudioOnDevice != null && bluetoothHeadset.getAudioState(hfpAudioOnDevice) == BluetoothHeadset.STATE_AUDIO_DISCONNECTED) { hfpAudioOnDevice = null; } return hfpAudioOnDevice; } /** * Check if in-band ringing is currently enabled. In-band ringing could be disabled during an * active connection. Loading
src/com/android/server/telecom/bluetooth/BluetoothStateReceiver.java +31 −35 Original line number Diff line number Diff line Loading @@ -166,7 +166,8 @@ public class BluetoothStateReceiver extends BroadcastReceiver { BluetoothDeviceManager.getDeviceTypeString(deviceType)); mBluetoothRouteManager.onActiveDeviceChanged(device, deviceType); if (deviceType == BluetoothDeviceManager.DEVICE_TYPE_HEARING_AID || deviceType == BluetoothDeviceManager.DEVICE_TYPE_LE_AUDIO) { Session session = Log.createSubsession(); SomeArgs args = SomeArgs.obtain(); args.arg1 = session; Loading @@ -178,31 +179,26 @@ public class BluetoothStateReceiver extends BroadcastReceiver { return; } args.arg2 = device.getAddress(); if (deviceType == BluetoothDeviceManager.DEVICE_TYPE_LE_AUDIO) { /* In Le Audio case, once device got Active, the Telecom needs to make sure it * is set as communication device before we can say that BT_AUDIO_IS_ON */ if (!mBluetoothDeviceManager.setLeAudioCommunicationDevice(device)) { if (!mBluetoothDeviceManager.setLeAudioCommunicationDevice()) { Log.w(LOG_TAG, "Device %s cannot be used as LE audio communication device.", "Device %s cannot be use as LE audio communication device.", device); return; } } else if (deviceType == BluetoothDeviceManager.DEVICE_TYPE_HEARING_AID) { } else { /* deviceType == BluetoothDeviceManager.DEVICE_TYPE_HEARING_AID */ if (!mBluetoothDeviceManager.setHearingAidCommunicationDevice()) { Log.w(LOG_TAG, "Device %s cannot be used as hearing aid communication device.", "Device %s cannot be use as hearing aid communication device.", device); } else { mBluetoothRouteManager.sendMessage(BT_AUDIO_IS_ON, args); } } else { /* deviceType == BluetoothDeviceManager.DEVICE_TYPE_HEADSET */ if (!mBluetoothDeviceManager.setScoAudioCommunicationDevice()) { Log.w(LOG_TAG, "Device %s cannot be used as SCO audio communication device.", device); } } } Loading
tests/src/com/android/server/telecom/tests/BasicCallTests.java +1 −1 Original line number Diff line number Diff line Loading @@ -641,7 +641,7 @@ public class BasicCallTests extends TelecomSystemTest { .getCallAudioRouteStateMachine().getHandler(), TEST_TIMEOUT); ArgumentCaptor<AudioDeviceInfo> infoArgumentCaptor = ArgumentCaptor.forClass(AudioDeviceInfo.class); verify(audioManager, timeout(TEST_TIMEOUT).atLeast(1)).setCommunicationDevice( verify(audioManager, timeout(TEST_TIMEOUT)).setCommunicationDevice( infoArgumentCaptor.capture()); assertEquals(AudioDeviceInfo.TYPE_BUILTIN_SPEAKER, infoArgumentCaptor.getValue().getType()); mInCallServiceFixtureX.mInCallAdapter.setAudioRoute(CallAudioState.ROUTE_EARPIECE, null); Loading