首页 > 其他分享 >Android Bluetooth 蓝牙开发/蓝牙协议 小结

Android Bluetooth 蓝牙开发/蓝牙协议 小结

时间:2024-01-13 09:22:18浏览次数:42  
标签:void 蓝牙 private Bluetooth static Override Android public

蓝牙术语

蓝牙

蓝牙术语:
HFP(Hands-free Profile)耳机模式:
让蓝牙设备可以控制电话,如接听、挂断、拒接、语音拨号等,拒接、语音拨号要视蓝牙耳机及电话是否支持。

HSP(Handset Profile)耳机模式
用于支持蓝牙耳机与移动电话之间使用

蓝牙电话广播:
BluetoothHeadsetClient.ACTION_CALL_CHANGED
public static final String ACTION_CALL_CHANGED = "android.bluetooth.headsetclient.profile.action.AG_CALL_CHANGED";

BluetoothHeadsetClientCall callStatus = intent.getParcelableExtra(BluetoothHeadsetClient.EXTRA_CALL);
        CALL_STATE_ACTIVE = 0; talking
        CALL_STATE_DIALING = 2; CALL_STATE_ALERTING = 3; out dial
        CALL_STATE_WAITING = 5; waiting
        CALL_STATE_INCOMING = 4; incoming
        CALL_STATE_TERMINATED = 7; hangup

蓝牙电话  手机和耳机音频切换广播:
BluetoothHeadsetClient.ACTION_AUDIO_STATE_CHANGED
public static final String ACTION_AUDIO_STATE_CHANGED = "android.bluetooth.headsetclient.profile.action.AUDIO_STATE_CHANGED";
 int newState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE,
                BluetoothProfile.STATE_DISCONNECTED);
newState :2 bt
newState :0 phone

