写点什么

手把手教你打通车载蓝牙与手机 app 的音频信息传输 & 车载反向控制手机 app

用户头像
Android架构
关注
发布于: 54 分钟前

registerReceiver(avrcpBroadcastReceiver,new IntentFilter(AvrcpControllerHelper.ACTION_TRACK_EVENT));

车载蓝牙如何反向控制音频播放器

车载蓝牙要反向控制音频播放器需要借助 BluetoothAvrcpController,BluetoothAvrcpController 对普通应而言是隐藏的。如果有 framework 可以直接访问,没有的话我们可以通过反射来进行处理。BluetoothAvrcpController#sendGroupNavigationCmd 是用来反向调用音频播放器的。


同时我们为 mediaSession 设置 callback 对象


mediaSession.setCallback(new MediaSession.Callback() {


@Overridepublic void onCommand(@NonNull String command, @Nullable Bundle args, @Nullable ResultReceiver cb) {Log.e(TAG,"onCommand");super.onCommand(command, args, cb);}


@Overridepublic boolean onMediaButtonEvent(@NonNull Intent mediaButtonIntent) {Log.e(TAG,"onMediaButtonEvent");Toast.makeText(BluetoothPlayerActivity.this,"我对你那么好,


《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》
浏览器打开:qq.cn.hn/FTe 免费领取
复制代码


你居然操作我",Toast.LENGTH_SHORT).show();return super.onMediaButtonEvent(mediaButtonIntent);}});


反射 BluetoothAvrcpController 来处理相关的方法


public class AvrcpControllerHelper {private static final String TAG = AvrcpControllerHelper.class.getSimpleName();public static int AVRCP_CONTROLLER = 12;


public static final String ACTION_TRACK_EVENT = "android.bluetooth.avrcp-controller.profile.action.TRACK_EVENT";public static final String EXTRA_METADATA = "android.bluetooth.avrcp-controller.profile.extra.METADATA";public static final String EXTRA_PLAYBACK = "android.bluetooth.avrcp-controller.profile.extra.PLAYBACK";


public static void sendGroupNavigationCmd(BluetoothProfile bluetoothProfile, BluetoothDevice device, int keyCode, int keyState){if(bluetoothProfile != null){try {Method m = bluetoothProfile.getClass().getMethod("sendGroupNavigationCmd",BluetoothDevice.class,int.class,int.class);m.setAccessible(true);m.invoke(bluetoothProfile,device,keyCode,keyState);} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {e.printStackTrace();}}}


private static void fixSystemHideApi(){if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P) {return;}try {Method forName = Class.class.getDeclaredMethod("forName", String.class);Method getDeclaredMethod = Class.class.getDeclaredMethod("getDeclaredMethod", String.class, Class[].class);Class<?> vmRuntimeClass = (Class<?>) forName.invoke(null, "dalvik.system.VMRuntime");Method getRuntime = (Method) getDeclaredMethod.invoke(vmRuntimeClass, "getRuntime", null);Method setHiddenApiExemptions = (Method) getDeclaredMethod.invoke(vmRuntimeClass, "setHiddenApiExemptions", new Class[]{String[].class});Object sVmRuntime = getRuntime.invoke(null);setHiddenApiExemptions.invoke(sVmRuntime, new Object[]{new String[]{"L"}});} catch (Throwable e) {Log.e("[error]", "reflect bootstrap failed:", e);}}


public static List<BluetoothDevice> getConnectedDevices(BluetoothProfile profile){if(profile == null){return null;}fixSystemHideApi();try {Method m = profile.getClass().getDeclaredMethod("getConnectedDevices");m.setAccessible(true);return (List<BluetoothDevice>) m.invoke(profile);} catch (NoSuchMethodException e) {Log.w(TAG, "No disconnect method in the " + profile.getClass().getName() +" class, ignoring request.");return null;} catch (InvocationTargetException | IllegalAccessException e) {Log.w(TAG, "Could not execute method 'disconnect' in profile " +profile.getClass().getName() + ", ignoring request.", e);return null;}}


//系统的 BluetoothAvrcp 获取不到,这里把这个拷贝出来 public static class BluetoothAvrcp {


/*


  • State flags for Passthrough commands*/public static final int PASSTHROUGH_STATE_PRESS = 0;public static final int PASSTHROUGH_STATE_RELEASE = 1;


/*


  • Operation IDs for Passthrough commands/public static final int PASSTHROUGH_ID_SELECT = 0x00; / select /public static final int PASSTHROUGH_ID_UP = 0x01; / up /public static final int PASSTHROUGH_ID_DOWN = 0x02; / down /public static final int PASSTHROUGH_ID_LEFT = 0x03; / left /public static final int PASSTHROUGH_ID_RIGHT = 0x04; / right /public static final int PASSTHROUGH_ID_RIGHT_UP = 0x05; / right-up /public static final int PASSTHROUGH_ID_RIGHT_DOWN = 0x06; / right-down /public static final int PASSTHROUGH_ID_LEFT_UP = 0x07; / left-up /public static final int PASSTHROUGH_ID_LEFT_DOWN = 0x08; / left-down /public static final int PASSTHROUGH_ID_ROOT_MENU = 0x09; / root menu /public static final int PASSTHROUGH_ID_SETUP_MENU = 0x0A; / setup menu /public static final int PASSTHROUGH_ID_CONT_MENU = 0x0B; / contents menu /public static final int PASSTHROUGH_ID_FAV_MENU = 0x0C; / favorite menu /public static final int PASSTHROUGH_ID_EXIT = 0x0D; / exit /public static final int PASSTHROUGH_ID_0 = 0x20; / 0 /public static final int PASSTHROUGH_ID_1 = 0x21; / 1 /public static final int PASSTHROUGH_ID_2 = 0x22; / 2 /public static final int PASSTHROUGH_ID_3 = 0x23; / 3 /public static final int PASSTHROUGH_ID_4 = 0x24; / 4 /public static final int PASSTHROUGH_ID_5 = 0x25; / 5 /public static final int PASSTHROUGH_ID_6 = 0x26; / 6 /public static final int PASSTHROUGH_ID_7 = 0x27; / 7 /public static final int PASSTHROUGH_ID_8 = 0x28; / 8 /public static final int PASSTHROUGH_ID_9 = 0x29; / 9 /public static final int PASSTHROUGH_ID_DOT = 0x2A; / dot /public static final int PASSTHROUGH_ID_ENTER = 0x2B; / enter /public static final int PASSTHROUGH_ID_CLEAR = 0x2C; / clear /public static final int PASSTHROUGH_ID_CHAN_UP = 0x30; / channel up /public static final int PASSTHROUGH_ID_CHAN_DOWN = 0x31; / channel down /public static final int PASSTHROUGH_ID_PREV_CHAN = 0x32; / previous channel /public static final int PASSTHROUGH_ID_SOUND_SEL = 0x33; / sound select /public static final int PASSTHROUGH_ID_INPUT_SEL = 0x34; / input select /public static final int PASSTHROUGH_ID_DISP_INFO = 0x35; / display information /public static final int PASSTHROUGH_ID_HELP = 0x36; / help /public static final int PASSTHROUGH_ID_PAGE_UP = 0x37; / page up /public static final int PASSTHROUGH_ID_PAGE_DOWN = 0x38; / page down /public static final int PASSTHROUGH_ID_POWER = 0x40; / power /public static final int PASSTHROUGH_ID_VOL_UP = 0x41; / volume up /public static final int PASSTHROUGH_ID_VOL_DOWN = 0x42; / volume down /public static final int PASSTHROUGH_ID_MUTE = 0x43; / mute /public static final int PASSTHROUGH_ID_PLAY = 0x44; / play /public static final int PASSTHROUGH_ID_STOP = 0x45; / stop /public static final int PASSTHROUGH_ID_PAUSE = 0x46; / pause /public static final int PASSTHROUGH_ID_RECORD = 0x47; / record /public static final int PASSTHROUGH_ID_REWIND = 0x48; / rewind /public static final int PASSTHROUGH_ID_FAST_FOR = 0x49; / fast forward /public static final int PASSTHROUGH_ID_EJECT = 0x4A; / eject /public static final int PASSTHROUGH_ID_FORWARD = 0x4B; / forward /public static final int PASSTHROUGH_ID_BACKWARD = 0x4C; / backward /public static final int PASSTHROUGH_ID_ANGLE = 0x50; / angle /public static final int PASSTHROUGH_ID_SUBPICT = 0x51; / subpicture /public static final int PASSTHROUGH_ID_F1 = 0x71; / F1 /public static final int PASSTHROUGH_ID_F2 = 0x72; / F2 /public static final int PASSTHROUGH_ID_F3 = 0x73; / F3 /public static final int PASSTHROUGH_ID_F4 = 0x74; / F4 /public static final int PASSTHROUGH_ID_F5 = 0x75; / F5 /public static final int PASSTHROUGH_ID_VENDOR = 0x7E; / vendor unique */public static final int PASSTHROUGH_KEYPRESSED_RELEASE = 0x80;}}整体使用 demo(只是打通了车载与手机 app 的互相调用流程):[github.com/xiaolutang/…](


)下一篇:从系统流程上分析蓝牙交互的过程。

用户头像

Android架构

关注

还未添加个人签名 2021.10.31 加入

还未添加个人简介

评论

发布
暂无评论
手把手教你打通车载蓝牙与手机app的音频信息传输&车载反向控制手机app