Loading src/com/android/server/telecom/BluetoothManager.java +34 −11 Original line number Original line Diff line number Diff line Loading @@ -16,7 +16,6 @@ package com.android.server.telecom; package com.android.server.telecom; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothHeadset; import android.bluetooth.BluetoothHeadset; import android.bluetooth.BluetoothProfile; import android.bluetooth.BluetoothProfile; Loading @@ -32,7 +31,6 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.IndentingPrintWriter; import java.util.List; import java.util.List; import java.util.concurrent.ThreadPoolExecutor; /** /** * Listens to and caches bluetooth headset state. Used By the CallAudioManager for maintaining * Listens to and caches bluetooth headset state. Used By the CallAudioManager for maintaining Loading Loading @@ -94,18 +92,21 @@ public class BluetoothManager { if (action.equals(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED)) { if (action.equals(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED)) { int bluetoothHeadsetState = intent.getIntExtra(BluetoothHeadset.EXTRA_STATE, int bluetoothHeadsetState = intent.getIntExtra(BluetoothHeadset.EXTRA_STATE, BluetoothHeadset.STATE_DISCONNECTED); BluetoothHeadset.STATE_DISCONNECTED); Log.d(this, "mReceiver: HEADSET_STATE_CHANGED_ACTION"); Log.i(this, "mReceiver: HEADSET_STATE_CHANGED_ACTION"); Log.d(this, "==> new state: %s ", bluetoothHeadsetState); Log.i(this, "==> new state: %s ", bluetoothHeadsetState); updateListenerOfBluetoothState( updateListenerOfBluetoothState( bluetoothHeadsetState == BluetoothHeadset.STATE_CONNECTING); bluetoothHeadsetState == BluetoothHeadset.STATE_CONNECTING); } else if (action.equals(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED)) { } else if (action.equals(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED)) { int bluetoothHeadsetAudioState = int bluetoothHeadsetAudioState = intent.getIntExtra(BluetoothHeadset.EXTRA_STATE, intent.getIntExtra(BluetoothHeadset.EXTRA_STATE, BluetoothHeadset.STATE_AUDIO_DISCONNECTED); BluetoothHeadset.STATE_AUDIO_DISCONNECTED); Log.d(this, "mReceiver: HEADSET_AUDIO_STATE_CHANGED_ACTION"); Log.i(this, "mReceiver: HEADSET_AUDIO_STATE_CHANGED_ACTION"); Log.d(this, "==> new state: %s", bluetoothHeadsetAudioState); Log.i(this, "==> new state: %s", bluetoothHeadsetAudioState); updateListenerOfBluetoothState( updateListenerOfBluetoothState( bluetoothHeadsetAudioState == BluetoothHeadset.STATE_AUDIO_CONNECTING); bluetoothHeadsetAudioState == BluetoothHeadset.STATE_AUDIO_CONNECTING || bluetoothHeadsetAudioState == BluetoothHeadset.STATE_AUDIO_CONNECTED); } } } finally { } finally { Log.endSession(); Log.endSession(); Loading @@ -130,6 +131,19 @@ public class BluetoothManager { updateListenerOfBluetoothState(false); updateListenerOfBluetoothState(false); } } }; }; private final Runnable mRetryConnectAudio = new Runnable("BM.rCA") { @Override public void loggedRun() { Log.i(this, "Retrying connecting to bluetooth audio."); if (!mBluetoothHeadset.connectAudio()) { Log.w(this, "Retry of bluetooth audio connection failed. Giving up."); } else { setBluetoothStatePending(); } } }; private final Context mContext; private final Context mContext; private int mBluetoothState = BLUETOOTH_UNINITIALIZED; private int mBluetoothState = BLUETOOTH_UNINITIALIZED; Loading Loading @@ -294,12 +308,21 @@ public class BluetoothManager { public void connectBluetoothAudio() { public void connectBluetoothAudio() { Log.v(this, "connectBluetoothAudio()..."); Log.v(this, "connectBluetoothAudio()..."); if (mBluetoothHeadset != null) { if (mBluetoothHeadset != null) { mBluetoothHeadset.connectAudio(); if (!mBluetoothHeadset.connectAudio()) { mHandler.postDelayed(mRetryConnectAudio.prepare(), Timeouts.getRetryBluetoothConnectAudioBackoffMillis( mContext.getContentResolver())); } } // The call to connectAudio is asynchronous and may take some time to complete. However, // if connectAudio() returns false, we know that it has failed and therefore will // schedule a retry to happen some time later. We set bluetooth state to pending now and // show bluetooth as connected in the UI, but confirmation that we are connected will // arrive through mReceiver. setBluetoothStatePending(); } } // Watch out: The bluetooth connection doesn't happen instantly; private void setBluetoothStatePending() { // the connectAudio() call returns instantly but does its real // work in another thread. mBluetoothState = BLUETOOTH_AUDIO_PENDING; mBluetoothState = BLUETOOTH_AUDIO_PENDING; mBluetoothConnectionRequestTime = SystemClock.elapsedRealtime(); mBluetoothConnectionRequestTime = SystemClock.elapsedRealtime(); mHandler.removeCallbacks(mBluetoothConnectionTimeout.getRunnableToCancel()); mHandler.removeCallbacks(mBluetoothConnectionTimeout.getRunnableToCancel()); Loading src/com/android/server/telecom/Timeouts.java +9 −0 Original line number Original line Diff line number Diff line Loading @@ -108,6 +108,15 @@ public final class Timeouts { return get(contentResolver, "bluetooth_pending_timeout_millis", 5000L); return get(contentResolver, "bluetooth_pending_timeout_millis", 5000L); } } /** * Returns the amount of time to wait before retrying the connectAudio call. This is * necessary to account for the HeadsetStateMachine sometimes not being ready when we want to * connect to bluetooth audio immediately after a device connects. */ public static long getRetryBluetoothConnectAudioBackoffMillis(ContentResolver contentResolver) { return get(contentResolver, "retry_bluetooth_connect_audio_backoff_millis", 500L); } /** /** * Returns the amount of time after a Logging session has been started that Telecom is set to * Returns the amount of time after a Logging session has been started that Telecom is set to * perform a sweep to check and make sure that the session is still not incomplete (stale). * perform a sweep to check and make sure that the session is still not incomplete (stale). Loading Loading
src/com/android/server/telecom/BluetoothManager.java +34 −11 Original line number Original line Diff line number Diff line Loading @@ -16,7 +16,6 @@ package com.android.server.telecom; package com.android.server.telecom; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothHeadset; import android.bluetooth.BluetoothHeadset; import android.bluetooth.BluetoothProfile; import android.bluetooth.BluetoothProfile; Loading @@ -32,7 +31,6 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.IndentingPrintWriter; import java.util.List; import java.util.List; import java.util.concurrent.ThreadPoolExecutor; /** /** * Listens to and caches bluetooth headset state. Used By the CallAudioManager for maintaining * Listens to and caches bluetooth headset state. Used By the CallAudioManager for maintaining Loading Loading @@ -94,18 +92,21 @@ public class BluetoothManager { if (action.equals(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED)) { if (action.equals(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED)) { int bluetoothHeadsetState = intent.getIntExtra(BluetoothHeadset.EXTRA_STATE, int bluetoothHeadsetState = intent.getIntExtra(BluetoothHeadset.EXTRA_STATE, BluetoothHeadset.STATE_DISCONNECTED); BluetoothHeadset.STATE_DISCONNECTED); Log.d(this, "mReceiver: HEADSET_STATE_CHANGED_ACTION"); Log.i(this, "mReceiver: HEADSET_STATE_CHANGED_ACTION"); Log.d(this, "==> new state: %s ", bluetoothHeadsetState); Log.i(this, "==> new state: %s ", bluetoothHeadsetState); updateListenerOfBluetoothState( updateListenerOfBluetoothState( bluetoothHeadsetState == BluetoothHeadset.STATE_CONNECTING); bluetoothHeadsetState == BluetoothHeadset.STATE_CONNECTING); } else if (action.equals(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED)) { } else if (action.equals(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED)) { int bluetoothHeadsetAudioState = int bluetoothHeadsetAudioState = intent.getIntExtra(BluetoothHeadset.EXTRA_STATE, intent.getIntExtra(BluetoothHeadset.EXTRA_STATE, BluetoothHeadset.STATE_AUDIO_DISCONNECTED); BluetoothHeadset.STATE_AUDIO_DISCONNECTED); Log.d(this, "mReceiver: HEADSET_AUDIO_STATE_CHANGED_ACTION"); Log.i(this, "mReceiver: HEADSET_AUDIO_STATE_CHANGED_ACTION"); Log.d(this, "==> new state: %s", bluetoothHeadsetAudioState); Log.i(this, "==> new state: %s", bluetoothHeadsetAudioState); updateListenerOfBluetoothState( updateListenerOfBluetoothState( bluetoothHeadsetAudioState == BluetoothHeadset.STATE_AUDIO_CONNECTING); bluetoothHeadsetAudioState == BluetoothHeadset.STATE_AUDIO_CONNECTING || bluetoothHeadsetAudioState == BluetoothHeadset.STATE_AUDIO_CONNECTED); } } } finally { } finally { Log.endSession(); Log.endSession(); Loading @@ -130,6 +131,19 @@ public class BluetoothManager { updateListenerOfBluetoothState(false); updateListenerOfBluetoothState(false); } } }; }; private final Runnable mRetryConnectAudio = new Runnable("BM.rCA") { @Override public void loggedRun() { Log.i(this, "Retrying connecting to bluetooth audio."); if (!mBluetoothHeadset.connectAudio()) { Log.w(this, "Retry of bluetooth audio connection failed. Giving up."); } else { setBluetoothStatePending(); } } }; private final Context mContext; private final Context mContext; private int mBluetoothState = BLUETOOTH_UNINITIALIZED; private int mBluetoothState = BLUETOOTH_UNINITIALIZED; Loading Loading @@ -294,12 +308,21 @@ public class BluetoothManager { public void connectBluetoothAudio() { public void connectBluetoothAudio() { Log.v(this, "connectBluetoothAudio()..."); Log.v(this, "connectBluetoothAudio()..."); if (mBluetoothHeadset != null) { if (mBluetoothHeadset != null) { mBluetoothHeadset.connectAudio(); if (!mBluetoothHeadset.connectAudio()) { mHandler.postDelayed(mRetryConnectAudio.prepare(), Timeouts.getRetryBluetoothConnectAudioBackoffMillis( mContext.getContentResolver())); } } // The call to connectAudio is asynchronous and may take some time to complete. However, // if connectAudio() returns false, we know that it has failed and therefore will // schedule a retry to happen some time later. We set bluetooth state to pending now and // show bluetooth as connected in the UI, but confirmation that we are connected will // arrive through mReceiver. setBluetoothStatePending(); } } // Watch out: The bluetooth connection doesn't happen instantly; private void setBluetoothStatePending() { // the connectAudio() call returns instantly but does its real // work in another thread. mBluetoothState = BLUETOOTH_AUDIO_PENDING; mBluetoothState = BLUETOOTH_AUDIO_PENDING; mBluetoothConnectionRequestTime = SystemClock.elapsedRealtime(); mBluetoothConnectionRequestTime = SystemClock.elapsedRealtime(); mHandler.removeCallbacks(mBluetoothConnectionTimeout.getRunnableToCancel()); mHandler.removeCallbacks(mBluetoothConnectionTimeout.getRunnableToCancel()); Loading
src/com/android/server/telecom/Timeouts.java +9 −0 Original line number Original line Diff line number Diff line Loading @@ -108,6 +108,15 @@ public final class Timeouts { return get(contentResolver, "bluetooth_pending_timeout_millis", 5000L); return get(contentResolver, "bluetooth_pending_timeout_millis", 5000L); } } /** * Returns the amount of time to wait before retrying the connectAudio call. This is * necessary to account for the HeadsetStateMachine sometimes not being ready when we want to * connect to bluetooth audio immediately after a device connects. */ public static long getRetryBluetoothConnectAudioBackoffMillis(ContentResolver contentResolver) { return get(contentResolver, "retry_bluetooth_connect_audio_backoff_millis", 500L); } /** /** * Returns the amount of time after a Logging session has been started that Telecom is set to * Returns the amount of time after a Logging session has been started that Telecom is set to * perform a sweep to check and make sure that the session is still not incomplete (stale). * perform a sweep to check and make sure that the session is still not incomplete (stale). Loading