[demo](https://blog.csdn.net/weixin_45534242/article/details/124899251)
BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED

 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
    public static final String ACTION_AUDIO_STATE_CHANGED =
            "android.bluetooth.headset.profile.action.AUDIO_STATE_CHANGED";

    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
    public static final String ACTION_ACTIVE_DEVICE_CHANGED =
            "android.bluetooth.headset.profile.action.ACTIVE_DEVICE_CHANGED";


获取蓝牙 Pbap 协议栈的支持

蓝牙开发相关协议
Android 蓝牙开发——PBAP协议(十)
BluetoothPbapClient

为了方便开发,Android 提供了若干个蓝牙功能的协议栈,我们称之为 profile 。车机蓝牙开发我们需要用到的 profile 主要有:
Profile	     Description
A2DP Sink	 音频相关
HFP Client	 电话相关
Avrcp Controller	 音频控制相关
Pbap Client	        通讯录、通话记录相关

Android 蓝牙 app开发 函数回调
//\frameworks\base\packages\SettingsLib\src\com\android\settingslib\bluetooth
public class TextApiActivity extends Activity {
    private static final String TAG = "TextApiActivity";

    private LocalBluetoothManager mLocalBluetoothManager;
    private CachedBluetoothDeviceManager mCachedBluetoothDeviceManager;
    private BluetoothEventManager mBluetoothEventManager;
    private LocalBluetoothProfileManager mBluetoothProfileManager;


    private LocalBluetoothAdapter mLocalBluetoothAdapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_text_api);
        mLocalBluetoothManager = getLocalBtManager(TextApiActivity.this);

        mCachedBluetoothDeviceManager = mLocalBluetoothManager.getCachedDeviceManager();
        mBluetoothEventManager = mLocalBluetoothManager.getEventManager();
        mBluetoothProfileManager = mLocalBluetoothManager.getProfileManager();

        mBluetoothEventManager.registerCallback(mBluetoothCallback);
        mBluetoothProfileManager.addServiceListener(mServiceListener);


        mLocalBluetoothAdapter = mLocalBluetoothManager.getBluetoothAdapter();

        findViewById(R.id.btn).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (mLocalBluetoothAdapter != null) {
                    mLocalBluetoothAdapter.startScanning(true);
                }
            }
        });
    }


    public static LocalBluetoothManager getLocalBtManager(Context context) {
        return LocalBluetoothManager.getInstance(context, mOnInitCallback);
    }

    private static final LocalBluetoothManager.BluetoothManagerCallback mOnInitCallback =
            new LocalBluetoothManager.BluetoothManagerCallback() {
                @Override
                public void onBluetoothManagerInitialized(Context appContext, LocalBluetoothManager bluetoothManager) {
                    BluetoothUtils.setErrorListener(mErrorListener);
                }
            };


    //监听协议(Profile)相关接口是否可用
    LocalBluetoothProfileManager.ServiceListener mServiceListener = new LocalBluetoothProfileManager.ServiceListener() {
        @Override
        public void onServiceConnected() {
            //Bluetooth Service bind success 可以调用各Profile的接口
        }

        @Override
        public void onServiceDisconnected() {
            //Bluetooth Service unbind success

        }
    };


    BluetoothCallback mBluetoothCallback = new BluetoothCallback() {
        @Override
        public void onBluetoothStateChanged(int bluetoothState) {
            //蓝牙开关状态变化
            Log.d(TAG, "onBluetoothStateChanged:" + bluetoothState);
            BluetoothCallback.super.onBluetoothStateChanged(bluetoothState);
        }

        @Override
        public void onScanningStateChanged(boolean started) {
            //搜索状态变化
            Log.d(TAG, "onScanningStateChanged:" + started);
            BluetoothCallback.super.onScanningStateChanged(started);
        }

        @Override
        public void onDeviceAdded(CachedBluetoothDevice cachedDevice) {
            //搜索到新设备
            Log.d(TAG, "onDeviceAdded:" + cachedDevice.getName());
            BluetoothCallback.super.onDeviceAdded(cachedDevice);
        }

        @Override
        public void onDeviceDeleted(CachedBluetoothDevice cachedDevice) {
            //设备被移除
            Log.d(TAG, "onDeviceDeleted:" + cachedDevice.getName());
            BluetoothCallback.super.onDeviceDeleted(cachedDevice);
        }

        @Override
        public void onDeviceBondStateChanged(CachedBluetoothDevice cachedDevice, int bondState) {
            //设备配对状态变化
            Log.d(TAG, "onDeviceBondStateChanged:" + cachedDevice.getName() + "-----》" + bondState);
            BluetoothCallback.super.onDeviceBondStateChanged(cachedDevice, bondState);
        }

        @Override
        public void onConnectionStateChanged(CachedBluetoothDevice cachedDevice, int state) {
            //设备连接状态变化
            Log.d(TAG, "onConnectionStateChanged:" + cachedDevice.getName() + "-----》" + state);
            BluetoothCallback.super.onConnectionStateChanged(cachedDevice, state);
        }

        @Override
        public void onActiveDeviceChanged(CachedBluetoothDevice activeDevice, int bluetoothProfile) {
            //活动设备变化
            Log.d(TAG, "onConnectionStateChanged:" + activeDevice.getName() + "bluetoothProfile-----》" + bluetoothProfile);
            BluetoothCallback.super.onActiveDeviceChanged(activeDevice, bluetoothProfile);
        }

        @Override
        public void onAudioModeChanged() {
            BluetoothCallback.super.onAudioModeChanged();
        }

        @Override
        public void onProfileConnectionStateChanged(CachedBluetoothDevice cachedDevice, int state, int bluetoothProfile) {
            //协议连接状态变化
            BluetoothCallback.super.onProfileConnectionStateChanged(cachedDevice, state, bluetoothProfile);
        }

        @Override
        public void onAclConnectionStateChanged(CachedBluetoothDevice cachedDevice, int state) {
            //ACL连接状态变化
            BluetoothCallback.super.onAclConnectionStateChanged(cachedDevice, state);
        }
    };

    private static final ErrorListener mErrorListener = new ErrorListener() {
        @Override
        public void onShowError(Context context, String name, int messageResId) {
            showError(context, name, messageResId);
        }
    };

    static void showError(Context context, String name, int messageResId) {
        showError(context, name, messageResId, getLocalBtManager(context));
    }

    private static void showError(Context context, String name, int messageResId, LocalBluetoothManager manager) {
        String message = context.getString(messageResId, name);
        if (manager.isForegroundActivity()) {
            try {
                Log.d(TAG, "show ErrorDialogFragment, message is " + message);

            } catch (Exception e) {
                Log.e(TAG, "Cannot show error dialog.", e);
            }
        } else {
            Toast.makeText(context, message, Toast.LENGTH_SHORT).show();
        }
    }
}

