Android Bluetooth 蓝牙开发/蓝牙协议 小结
蓝牙术语
蓝牙术语:
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开发 电话范例 -->反射
那么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 onError(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) {