当前位置:   article > 正文

关于Android 11检测当前是否处于耳机或者蓝牙状态_android 判断当前是否连接耳机

android 判断当前是否连接耳机

  这个博客纯属相当于记笔记,因为自己也是刚接触Android 领域不久,很多东西的都慢慢学然后边慢慢在项目上应用。

  不过虽然不是完全研发的哪种领域,至少业务逻辑以及大部分业务需求还是能完成的,好了废话不多说,关于Android 11的检测当前是否处于耳机或者蓝牙状态的,我是怎么实现的(这玩意挺容易的),代码以及逻辑有不好的地方欢迎大家进行改进或者积极提出意见。

场景:客户提出搭建一个调音台的功能,要求在设备上可以检测到当前处于什么样的音频输出(ps这个其实我很不理解,本身设备不就是可以自己切换嘛!)

环境:

compileSdkVersion 29
buildToolsVersion "29.0.3"
classpath "com.android.tools.build:gradle:4.2.2"

本来我自己电脑版本都是最新的,没办法适应公司的版本只能改成一样的了,不然怕有什么问题,其实也没什么问题bushi

原理:其实原来很简单,我在查阅了Android 官方文档,在断开蓝牙连接以及连接上蓝牙都会发出一个广播,其实只要自己接收到这个广播就可以了,然后根据这个广播再来操作自己想要的东西,至于耳机也一样都是发出一个广播,我粗略看过那个蓝牙以及耳机的流程,这个请求通常会被传递给AudioService.java,它是Android音频服务的核心组件,负责管理音频设备和流的路由。
HAL层:
AudioService接收到请求后,会通过AudioFlinger与音频硬件抽象层(HAL)进行通信。
HAL层是操作系统内核空间与硬件驱动程序之间的接口,对于蓝牙音频来说,对应的是蓝牙音频HAL(如audio_policy_hal.c、a2dp_hw.c等)。
硬件驱动层:
蓝牙音频HAL会进一步处理这个请求,将其转换为相应的控制命令,并通过蓝牙协议栈向蓝牙控制器发送指令。
指令内容可能是设置当前蓝牙音频输出设备的状态为启用A2DP模式。
蓝牙控制器与蓝牙设备:
蓝牙控制器接收到指令后,会与已连接的蓝牙A2DP设备协商并调整音频传输方式,使其能够开始接收立体声音乐或音频信号。
反馈机制:
当操作完成后,框架层可能会收到一个确认回调,表示状态更改已经完成或成功,然后更新内部状态信息。。。。

emmm至于怎么回来的细节我不知道,只是知道有这么个事儿。

哦对了,原谅我废话多,因为我写的详细,我到时候我自己翻起来也容易看我自己写的黄金(shishan)代码。