Android 蓝牙 app开发 电话范例 -->反射

demo

那么Android手机设备通过蓝牙连接上汽车中控系统后,如何实现打电话功能的?有两种方式实现
1.通过硬件厂商提供的SDK来实现,这部分直接调用提供的API即可,实现简单
2.通过标准的Android 蓝牙协议实现,需要自己来实现,网上这方面的文章也不是很多

通过标准的Android蓝牙如何实现打电话的?
android.bluetooth.BluetoothHeadsetClient是一个系统隐藏类,实现蓝牙电话就是通过这个类完成。
不能直接调用,就只能反射调用了:
public class BluetoothManager {
    private final static String DIAL_CLASS_NAME = "android.bluetooth.BluetoothHeadsetClient";  //拨打电话类名
    private final static String DIAL_METHOD_NAME = "dial";  //拨打电话方法名
    private final static String BLUE_TOOTH_PROFILE_FIELD = "HEADSET_CLIENT";  //蓝牙适配器远程设备类型

    private static BluetoothManager instance;
    private OnCallResultListener onCallResultListener;

    public interface OnCallResultListener {
        //蓝牙未打开
        void onBluetoothIsClosed();

        //蓝牙未连接
        void onDeviceIsEmpty();

        //无效的电话号码
        void onPhoneIsInValid();

        void one rror(String errorMsg);
    }

    public static BluetoothManager getInstance() {
        if (instance == null) {
            instance = new BluetoothManager();
        }
        return instance;
    }

    //拨打电话的实际调用
    public void dial(final String number, final OnCallResultListener onCallResultListener) {
        this.onCallResultListener = onCallResultListener;
        if (StringUtils.isEmpty(number)) {
            if (onCallResultListener != null) {
                onCallResultListener.onPhoneIsInValid();
            }
        }
        getConnectStatus(new BluetoothProfile.ServiceListener() {
            @Override
            public void onServiceConnected(int profile, BluetoothProfile proxy) {
                List<BluetoothDevice> mDevices = proxy.getConnectedDevices();
                if (!Utils.isListEmpty(mDevices)) {
                    for (BluetoothDevice device : mDevices) {
                        dial(proxy, device, number);
                        break;
                    }
                } else {
                    if (onCallResultListener != null) {
                        onCallResultListener.onDeviceIsEmpty();
                    }
                }
            }

            @Override
            public void onServiceDisconnected(int profile) {
                if (onCallResultListener != null) {
                    onCallResultListener.onDeviceIsEmpty();
                }
            }
        });
    }

