Don't follow BT audio changes outside of calls
When there's no Telecom call going on, don't use BRM to follow Bluetooth
audio changes -- this will interfere with other apps trying to use HFP.
Bug: 73274274
Test: unit test update, manual
Change-Id: Ia4e71fb71baafc9e9f8702ab72f803d47c37482a
diff --git a/src/com/android/server/telecom/CallAudioManager.java b/src/com/android/server/telecom/CallAudioManager.java
index 4b328f5..ad446ec 100644
--- a/src/com/android/server/telecom/CallAudioManager.java
+++ b/src/com/android/server/telecom/CallAudioManager.java
@@ -26,6 +26,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.IndentingPrintWriter;
+import com.android.server.telecom.bluetooth.BluetoothStateReceiver;
import java.util.Collection;
import java.util.HashSet;
@@ -48,6 +49,7 @@
private final CallAudioRouteStateMachine mCallAudioRouteStateMachine;
private final CallAudioModeStateMachine mCallAudioModeStateMachine;
+ private final BluetoothStateReceiver mBluetoothStateReceiver;
private final CallsManager mCallsManager;
private final InCallTonePlayer.Factory mPlayerFactory;
private final Ringer mRinger;
@@ -65,6 +67,7 @@
InCallTonePlayer.Factory playerFactory,
Ringer ringer,
RingbackPlayer ringbackPlayer,
+ BluetoothStateReceiver bluetoothStateReceiver,
DtmfLocalTonePlayer dtmfLocalTonePlayer) {
mActiveDialingOrConnectingCalls = new LinkedHashSet<>();
mRingingCalls = new LinkedHashSet<>();
@@ -85,6 +88,7 @@
mPlayerFactory = playerFactory;
mRinger = ringer;
mRingbackPlayer = ringbackPlayer;
+ mBluetoothStateReceiver = bluetoothStateReceiver;
mDtmfLocalTonePlayer = dtmfLocalTonePlayer;
mPlayerFactory.setCallAudioManager(this);
@@ -148,6 +152,9 @@
}
updateForegroundCall();
mCalls.add(call);
+ if (mCalls.size() == 1) {
+ mBluetoothStateReceiver.setIsInCall(true);
+ }
onCallEnteringState(call, call.getState());
}
@@ -166,6 +173,9 @@
updateForegroundCall();
mCalls.remove(call);
+ if (mCalls.size() == 0) {
+ mBluetoothStateReceiver.setIsInCall(false);
+ }
onCallLeavingState(call, call.getState());
}
diff --git a/src/com/android/server/telecom/CallsManager.java b/src/com/android/server/telecom/CallsManager.java
index faaffe8..c7e994b 100644
--- a/src/com/android/server/telecom/CallsManager.java
+++ b/src/com/android/server/telecom/CallsManager.java
@@ -57,6 +57,7 @@
import com.android.internal.telephony.TelephonyProperties;
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.telecom.bluetooth.BluetoothRouteManager;
+import com.android.server.telecom.bluetooth.BluetoothStateReceiver;
import com.android.server.telecom.callfiltering.AsyncBlockCheckFilter;
import com.android.server.telecom.callfiltering.BlockCheckerAdapter;
import com.android.server.telecom.callfiltering.CallFilterResultCallback;
@@ -337,6 +338,7 @@
EmergencyCallHelper emergencyCallHelper,
InCallTonePlayer.ToneGeneratorFactory toneGeneratorFactory,
ClockProxy clockProxy,
+ BluetoothStateReceiver bluetoothStateReceiver,
InCallControllerFactory inCallControllerFactory) {
mContext = context;
mLock = lock;
@@ -392,7 +394,8 @@
mCallAudioManager = new CallAudioManager(callAudioRouteStateMachine,
this,new CallAudioModeStateMachine((AudioManager)
mContext.getSystemService(Context.AUDIO_SERVICE)),
- playerFactory, mRinger, new RingbackPlayer(playerFactory), mDtmfLocalTonePlayer);
+ playerFactory, mRinger, new RingbackPlayer(playerFactory),
+ bluetoothStateReceiver, mDtmfLocalTonePlayer);
mConnectionSvrFocusMgr = connectionServiceFocusManagerFactory.create(
mRequester, Looper.getMainLooper());
diff --git a/src/com/android/server/telecom/TelecomSystem.java b/src/com/android/server/telecom/TelecomSystem.java
index 18b24f2..3fd0e21 100644
--- a/src/com/android/server/telecom/TelecomSystem.java
+++ b/src/com/android/server/telecom/TelecomSystem.java
@@ -19,6 +19,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.telecom.bluetooth.BluetoothDeviceManager;
import com.android.server.telecom.bluetooth.BluetoothRouteManager;
+import com.android.server.telecom.bluetooth.BluetoothStateReceiver;
import com.android.server.telecom.components.UserCallIntentProcessor;
import com.android.server.telecom.components.UserCallIntentProcessorFactory;
import com.android.server.telecom.ui.IncomingCallNotifier;
@@ -229,6 +230,10 @@
new BluetoothAdapterProxy(), mLock);
BluetoothRouteManager bluetoothRouteManager = new BluetoothRouteManager(mContext, mLock,
bluetoothDeviceManager, new Timeouts.Adapter());
+ BluetoothStateReceiver bluetoothStateReceiver = new BluetoothStateReceiver(
+ bluetoothDeviceManager, bluetoothRouteManager);
+ mContext.registerReceiver(bluetoothStateReceiver, BluetoothStateReceiver.INTENT_FILTER);
+
WiredHeadsetManager wiredHeadsetManager = new WiredHeadsetManager(mContext);
SystemStateProvider systemStateProvider = new SystemStateProvider(mContext);
@@ -271,6 +276,7 @@
emergencyCallHelper,
toneGeneratorFactory,
clockProxy,
+ bluetoothStateReceiver,
inCallControllerFactory);
mIncomingCallNotifier = incomingCallNotifier;
diff --git a/src/com/android/server/telecom/bluetooth/BluetoothDeviceManager.java b/src/com/android/server/telecom/bluetooth/BluetoothDeviceManager.java
index e45e9af..ff81b4d 100644
--- a/src/com/android/server/telecom/bluetooth/BluetoothDeviceManager.java
+++ b/src/com/android/server/telecom/bluetooth/BluetoothDeviceManager.java
@@ -80,49 +80,6 @@
}
};
- private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- Log.startSession("BM.oR");
- try {
- String action = intent.getAction();
-
- if (action.equals(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED)) {
- int bluetoothHeadsetState = intent.getIntExtra(BluetoothHeadset.EXTRA_STATE,
- BluetoothHeadset.STATE_DISCONNECTED);
- BluetoothDevice device =
- intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
-
- if (device == null) {
- Log.w(BluetoothDeviceManager.this, "Got null device from broadcast. " +
- "Ignoring.");
- return;
- }
-
- Log.i(BluetoothDeviceManager.this, "Device %s changed state to %d",
- device.getAddress(), bluetoothHeadsetState);
-
- synchronized (mLock) {
- if (bluetoothHeadsetState == BluetoothHeadset.STATE_CONNECTED) {
- if (!mConnectedDevicesByAddress.containsKey(device.getAddress())) {
- mConnectedDevicesByAddress.put(device.getAddress(), device);
- mBluetoothRouteManager.onDeviceAdded(device.getAddress());
- }
- } else if (bluetoothHeadsetState == BluetoothHeadset.STATE_DISCONNECTED
- || bluetoothHeadsetState == BluetoothHeadset.STATE_DISCONNECTING) {
- if (mConnectedDevicesByAddress.containsKey(device.getAddress())) {
- mConnectedDevicesByAddress.remove(device.getAddress());
- mBluetoothRouteManager.onDeviceLost(device.getAddress());
- }
- }
- }
- }
- } finally {
- Log.endSession();
- }
- }
- };
-
private final LinkedHashMap<String, BluetoothDevice> mConnectedDevicesByAddress =
new LinkedHashMap<>();
private final TelecomSystem.SyncRoot mLock;
@@ -138,9 +95,6 @@
bluetoothAdapter.getProfileProxy(context, mBluetoothProfileServiceListener,
BluetoothProfile.HEADSET);
}
- IntentFilter intentFilter =
- new IntentFilter(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED);
- context.registerReceiver(mReceiver, intentFilter);
}
public void setBluetoothRouteManager(BluetoothRouteManager brm) {
@@ -174,4 +128,22 @@
public void setHeadsetServiceForTesting(BluetoothHeadsetProxy bluetoothHeadset) {
mBluetoothHeadsetService = bluetoothHeadset;
}
+
+ void onDeviceConnected(BluetoothDevice device) {
+ synchronized (mLock) {
+ if (!mConnectedDevicesByAddress.containsKey(device.getAddress())) {
+ mConnectedDevicesByAddress.put(device.getAddress(), device);
+ mBluetoothRouteManager.onDeviceAdded(device.getAddress());
+ }
+ }
+ }
+
+ void onDeviceDisconnected(BluetoothDevice device) {
+ synchronized (mLock) {
+ if (mConnectedDevicesByAddress.containsKey(device.getAddress())) {
+ mConnectedDevicesByAddress.remove(device.getAddress());
+ mBluetoothRouteManager.onDeviceLost(device.getAddress());
+ }
+ }
+ }
}
diff --git a/src/com/android/server/telecom/bluetooth/BluetoothRouteManager.java b/src/com/android/server/telecom/bluetooth/BluetoothRouteManager.java
index 2a4d6af..cdb8b4e 100644
--- a/src/com/android/server/telecom/bluetooth/BluetoothRouteManager.java
+++ b/src/com/android/server/telecom/bluetooth/BluetoothRouteManager.java
@@ -80,47 +80,6 @@
void onBluetoothAudioDisconnected();
}
- // Broadcast receiver to receive audio state change broadcasts from the BT stack
- private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- Log.startSession("BRM.oR");
- try {
- String action = intent.getAction();
-
- if (action.equals(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED)) {
- int bluetoothHeadsetAudioState =
- intent.getIntExtra(BluetoothHeadset.EXTRA_STATE,
- BluetoothHeadset.STATE_AUDIO_DISCONNECTED);
- BluetoothDevice device =
- intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
- if (device == null) {
- Log.w(BluetoothRouteManager.this, "Got null device from broadcast. " +
- "Ignoring.");
- return;
- }
-
- Log.i(BluetoothRouteManager.this, "Device %s transitioned to audio state %d",
- device.getAddress(), bluetoothHeadsetAudioState);
- Session session = Log.createSubsession();
- SomeArgs args = SomeArgs.obtain();
- args.arg1 = session;
- args.arg2 = device.getAddress();
- switch (bluetoothHeadsetAudioState) {
- case BluetoothHeadset.STATE_AUDIO_CONNECTED:
- sendMessage(HFP_IS_ON, args);
- break;
- case BluetoothHeadset.STATE_AUDIO_DISCONNECTED:
- sendMessage(HFP_LOST, args);
- break;
- }
- }
- } finally {
- Log.endSession();
- }
- }
- };
-
/**
* Constants representing messages sent to the state machine.
* Messages are expected to be sent with {@link SomeArgs} as the obj.
@@ -511,9 +470,6 @@
mDeviceManager.setBluetoothRouteManager(this);
mTimeoutsAdapter = timeoutsAdapter;
- IntentFilter intentFilter = new IntentFilter(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED);
- context.registerReceiver(mReceiver, intentFilter);
-
mAudioOffState = new AudioOffState();
addState(mAudioOffState);
setInitialState(mAudioOffState);
diff --git a/src/com/android/server/telecom/bluetooth/BluetoothStateReceiver.java b/src/com/android/server/telecom/bluetooth/BluetoothStateReceiver.java
new file mode 100644
index 0000000..802fba0
--- /dev/null
+++ b/src/com/android/server/telecom/bluetooth/BluetoothStateReceiver.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.telecom.bluetooth;
+
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothHeadset;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.telecom.Log;
+import android.telecom.Logging.Session;
+
+import com.android.internal.os.SomeArgs;
+
+import static com.android.server.telecom.bluetooth.BluetoothRouteManager.HFP_IS_ON;
+import static com.android.server.telecom.bluetooth.BluetoothRouteManager.HFP_LOST;
+
+
+public class BluetoothStateReceiver extends BroadcastReceiver {
+ private static final String LOG_TAG = BluetoothStateReceiver.class.getSimpleName();
+ public static final IntentFilter INTENT_FILTER;
+ static {
+ INTENT_FILTER = new IntentFilter();
+ INTENT_FILTER.addAction(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED);
+ INTENT_FILTER.addAction(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED);
+ }
+
+ // If not in a call, BSR won't listen to the Bluetooth stack's HFP on/off messages, since
+ // other apps could be turning it on and off. We don't want to interfere.
+ private boolean mIsInCall = false;
+ private final BluetoothRouteManager mBluetoothRouteManager;
+ private final BluetoothDeviceManager mBluetoothDeviceManager;
+
+ public void onReceive(Context context, Intent intent) {
+ Log.startSession("BSR.oR");
+ try {
+ String action = intent.getAction();
+
+ if (action.equals(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED)) {
+ if (!mIsInCall) {
+ Log.i(LOG_TAG, "Ignoring BT audio state change since we're not in a call");
+ return;
+ }
+ int bluetoothHeadsetAudioState =
+ intent.getIntExtra(BluetoothHeadset.EXTRA_STATE,
+ BluetoothHeadset.STATE_AUDIO_DISCONNECTED);
+ BluetoothDevice device =
+ intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
+ if (device == null) {
+ Log.w(LOG_TAG, "Got null device from broadcast. " +
+ "Ignoring.");
+ return;
+ }
+
+ Log.i(LOG_TAG, "Device %s transitioned to audio state %d",
+ device.getAddress(), bluetoothHeadsetAudioState);
+ Session session = Log.createSubsession();
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = session;
+ args.arg2 = device.getAddress();
+ switch (bluetoothHeadsetAudioState) {
+ case BluetoothHeadset.STATE_AUDIO_CONNECTED:
+ mBluetoothRouteManager.sendMessage(HFP_IS_ON, args);
+ break;
+ case BluetoothHeadset.STATE_AUDIO_DISCONNECTED:
+ mBluetoothRouteManager.sendMessage(HFP_LOST, args);
+ break;
+ }
+ }
+
+ else if (action.equals(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED)) {
+ int bluetoothHeadsetState = intent.getIntExtra(BluetoothHeadset.EXTRA_STATE,
+ BluetoothHeadset.STATE_DISCONNECTED);
+ BluetoothDevice device =
+ intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
+
+ if (device == null) {
+ Log.w(LOG_TAG, "Got null device from broadcast. " +
+ "Ignoring.");
+ return;
+ }
+
+ Log.i(LOG_TAG, "Device %s changed state to %d",
+ device.getAddress(), bluetoothHeadsetState);
+
+ if (bluetoothHeadsetState == BluetoothHeadset.STATE_CONNECTED) {
+ mBluetoothDeviceManager.onDeviceConnected(device);
+ } else if (bluetoothHeadsetState == BluetoothHeadset.STATE_DISCONNECTED
+ || bluetoothHeadsetState == BluetoothHeadset.STATE_DISCONNECTING) {
+ mBluetoothDeviceManager.onDeviceDisconnected(device);
+ }
+ }
+ } finally {
+ Log.endSession();
+ }
+ }
+
+ public BluetoothStateReceiver(BluetoothDeviceManager deviceManager,
+ BluetoothRouteManager routeManager) {
+ mBluetoothDeviceManager = deviceManager;
+ mBluetoothRouteManager = routeManager;
+ }
+
+ public void setIsInCall(boolean isInCall) {
+ mIsInCall = isInCall;
+ }
+}
diff --git a/tests/src/com/android/server/telecom/tests/BluetoothDeviceManagerTest.java b/tests/src/com/android/server/telecom/tests/BluetoothDeviceManagerTest.java
index 59934dc..4a48f1b 100644
--- a/tests/src/com/android/server/telecom/tests/BluetoothDeviceManagerTest.java
+++ b/tests/src/com/android/server/telecom/tests/BluetoothDeviceManagerTest.java
@@ -30,6 +30,7 @@
import com.android.server.telecom.TelecomSystem;
import com.android.server.telecom.bluetooth.BluetoothDeviceManager;
import com.android.server.telecom.bluetooth.BluetoothRouteManager;
+import com.android.server.telecom.bluetooth.BluetoothStateReceiver;
import org.junit.Before;
import org.junit.Test;
@@ -77,14 +78,8 @@
serviceCaptor.capture(), eq(BluetoothProfile.HEADSET));
serviceListenerUnderTest = serviceCaptor.getValue();
- ArgumentCaptor<BroadcastReceiver> receiverCaptor =
- ArgumentCaptor.forClass(BroadcastReceiver.class);
- ArgumentCaptor<IntentFilter> intentFilterCaptor =
- ArgumentCaptor.forClass(IntentFilter.class);
- verify(mContext).registerReceiver(receiverCaptor.capture(), intentFilterCaptor.capture());
- assertTrue(intentFilterCaptor.getValue().hasAction(
- BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED));
- receiverUnderTest = receiverCaptor.getValue();
+ receiverUnderTest = new BluetoothStateReceiver(mBluetoothDeviceManager,
+ null /* route mgr not needed here */);
mBluetoothDeviceManager.setHeadsetServiceForTesting(mHeadsetProxy);
}
diff --git a/tests/src/com/android/server/telecom/tests/CallAudioManagerTest.java b/tests/src/com/android/server/telecom/tests/CallAudioManagerTest.java
index 78f7b50..5e23dcc 100644
--- a/tests/src/com/android/server/telecom/tests/CallAudioManagerTest.java
+++ b/tests/src/com/android/server/telecom/tests/CallAudioManagerTest.java
@@ -31,6 +31,7 @@
import com.android.server.telecom.InCallTonePlayer;
import com.android.server.telecom.RingbackPlayer;
import com.android.server.telecom.Ringer;
+import com.android.server.telecom.bluetooth.BluetoothStateReceiver;
import org.junit.Before;
import org.junit.Test;
@@ -64,6 +65,7 @@
@Mock private Ringer mRinger;
@Mock private RingbackPlayer mRingbackPlayer;
@Mock private DtmfLocalTonePlayer mDtmfLocalTonePlayer;
+ @Mock private BluetoothStateReceiver mBluetoothStateReceiver;
private CallAudioManager mCallAudioManager;
@@ -86,6 +88,7 @@
mPlayerFactory,
mRinger,
mRingbackPlayer,
+ mBluetoothStateReceiver,
mDtmfLocalTonePlayer);
}
diff --git a/tests/src/com/android/server/telecom/tests/CallsManagerTest.java b/tests/src/com/android/server/telecom/tests/CallsManagerTest.java
index d3efa99..6bba7af 100644
--- a/tests/src/com/android/server/telecom/tests/CallsManagerTest.java
+++ b/tests/src/com/android/server/telecom/tests/CallsManagerTest.java
@@ -72,6 +72,7 @@
import com.android.server.telecom.Timeouts;
import com.android.server.telecom.WiredHeadsetManager;
import com.android.server.telecom.bluetooth.BluetoothRouteManager;
+import com.android.server.telecom.bluetooth.BluetoothStateReceiver;
import org.junit.Before;
import org.junit.Test;
@@ -140,6 +141,7 @@
@Mock private InCallControllerFactory mInCallControllerFactory;
@Mock private InCallController mInCallController;
@Mock private ConnectionServiceFocusManager mConnectionSvrFocusMgr;
+ @Mock private BluetoothStateReceiver mBluetoothStateReceiver;
private CallsManager mCallsManager;
@@ -181,6 +183,7 @@
mEmergencyCallHelper,
mToneGeneratorFactory,
mClockProxy,
+ mBluetoothStateReceiver,
mInCallControllerFactory);
when(mPhoneAccountRegistrar.getPhoneAccount(