废话不多说贴上代码:

  1. public class AudioDeviceHelper {
  2. private Context context;
  3. private AudioManager audioManager;
  4. private BluetoothAdapter bluetoothAdapter;
  5. private List<AudioDeviceObserver> observers = new ArrayList<>();
  6. private Timer timer;
  7. public AudioDeviceHelper(Context context) {
  8. this.context = context;
  9. this.bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
  10. this.audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
  11. // 注册监听耳机插入拔出的BroadcastReceiver
  12. IntentFilter headsetFilter = new IntentFilter(Intent.ACTION_HEADSET_PLUG);
  13. context.registerReceiver(headsetPlugReceiver, headsetFilter);
  14. // 注册监听蓝牙连接状态的BroadcastReceiver
  15. IntentFilter bluetoothFilter = new IntentFilter();
  16. bluetoothFilter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
  17. bluetoothFilter.addAction(BluetoothDevice.ACTION_ACL_CONNECTED);
  18. bluetoothFilter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED);
  19. context.registerReceiver(bluetoothConnectionReceiver, bluetoothFilter);
  20. //-------
  21. IntentFilter volumeIntentFilter = new IntentFilter("android.media.VOLUME_CHANGED_ACTION");
  22. context.registerReceiver(VolumeReceiver, volumeIntentFilter);
  23. }
  24. // 定义观察者接口
  25. public interface AudioDeviceObserver {
  26. void onHeadsetPluggedStateChange(boolean isPluggedIn);
  27. void onBluetoothConnectionStateChange(boolean isConnected);
  28. void onVolumeChanged(int currentVolume);
  29. }
  30. // 添加观察者
  31. public void addObserver(AudioDeviceObserver observer) {
  32. observers.add(observer);
  33. }
  34. // 移除观察者
  35. public void removeObserver(AudioDeviceObserver observer) {
  36. observers.remove(observer);
  37. }
  38. // 耳机插拔广播接收器
  39. private BroadcastReceiver headsetPlugReceiver = new BroadcastReceiver() {
  40. @Override
  41. public void onReceive(Context context, Intent intent) {
  42. boolean isHeadsetPluggedIn = audioManager.isWiredHeadsetOn();
  43. notifyHeadsetPluggedStateChange(isHeadsetPluggedIn);
  44. }
  45. };
  46. // 蓝牙连接状态广播接收器
  47. private BroadcastReceiver bluetoothConnectionReceiver = new BroadcastReceiver() {
  48. @Override
  49. public void onReceive(Context context, Intent intent) {
  50. String action = intent.getAction();
  51. if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED)) {
  52. int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR);
  53. handleBluetoothAdapterStateChange(state);
  54. LogUtils.e("1--监听蓝牙状态");
  55. } else if (action.equals(BluetoothDevice.ACTION_ACL_CONNECTED)) {
  56. BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
  57. LogUtils.e("2--设备连接 判断设备是否是A2DP设备");
  58. time();
  59. } else if (action.equals(BluetoothDevice.ACTION_ACL_DISCONNECTED)) {
  60. BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
  61. LogUtils.e("3--设备连接断开");
  62. }
  63. }
  64. // if (intent.getAction().equals(BluetoothAdapter.ACTION_STATE_CHANGED)) {
  65. // int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR);
  66. // boolean isConnected = false;
  67. // switch (state) {
  68. // case BluetoothAdapter.STATE_CONNECTED:
  69. // case BluetoothAdapter.STATE_TURNING_ON:
  70. // LogUtils.e("蓝牙开启A");
  71. // time();
  72. // break;
  73. // case BluetoothAdapter.STATE_DISCONNECTED:
  74. // case BluetoothAdapter.STATE_TURNING_OFF:
  75. // isConnected = false;
  76. // LogUtils.e("蓝牙广播关闭:");
  77. // break;
  78. // default:
  79. //
  80. // break;
  81. // }
  82. //
  83. //
  84. // }
  85. };
  86. //音量广播控制器
  87. private BroadcastReceiver VolumeReceiver = new BroadcastReceiver() {
  88. @Override
  89. public void onReceive(Context context, Intent intent) {
  90. if (intent.getAction().equals("android.media.VOLUME_CHANGED_ACTION")) {
  91. int currentVolume = audioManager.getStreamVolume(AudioManager.STREAM_MUSIC);
  92. notifyVolumeChanged(currentVolume);
  93. }
  94. }
  95. };
  96. //蓝牙状态控制器
  97. private void handleBluetoothAdapterStateChange(int state) {
  98. switch (state) {
  99. case BluetoothAdapter.STATE_TURNING_ON:
  100. LogUtils.e("蓝牙正在开启...");
  101. break;
  102. case BluetoothAdapter.STATE_ON:
  103. // 如果您只需要在蓝牙完全开启后才进行连接状态检查,则可以在这里调用time()方法
  104. // time();
  105. break;
  106. case BluetoothAdapter.STATE_TURNING_OFF:
  107. LogUtils.e("蓝牙正在关闭...");
  108. break;
  109. case BluetoothAdapter.STATE_OFF:
  110. notifyBluetoothConnectionStateChange(false);
  111. break;
  112. default:
  113. break;
  114. }
  115. }
  116. //延时控制器
  117. private void time() {
  118. timer = new Timer();
  119. TimerTask timerTask = new TimerTask() {
  120. @Override
  121. public void run() {
  122. boolean states = isBlueTooth();
  123. LogUtils.e("A2DP状态" + states);
  124. if (states) {
  125. LogUtils.e("蓝牙广播开启A2DP已连接:");
  126. notifyBluetoothConnectionStateChange(true);
  127. } else {
  128. LogUtils.e("蓝牙广播开启A2DP未连接:");
  129. notifyBluetoothConnectionStateChange(false);
  130. }
  131. }
  132. };
  133. timer.schedule(timerTask, 1500);
  134. // timer.cancel();
  135. }
  136. // 通知观察者耳机插拔状态改变
  137. private void notifyHeadsetPluggedStateChange(boolean isPluggedIn) {
  138. for (AudioDeviceObserver observer : observers) {
  139. observer.onHeadsetPluggedStateChange(isPluggedIn);
  140. }
  141. }
  142. // 通知观察者蓝牙连接状态改变
  143. private void notifyBluetoothConnectionStateChange(boolean isConnected) {
  144. for (AudioDeviceObserver observer : observers) {
  145. observer.onBluetoothConnectionStateChange(isConnected);
  146. }
  147. }
  148. // 通知观察者音量改变
  149. private void notifyVolumeChanged(int currentVolume) {
  150. for (AudioDeviceObserver observer : observers) {
  151. observer.onVolumeChanged(currentVolume);
  152. }
  153. }
  154. // 监测是否插入了耳机(仅提供原方法,已通过广播监听实时更新)
  155. public boolean isHeadSetPluggedIn() {
  156. return audioManager.isWiredHeadsetOn();
  157. }
  158. // 判断蓝牙是否连接(仅提供原方法,已通过广播监听实时更新)
  159. public boolean isBlueTooth() {
  160. int state = bluetoothAdapter.getProfileConnectionState(BluetoothProfile.A2DP);
  161. return state == BluetoothAdapter.STATE_CONNECTED;
  162. }
  163. // 在不需要使用时,记得注销广播接收器以释放资源
  164. public void unregisterReceivers() {
  165. context.unregisterReceiver(headsetPlugReceiver);
  166. context.unregisterReceiver(bluetoothConnectionReceiver);
  167. context.unregisterReceiver(VolumeReceiver);
  168. }
  169. }

