From 0f1c1e44faf12403ea568f52599655bf32b89f2c Mon Sep 17 00:00:00 2001 From: Arseniy Borisov Date: Mon, 30 Jan 2017 23:33:51 +0300 Subject: [PATCH 1/4] observe bluetooth headset state --- .../utils/audio/HeadsetStateObserver.java | 33 ++++++++++++++----- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/src/main/java/ru/touchin/roboswag/components/utils/audio/HeadsetStateObserver.java b/src/main/java/ru/touchin/roboswag/components/utils/audio/HeadsetStateObserver.java index d17066e..69b4b71 100644 --- a/src/main/java/ru/touchin/roboswag/components/utils/audio/HeadsetStateObserver.java +++ b/src/main/java/ru/touchin/roboswag/components/utils/audio/HeadsetStateObserver.java @@ -19,6 +19,7 @@ package ru.touchin.roboswag.components.utils.audio; +import android.bluetooth.BluetoothA2dp; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; @@ -31,7 +32,8 @@ import rx.subjects.PublishSubject; /** * Created by Gavriil Sitnikov on 02/11/2015. - * Simple observer of wired headset state (plugged in or not). + * Simple observer of wired and wireless (bluetooth A2DP) headsets state (plugged in or not). + *
You require android.permission.BLUETOOTH if want to observe wireless headset state */ public final class HeadsetStateObserver { @@ -50,24 +52,28 @@ public final class HeadsetStateObserver { .switchMap(isPluggedInReceiver -> Observable .just(isPluggedIn()) .concatWith(isPluggedInReceiver.isPluggedInChangedEvent - .doOnSubscribe(() -> context.registerReceiver(isPluggedInReceiver, new IntentFilter(Intent.ACTION_HEADSET_PLUG))) + .doOnSubscribe(() -> { + final IntentFilter headsetStateIntentFilter = new IntentFilter(Intent.ACTION_HEADSET_PLUG); + headsetStateIntentFilter.addAction(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED); + context.registerReceiver(isPluggedInReceiver, headsetStateIntentFilter); + }) .doOnUnsubscribe(() -> context.unregisterReceiver(isPluggedInReceiver)))) .replay(1) .refCount(); } /** - * Returns if wired headset plugged in. + * Returns if wired or wireless headset plugged in. * * @return True if headset is plugged in. */ @SuppressWarnings("deprecation") public boolean isPluggedIn() { - return audioManager.isWiredHeadsetOn(); + return audioManager.isWiredHeadsetOn() || audioManager.isBluetoothA2dpOn(); } /** - * Observes plugged in state of wired headset. + * Observes plugged in state of headset. * * @return Returns observable which will provide current plugged in state and any of it's udpdate. */ @@ -84,10 +90,19 @@ public final class HeadsetStateObserver { @Override public void onReceive(final Context context, final Intent intent) { if (Intent.ACTION_HEADSET_PLUG.equals(intent.getAction())) { - if (intent.getExtras() == null) { - isPluggedInChangedEvent.onNext(false); - } else { - isPluggedInChangedEvent.onNext(intent.getExtras().getInt("state") != 0); + isPluggedInChangedEvent.onNext(intent.getIntExtra("state", 0) != 0); + } + if (BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED.equals(intent.getAction())) { + final int bluetoothState = intent.getIntExtra(BluetoothA2dp.EXTRA_STATE, BluetoothA2dp.STATE_DISCONNECTED); + switch (bluetoothState) { + case BluetoothA2dp.STATE_DISCONNECTED: + isPluggedInChangedEvent.onNext(false); + break; + case BluetoothA2dp.STATE_CONNECTED: + isPluggedInChangedEvent.onNext(true); + break; + default: + break; } } } From fa14b2f55984ea1d24b6f29e9c14c48e18b1b77c Mon Sep 17 00:00:00 2001 From: Arseniy Borisov Date: Tue, 31 Jan 2017 01:46:03 +0300 Subject: [PATCH 2/4] minSdkVersion 11 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 00f7e22..b134c60 100644 --- a/build.gradle +++ b/build.gradle @@ -11,7 +11,7 @@ android { } defaultConfig { - minSdkVersion 9 + minSdkVersion 11 targetSdkVersion 24 } } From 523c8817463d8098232c846fcc52a4ff2b169863 Mon Sep 17 00:00:00 2001 From: Arseniy Borisov Date: Tue, 31 Jan 2017 18:03:59 +0300 Subject: [PATCH 3/4] follow comments --- build.gradle | 2 +- .../utils/audio/HeadsetStateObserver.java | 60 ++++++++++--------- 2 files changed, 32 insertions(+), 30 deletions(-) diff --git a/build.gradle b/build.gradle index b134c60..00f7e22 100644 --- a/build.gradle +++ b/build.gradle @@ -11,7 +11,7 @@ android { } defaultConfig { - minSdkVersion 11 + minSdkVersion 9 targetSdkVersion 24 } } diff --git a/src/main/java/ru/touchin/roboswag/components/utils/audio/HeadsetStateObserver.java b/src/main/java/ru/touchin/roboswag/components/utils/audio/HeadsetStateObserver.java index 69b4b71..c1928e5 100644 --- a/src/main/java/ru/touchin/roboswag/components/utils/audio/HeadsetStateObserver.java +++ b/src/main/java/ru/touchin/roboswag/components/utils/audio/HeadsetStateObserver.java @@ -28,12 +28,12 @@ import android.media.AudioManager; import android.support.annotation.NonNull; import rx.Observable; -import rx.subjects.PublishSubject; +import rx.subjects.BehaviorSubject; /** * Created by Gavriil Sitnikov on 02/11/2015. - * Simple observer of wired and wireless (bluetooth A2DP) headsets state (plugged in or not). - *
You require android.permission.BLUETOOTH if want to observe wireless headset state + * Simple observer of wired or wireless (bluetooth A2DP) headsets state (plugged in or not). + *
You require android.permission.BLUETOOTH and API level >= 11 if want to observe wireless headset state */ public final class HeadsetStateObserver { @@ -46,32 +46,25 @@ public final class HeadsetStateObserver { audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); isPluggedInObservable = Observable .create(subscriber -> { - subscriber.onNext(new IsPluggedInReceiver()); + subscriber.onNext(new IsPluggedInReceiver(audioManager)); subscriber.onCompleted(); }) - .switchMap(isPluggedInReceiver -> Observable - .just(isPluggedIn()) - .concatWith(isPluggedInReceiver.isPluggedInChangedEvent - .doOnSubscribe(() -> { - final IntentFilter headsetStateIntentFilter = new IntentFilter(Intent.ACTION_HEADSET_PLUG); - headsetStateIntentFilter.addAction(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED); - context.registerReceiver(isPluggedInReceiver, headsetStateIntentFilter); - }) - .doOnUnsubscribe(() -> context.unregisterReceiver(isPluggedInReceiver)))) + .switchMap(isPluggedInReceiver -> Observable.combineLatest(isPluggedInReceiver.isWiredPluggedInChangedEvent, + isPluggedInReceiver.isWirelessPluggedInChangedEvent, + (isWiredPluggedIn, isWirelessPluggedIn) -> isWiredPluggedIn || isWirelessPluggedIn) + .distinctUntilChanged() + .doOnSubscribe(() -> { + final IntentFilter headsetStateIntentFilter = new IntentFilter(Intent.ACTION_HEADSET_PLUG); + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB) { + headsetStateIntentFilter.addAction(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED); + } + context.registerReceiver(isPluggedInReceiver, headsetStateIntentFilter); + }) + .doOnUnsubscribe(() -> context.unregisterReceiver(isPluggedInReceiver))) .replay(1) .refCount(); } - /** - * Returns if wired or wireless headset plugged in. - * - * @return True if headset is plugged in. - */ - @SuppressWarnings("deprecation") - public boolean isPluggedIn() { - return audioManager.isWiredHeadsetOn() || audioManager.isBluetoothA2dpOn(); - } - /** * Observes plugged in state of headset. * @@ -85,21 +78,30 @@ public final class HeadsetStateObserver { private static class IsPluggedInReceiver extends BroadcastReceiver { @NonNull - private final PublishSubject isPluggedInChangedEvent = PublishSubject.create(); + private final BehaviorSubject isWiredPluggedInChangedEvent; + @NonNull + private final BehaviorSubject isWirelessPluggedInChangedEvent; + + @SuppressWarnings("deprecation") + public IsPluggedInReceiver(@NonNull final AudioManager audioManager) { + isWiredPluggedInChangedEvent = BehaviorSubject.create(audioManager.isWiredHeadsetOn()); + isWirelessPluggedInChangedEvent = BehaviorSubject.create(audioManager.isBluetoothA2dpOn()); + } @Override public void onReceive(final Context context, final Intent intent) { - if (Intent.ACTION_HEADSET_PLUG.equals(intent.getAction())) { - isPluggedInChangedEvent.onNext(intent.getIntExtra("state", 0) != 0); + if (Intent.ACTION_HEADSET_PLUG.equals(intent.getAction()) && !isInitialStickyBroadcast()) { + isWiredPluggedInChangedEvent.onNext(intent.getIntExtra("state", 0) != 0); } - if (BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED.equals(intent.getAction())) { + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB && + BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED.equals(intent.getAction())) { final int bluetoothState = intent.getIntExtra(BluetoothA2dp.EXTRA_STATE, BluetoothA2dp.STATE_DISCONNECTED); switch (bluetoothState) { case BluetoothA2dp.STATE_DISCONNECTED: - isPluggedInChangedEvent.onNext(false); + isWirelessPluggedInChangedEvent.onNext(false); break; case BluetoothA2dp.STATE_CONNECTED: - isPluggedInChangedEvent.onNext(true); + isWirelessPluggedInChangedEvent.onNext(true); break; default: break; From 0b01d3d66ac08a11a7c5a1467f1fff010ba459c4 Mon Sep 17 00:00:00 2001 From: Arseniy Borisov Date: Wed, 1 Feb 2017 13:47:30 +0300 Subject: [PATCH 4/4] rename isPlugged -> isConnected --- .../utils/audio/HeadsetStateObserver.java | 58 +++++++++++-------- 1 file changed, 34 insertions(+), 24 deletions(-) diff --git a/src/main/java/ru/touchin/roboswag/components/utils/audio/HeadsetStateObserver.java b/src/main/java/ru/touchin/roboswag/components/utils/audio/HeadsetStateObserver.java index c1928e5..69ebcb1 100644 --- a/src/main/java/ru/touchin/roboswag/components/utils/audio/HeadsetStateObserver.java +++ b/src/main/java/ru/touchin/roboswag/components/utils/audio/HeadsetStateObserver.java @@ -32,7 +32,7 @@ import rx.subjects.BehaviorSubject; /** * Created by Gavriil Sitnikov on 02/11/2015. - * Simple observer of wired or wireless (bluetooth A2DP) headsets state (plugged in or not). + * Simple observer of wired or wireless (bluetooth A2DP) headsets state (connected or not). *
You require android.permission.BLUETOOTH and API level >= 11 if want to observe wireless headset state */ public final class HeadsetStateObserver { @@ -40,68 +40,78 @@ public final class HeadsetStateObserver { @NonNull private final AudioManager audioManager; @NonNull - private final Observable isPluggedInObservable; + private final Observable isConnectedObservable; public HeadsetStateObserver(@NonNull final Context context) { audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); - isPluggedInObservable = Observable - .create(subscriber -> { - subscriber.onNext(new IsPluggedInReceiver(audioManager)); + isConnectedObservable = Observable + .create(subscriber -> { + subscriber.onNext(new IsConnectedReceiver(audioManager)); subscriber.onCompleted(); }) - .switchMap(isPluggedInReceiver -> Observable.combineLatest(isPluggedInReceiver.isWiredPluggedInChangedEvent, - isPluggedInReceiver.isWirelessPluggedInChangedEvent, - (isWiredPluggedIn, isWirelessPluggedIn) -> isWiredPluggedIn || isWirelessPluggedIn) + .switchMap(isConnectedReceiver -> Observable.combineLatest(isConnectedReceiver.isWiredConnectedChangedEvent, + isConnectedReceiver.isWirelessConnectedChangedEvent, + (isWiredConnected, isWirelessConnected) -> isWiredConnected || isWirelessConnected) .distinctUntilChanged() .doOnSubscribe(() -> { final IntentFilter headsetStateIntentFilter = new IntentFilter(Intent.ACTION_HEADSET_PLUG); if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB) { headsetStateIntentFilter.addAction(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED); } - context.registerReceiver(isPluggedInReceiver, headsetStateIntentFilter); + context.registerReceiver(isConnectedReceiver, headsetStateIntentFilter); }) - .doOnUnsubscribe(() -> context.unregisterReceiver(isPluggedInReceiver))) + .doOnUnsubscribe(() -> context.unregisterReceiver(isConnectedReceiver))) .replay(1) .refCount(); } /** - * Observes plugged in state of headset. + * Returns if wired or wireless headset is connected. * - * @return Returns observable which will provide current plugged in state and any of it's udpdate. + * @return True if headset is connected. */ - @NonNull - public Observable observeIsPluggedIn() { - return isPluggedInObservable; + @SuppressWarnings("deprecation") + public boolean isConnected() { + return audioManager.isWiredHeadsetOn() || audioManager.isBluetoothA2dpOn(); } - private static class IsPluggedInReceiver extends BroadcastReceiver { + /** + * Observes connection state of headset. + * + * @return Returns observable which will provide current connection state and any of it's udpdate. + */ + @NonNull + public Observable observeIsConnected() { + return isConnectedObservable; + } + + private static class IsConnectedReceiver extends BroadcastReceiver { @NonNull - private final BehaviorSubject isWiredPluggedInChangedEvent; + private final BehaviorSubject isWiredConnectedChangedEvent; @NonNull - private final BehaviorSubject isWirelessPluggedInChangedEvent; + private final BehaviorSubject isWirelessConnectedChangedEvent; @SuppressWarnings("deprecation") - public IsPluggedInReceiver(@NonNull final AudioManager audioManager) { - isWiredPluggedInChangedEvent = BehaviorSubject.create(audioManager.isWiredHeadsetOn()); - isWirelessPluggedInChangedEvent = BehaviorSubject.create(audioManager.isBluetoothA2dpOn()); + public IsConnectedReceiver(@NonNull final AudioManager audioManager) { + isWiredConnectedChangedEvent = BehaviorSubject.create(audioManager.isWiredHeadsetOn()); + isWirelessConnectedChangedEvent = BehaviorSubject.create(audioManager.isBluetoothA2dpOn()); } @Override public void onReceive(final Context context, final Intent intent) { if (Intent.ACTION_HEADSET_PLUG.equals(intent.getAction()) && !isInitialStickyBroadcast()) { - isWiredPluggedInChangedEvent.onNext(intent.getIntExtra("state", 0) != 0); + isWiredConnectedChangedEvent.onNext(intent.getIntExtra("state", 0) != 0); } if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB && BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED.equals(intent.getAction())) { final int bluetoothState = intent.getIntExtra(BluetoothA2dp.EXTRA_STATE, BluetoothA2dp.STATE_DISCONNECTED); switch (bluetoothState) { case BluetoothA2dp.STATE_DISCONNECTED: - isWirelessPluggedInChangedEvent.onNext(false); + isWirelessConnectedChangedEvent.onNext(false); break; case BluetoothA2dp.STATE_CONNECTED: - isWirelessPluggedInChangedEvent.onNext(true); + isWirelessConnectedChangedEvent.onNext(true); break; default: break;