77 * in the file PATENTS. All contributing project authors may
88 * be found in the AUTHORS file in the root of the source tree.
99 */
10-
1110package com .zxcpoiu .incallmanager .AppRTC ;
12-
1311import android .annotation .SuppressLint ;
1412import android .bluetooth .BluetoothAdapter ;
1513import android .bluetooth .BluetoothDevice ;
2624import android .os .Looper ;
2725import android .os .Process ;
2826import android .util .Log ;
27+ import androidx .annotation .Nullable ;
2928import java .util .List ;
3029import java .util .Set ;
31-
30+ import com .zxcpoiu .incallmanager .AppRTC .AppRTCUtils ;
31+ import com .zxcpoiu .incallmanager .AppRTC .ThreadUtils ;
3232import com .zxcpoiu .incallmanager .InCallManagerModule ;
33-
3433/**
3534 * AppRTCProximitySensor manages functions related to Bluetoth devices in the
3635 * AppRTC demo.
3736 */
3837public class AppRTCBluetoothManager {
3938 private static final String TAG = "AppRTCBluetoothManager" ;
40-
4139 // Timeout interval for starting or stopping audio to a Bluetooth SCO device.
4240 private static final int BLUETOOTH_SCO_TIMEOUT_MS = 4000 ;
4341 // Maximum number of SCO connection attempts.
4442 private static final int MAX_SCO_CONNECTION_ATTEMPTS = 2 ;
45-
4643 // Bluetooth connection state.
4744 public enum State {
4845 // Bluetooth is not available; no adapter or Bluetooth is off.
@@ -62,20 +59,21 @@ public enum State {
6259 // Bluetooth audio SCO connection with remote device is established.
6360 SCO_CONNECTED
6461 }
65-
6662 private final Context apprtcContext ;
6763 private final InCallManagerModule apprtcAudioManager ;
64+ @ Nullable
6865 private final AudioManager audioManager ;
6966 private final Handler handler ;
70-
7167 int scoConnectionAttempts ;
7268 private State bluetoothState ;
7369 private final BluetoothProfile .ServiceListener bluetoothServiceListener ;
70+ @ Nullable
7471 private BluetoothAdapter bluetoothAdapter ;
72+ @ Nullable
7573 private BluetoothHeadset bluetoothHeadset ;
74+ @ Nullable
7675 private BluetoothDevice bluetoothDevice ;
7776 private final BroadcastReceiver bluetoothHeadsetReceiver ;
78-
7977 // Runs when the Bluetooth timeout expires. We use that timeout after calling
8078 // startScoAudio() or stopScoAudio() because we're not guaranteed to get a
8179 // callback after those calls.
@@ -85,7 +83,6 @@ public void run() {
8583 bluetoothTimeout ();
8684 }
8785 };
88-
8986 /**
9087 * Implementation of an interface that notifies BluetoothProfile IPC clients when they have been
9188 * connected to or disconnected from the service.
@@ -105,7 +102,6 @@ public void onServiceConnected(int profile, BluetoothProfile proxy) {
105102 updateAudioDeviceState ();
106103 Log .d (TAG , "onServiceConnected done: BT state=" + bluetoothState );
107104 }
108-
109105 @ Override
110106 /** Notifies the client when the proxy object has been disconnected from the service. */
111107 public void onServiceDisconnected (int profile ) {
@@ -121,7 +117,6 @@ public void onServiceDisconnected(int profile) {
121117 Log .d (TAG , "onServiceDisconnected done: BT state=" + bluetoothState );
122118 }
123119 }
124-
125120 // Intent broadcast receiver which handles changes in Bluetooth device availability.
126121 // Detects headset changes and Bluetooth SCO state changes.
127122 private class BluetoothHeadsetBroadcastReceiver extends BroadcastReceiver {
@@ -189,15 +184,14 @@ public void onReceive(Context context, Intent intent) {
189184 Log .d (TAG , "onReceive done: BT state=" + bluetoothState );
190185 }
191186 }
192-
193187 /** Construction. */
194188 public static AppRTCBluetoothManager create (Context context , InCallManagerModule audioManager ) {
195- Log .d (TAG , "create" );
189+ Log .d (TAG , "create" + AppRTCUtils . getThreadInfo () );
196190 return new AppRTCBluetoothManager (context , audioManager );
197191 }
198-
199192 protected AppRTCBluetoothManager (Context context , InCallManagerModule audioManager ) {
200193 Log .d (TAG , "ctor" );
194+ ThreadUtils .checkIsOnMainThread ();
201195 apprtcContext = context ;
202196 apprtcAudioManager = audioManager ;
203197 this .audioManager = getAudioManager (context );
@@ -206,12 +200,11 @@ protected AppRTCBluetoothManager(Context context, InCallManagerModule audioManag
206200 bluetoothHeadsetReceiver = new BluetoothHeadsetBroadcastReceiver ();
207201 handler = new Handler (Looper .getMainLooper ());
208202 }
209-
210203 /** Returns the internal state. */
211204 public State getState () {
205+ ThreadUtils .checkIsOnMainThread ();
212206 return bluetoothState ;
213207 }
214-
215208 /**
216209 * Activates components required to detect Bluetooth devices and to enable
217210 * BT SCO (audio is routed via BT SCO) for the headset profile. The end
@@ -226,6 +219,7 @@ public State getState() {
226219 * change.
227220 */
228221 public void start () {
222+ ThreadUtils .checkIsOnMainThread ();
229223 Log .d (TAG , "start" );
230224 String p = Build .VERSION .SDK_INT >= Build .VERSION_CODES .S ? android .Manifest .permission .BLUETOOTH_CONNECT : android .Manifest .permission .BLUETOOTH ;
231225 if (!hasPermission (apprtcContext , p )) {
@@ -271,9 +265,9 @@ public void start() {
271265 bluetoothState = State .HEADSET_UNAVAILABLE ;
272266 Log .d (TAG , "start done: BT state=" + bluetoothState );
273267 }
274-
275268 /** Stops and closes all components related to Bluetooth audio. */
276269 public void stop () {
270+ ThreadUtils .checkIsOnMainThread ();
277271 Log .d (TAG , "stop: BT state=" + bluetoothState );
278272 if (bluetoothAdapter == null ) {
279273 return ;
@@ -295,7 +289,6 @@ public void stop() {
295289 bluetoothState = State .UNINITIALIZED ;
296290 Log .d (TAG , "stop done: BT state=" + bluetoothState );
297291 }
298-
299292 /**
300293 * Starts Bluetooth SCO connection with remote device.
301294 * Note that the phone application always has the priority on the usage of the SCO connection
@@ -310,6 +303,7 @@ public void stop() {
310303 * accept SCO audio without a "call".
311304 */
312305 public boolean startScoAudio () {
306+ ThreadUtils .checkIsOnMainThread ();
313307 Log .d (TAG , "startSco: BT state=" + bluetoothState + ", "
314308 + "attempts: " + scoConnectionAttempts + ", "
315309 + "SCO is on: " + isScoOn ());
@@ -335,9 +329,9 @@ public boolean startScoAudio() {
335329 + "SCO is on: " + isScoOn ());
336330 return true ;
337331 }
338-
339332 /** Stops Bluetooth SCO connection with remote device. */
340333 public void stopScoAudio () {
334+ ThreadUtils .checkIsOnMainThread ();
341335 Log .d (TAG , "stopScoAudio: BT state=" + bluetoothState + ", "
342336 + "SCO is on: " + isScoOn ());
343337 if (bluetoothState != State .SCO_CONNECTING && bluetoothState != State .SCO_CONNECTED ) {
@@ -350,12 +344,11 @@ public void stopScoAudio() {
350344 Log .d (TAG , "stopScoAudio done: BT state=" + bluetoothState + ", "
351345 + "SCO is on: " + isScoOn ());
352346 }
353-
354347 /**
355348 * Use the BluetoothHeadset proxy object (controls the Bluetooth Headset
356349 * Service via IPC) to update the list of connected devices for the HEADSET
357350 * profile. The internal state will change to HEADSET_UNAVAILABLE or to
358- * HEADSET_AVAILABLE and | bluetoothDevice| will be mapped to the connected
351+ * HEADSET_AVAILABLE and ` bluetoothDevice` will be mapped to the connected
359352 * device if available.
360353 */
361354 public void updateDevice () {
@@ -382,32 +375,27 @@ public void updateDevice() {
382375 }
383376 Log .d (TAG , "updateDevice done: BT state=" + bluetoothState );
384377 }
385-
386378 /**
387379 * Stubs for test mocks.
388380 */
381+ @ Nullable
389382 protected AudioManager getAudioManager (Context context ) {
390383 return (AudioManager ) context .getSystemService (Context .AUDIO_SERVICE );
391384 }
392-
393385 protected void registerReceiver (BroadcastReceiver receiver , IntentFilter filter ) {
394386 apprtcContext .registerReceiver (receiver , filter );
395387 }
396-
397388 protected void unregisterReceiver (BroadcastReceiver receiver ) {
398389 apprtcContext .unregisterReceiver (receiver );
399390 }
400-
401391 protected boolean getBluetoothProfileProxy (
402392 Context context , BluetoothProfile .ServiceListener listener , int profile ) {
403393 return bluetoothAdapter .getProfileProxy (context , listener , profile );
404394 }
405-
406395 protected boolean hasPermission (Context context , String permission ) {
407396 return apprtcContext .checkPermission (permission , Process .myPid (), Process .myUid ())
408397 == PackageManager .PERMISSION_GRANTED ;
409398 }
410-
411399 /** Logs the state of the local Bluetooth adapter. */
412400 @ SuppressLint ("HardwareIds" )
413401 protected void logBluetoothAdapterInfo (BluetoothAdapter localAdapter ) {
@@ -425,30 +413,30 @@ protected void logBluetoothAdapterInfo(BluetoothAdapter localAdapter) {
425413 }
426414 }
427415 }
428-
429416 /** Ensures that the audio manager updates its list of available audio devices. */
430417 private void updateAudioDeviceState () {
418+ ThreadUtils .checkIsOnMainThread ();
431419 Log .d (TAG , "updateAudioDeviceState" );
432420 apprtcAudioManager .updateAudioDeviceState ();
433421 }
434-
435422 /** Starts timer which times out after BLUETOOTH_SCO_TIMEOUT_MS milliseconds. */
436423 private void startTimer () {
424+ ThreadUtils .checkIsOnMainThread ();
437425 Log .d (TAG , "startTimer" );
438426 handler .postDelayed (bluetoothTimeoutRunnable , BLUETOOTH_SCO_TIMEOUT_MS );
439427 }
440-
441428 /** Cancels any outstanding timer tasks. */
442429 private void cancelTimer () {
430+ ThreadUtils .checkIsOnMainThread ();
443431 Log .d (TAG , "cancelTimer" );
444432 handler .removeCallbacks (bluetoothTimeoutRunnable );
445433 }
446-
447434 /**
448435 * Called when start of the BT SCO channel takes too long time. Usually
449436 * happens when the BT device has been turned on during an ongoing call.
450437 */
451438 private void bluetoothTimeout () {
439+ ThreadUtils .checkIsOnMainThread ();
452440 if (bluetoothState == State .UNINITIALIZED || bluetoothHeadset == null ) {
453441 return ;
454442 }
@@ -482,12 +470,10 @@ private void bluetoothTimeout() {
482470 updateAudioDeviceState ();
483471 Log .d (TAG , "bluetoothTimeout done: BT state=" + bluetoothState );
484472 }
485-
486473 /** Checks whether audio uses Bluetooth SCO. */
487474 private boolean isScoOn () {
488475 return audioManager .isBluetoothScoOn ();
489476 }
490-
491477 /** Converts BluetoothAdapter states into local string representations. */
492478 private String stateToString (int state ) {
493479 switch (state ) {
0 commit comments