代码里面都有注释写的很详细,至于我为什么使用观察者模式来去监听纯属我自己想用(haha),使用观察模式的目的不光是为了更深刻的理解设计模式,更是想让自己以后的代码更加结构体系化,可能现在写的不咋地。

这里调用其实非常的方便,在你需要的Service或者Activity里把这玩意实例化,然后传入一个context就可以,然后在你需要的地方注册广播,或者在你不要的时候销毁,说白了就是个工具类

我给一个怎么用的实例代码:

调用因为我里面有回调接口(当然你不用也可以,不行还是得用,你要嫌麻烦不改,就直接实现就完事了,观察者会刷新数据然后你自己通过接口回调拿到你要的状态)要记得继承这个接口然实现里面的方法

MainActivity extends AppCompatActivity implements AudioDeviceHelper.AudioDeviceObserver
  1. private AudioDeviceHelper audioDeviceHelper;//首先声明变量
  2. //这一步在你onCreate或者初始化就创建
  3. audioDeviceHelper = new AudioDeviceHelper(MainActivity.this);//实例化传入上下文
  4. //添加观察者
  5. audioDeviceHelper.addObserver(MainActivity.this);
  6. //在你不要的地方注销掉广播
  7. audioDeviceHelper.unregisterReceivers();

你看,是不是非常容易调用,这也是我为什么热衷于将所有的方法写成工具类的原因,那会上大学写Android 什么方法都往Activity里塞,后面出来实习就不行了,看了别人的代码发现都很规整以及模块化,看起干干净净清清爽爽,狠狠的羡慕了,代码规范其实也是很重要的一个学问,使用的好对自己事半功倍,以后也好改(瞎改)。

其实你会发现,因为是跟音频有关,所有我的蓝牙判断是跟A2DP有关而不是单纯的蓝牙是否连接,至于我为什么会用一个延时器再来做一次判断,因为蓝牙开启需要时间啊,你不可能说开启就去判断吧,人家还没连上呢

再来看一看在Activity中如何使用该接口吧!

  1. @Override
  2. public void onHeadsetPluggedStateChange(boolean isPluggedIn) {
  3. LogUtils.e("耳机插入状态:" + isPluggedIn);
  4. }
  5. @Override
  6. public void onBluetoothConnectionStateChange(boolean isConnected) {
  7. LogUtils.e("蓝牙A2DP状态:" + isConnected);
  8. }

要实现这个接口,这两个接口返回的是个布尔值,并且这个布尔值不需要你去刷新界面啊,什么重新启动啊乱七八糟的,反正就是你在那里反复抽查耳机孔以及连接断开蓝牙就会实时改变,实时改变的也很及时。

转载前或者需要引用麻烦说一声,虽然是小白麻烦搬运也要说一声,毕竟自己心得,还有复制粘贴然后转成自己的sm玩意注意点啊,半夜刀了你。

当然希望各位大佬进行该代码的改进以及指正!

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/知新_RL/article/detail/866539
推荐阅读
相关标签
  

闽ICP备14008679号