    //获取蓝牙的连接状态
    private void getConnectStatus(BluetoothProfile.ServiceListener serviceListener) {
        final int bluetooth_Profile_HEADSET_CLIENT;
        try {
            BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
            if (!adapter.isEnabled()) {
                if (onCallResultListener != null) {
                    onCallResultListener.onBluetoothIsClosed();
                    return;
                }
            }

            bluetooth_Profile_HEADSET_CLIENT = (int) BluetoothProfile.class.getField(BLUE_TOOTH_PROFILE_FIELD).get(null);
            //获取到蓝牙电话的连接状态
            int isConnected = adapter.getProfileConnectionState(bluetooth_Profile_HEADSET_CLIENT);
            if (isConnected == BluetoothProfile.STATE_DISCONNECTED) {
                if (onCallResultListener != null) {
                    onCallResultListener.onDeviceIsEmpty();
                    return;
                }
            }
            adapter.getProfileProxy(CommonApp.getCommonApp().getApplication(), serviceListener, bluetooth_Profile_HEADSET_CLIENT);

        } catch (Exception e) {
            if (onCallResultListener != null) {
                onCallResultListener.onError(e.getMessage());
            }
        }
    }

    /***
     * 拨号
     * @param proxy
     * @param bluetoothDevice
     * @param number
     */
    private void dial(BluetoothProfile proxy, BluetoothDevice bluetoothDevice, String number) {
        try {
            if (proxy == null || bluetoothDevice == null || (StringUtils.isEmpty(number))) {
                return;
            }
            Class BluetoothHeadsetClient = Class.forName(DIAL_CLASS_NAME);
            Method methodMain = BluetoothHeadsetClient.getMethod(DIAL_METHOD_NAME, BluetoothDevice.class, String.class);
            if (methodMain != null) {
                //蓝牙电话调用的具体执行
                methodMain.invoke(proxy, bluetoothDevice, number);
            }
        } catch (Exception e) {
            if (onCallResultListener != null) {
                onCallResultListener.onError(e.getMessage());
            }
        }
    }
}

//如果有系统源码,采用定制化的系统,直接引入out下面的framework.jar
private void createBtHeadSetClient() {
        BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
        if (bluetoothAdapter != null) {
            bluetoothAdapter.getProfileProxy(getApplicationContext(), new BluetoothProfile.ServiceListener() {
                @Override
                public void onServiceConnected(int profile, BluetoothProfile proxy) {
                    if (profile == BluetoothProfile.HEADSET_CLIENT) {
                        Log.d(TAG, "bluetoothAdapter onServiceConnected proxy:" + proxy);
                        mBluetoothHeadsetClient = (BluetoothHeadsetClient) proxy;
                    }
                }

                @Override
                public void onServiceDisconnected(int profile) {
                    Log.d(TAG, "bluetoothAdapter onServiceDisconnected" + profile);
                }
            }, BluetoothProfile.HEADSET_CLIENT);
        }
    }
    
public BluetoothHeadsetClientCall dial(BluetoothDevice device, String number) {
   
 }

Android 9.0 设置去取热点打开的首页显示的提示

--- a/ac8257_0302/vendor/mediatek/proprietary/packages/apps/MtkSettings/src/com/android/settings/dashboard/conditional/ConditionManager.java
+++ b/ac8257_0302/vendor/mediatek/proprietary/packages/apps/MtkSettings/src/com/android/settings/dashboard/conditional/ConditionManager.java
@@ -42,7 +42,7 @@ public class ConditionManager implements LifecycleObserver, OnResume, OnPause {
 
     private static final String TAG = "ConditionManager";
 
-    private static final boolean DEBUG = false;
+    private static final boolean DEBUG = true;
 
     private static final String PKG = "com.android.settings.dashboard.conditional.";
 
@@ -176,7 +176,9 @@ public class ConditionManager implements LifecycleObserver, OnResume, OnPause {
         if (AirplaneModeCondition.class == clz) {
             return new AirplaneModeCondition(this);
         } else if (HotspotCondition.class == clz) {
-            return new HotspotCondition(this);
+            //return new HotspotCondition(this);//add 
+            Log.d(TAG,"no new HotspotCondition(this)");
+            return null;
         } else if (DndCondition.class == clz) {
             return new DndCondition(this);
         } else if (BatterySaverCondition.class == clz) {

标签:void,蓝牙,private,Bluetooth,static,Override,Android,public
From: https://www.cnblogs.com/kato-T/p/17961954

相关文章

  • Android Webview判断网页加载完毕
    原文:AndroidWebview判断网页加载完毕-Stars-One的杂货小窝书接上文,在AndroidWebView获取html源码-Stars-One的杂货小窝此文讲到没有一个可以判断网页加载完毕的方法最近发现确实是有个解决方案,就是设置webViewClient里的onPageFinished方法判断当前webview进度,如下......
  • 迅为RK3568开发板编译Android12源码包-修改编译线程数
    在编译 Android 系统时,可以通过调整线程数来控制并行编译的任务数量,使用多线程可以加快构建速度。要注意根据 Ubuntu 的处理器内核总数以及内存大小来设置合适的线程数。过高的线程数可能导致系统资源的竞争,过低的线程数则不能充分利用系统的并行处理能力。找到合适的线程数可......
  • 集成 Firebase 后,Flutter IM SDK 在 Android 端不触发回调
    描述客户已集成FirebaseMessaging,Android平台FlutterIMSDK的不触发任何回调。分析(根因分析、需求分析)可能原因是客户构建了一个FlutterEngineinstance,导致SDK的FlutterEngineinstance失效了。解决方案找到以下java文件packages/firebase_messaging/firebase_me......
  • 【案例分析】在无线激光打靶应用中,2.4G蓝牙和Sub-G无线通信哪个方案更优?
    01行业背景特种行业的人员为了熟悉枪械的使用并提高其技术水准,需要大量的打靶训练。打靶实操中,需要有指挥人员、辅助人员、射击场地、射击器材等。打靶器材分为枪支、靶子、子弹。场地人员分为实操作训人员、人工报靶人员和现场指挥人员。打靶之前,指挥人员会吹口哨示警并摇动小红......
  • [Android] EventLogTags.logtags简单使用
    转载来源:https://blog.csdn.net/yfbdxz/article/details/114702144用EventLog.writeEvent打的日志(或EventLogTags.java方法打的日志),可以用logcat-bevents查看frameworks/base/core/java/android/util/EventLog.java//tag:Theeventtypetagcode.value:va......
  • Android架构测试 套小记
    Android架构测试主要是为了确保Android应用程序在不同设备和系统版本上的兼容性、性能和稳定性。这需要对应用程序的各个组件进行测试,包括活动、服务、广播接收器、内容提供程序等。以下是进行Android架构测试时可以采取的一些步骤:单元测试:对应用程序的各个组件进行测试,确保它......
  • 【Android】深入Binder拦截
    ☞Github☜☞Gitee☜说明Binder作为Android系统跨进程通信的核心机制。网上也有很多深度讲解该机制的文章,如:Android跨进程通信详解Binder机制原理Android系统核心机制Binder【系列】这些文章和系统源码可以很好帮助我们理解Binder的实现原理和设计理念,为拦截做准备......
  • Android——2个activity之间的数据传递返回
    老版本2个activity之间传递反回数据,实例如:https://www.cnblogs.com/xiaobaibailongma/p/16440432.html 新版本如下:https://blog.csdn.net/freezingxu/article/details/124953918?spm=1001.2101.3001.6650.2&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBl......
  • 迅为RK3568开发板Android11/12/Linux编译驱动到内核
    在平时的驱动开发中,经常需要在内核中配置某种功能,为了方便大家开发和学习,本小节讲解如何在内核中添加驱动。具体的讲解原理讲解请参考本手册的驱动教程。Android11源码如果想要修改内核,可以运行以下命令进行修改:cdkernel/makeARCH=arm64rockchip_defconfigmakeARCH=arm64men......
  • Технология Bluetooth: беспроводная революция, с
    ТехнологияBluetooth—этоинновационноерешениебеспроводнойсвязи,предназначенноедлябеспрепятственногосоединенияразличныхпортативных......