Android Bluetooth 蓝牙开发/蓝牙协议 小结
1.Android 11 -- 强制清理app后台,关于权限引发的问题2.Android 11 (MTK)状态栏图标反色-->跟随当前应用变化代码流程3.Android 11 --关于Toast的异常4.Android 11 -- 关于dialog和悬浮窗导致SystemUI状态栏下拉频繁闪烁(窗口焦点问题)5.Android 11 下拉菜单长按WiFi图标SystemUI ANR6.Android 11 sim卡来电不弹出悬浮通知,默认来电默认全屏
7.Android Bluetooth 蓝牙开发/蓝牙协议 小结
8.Android11 —— 自定义添加一个System Services9.Android系统——AOSP相关-->随记10.Android11 , Launcher3 切换阿拉伯语,最近应用(后台)不能滑动11.Android 底层问题日志记录12.Android 11 -- app 服务保活13.Android11 - 添加自定义服务注意事项14.Android 11 导航栏添加一个虚拟按钮--问题合集15.Android 11--设置第三方Launcher并默认 与 如何预置apk16.Android11 系统修改 AOSP输入法的默认输入键盘布局17.Settings里面切换不同Launcher的代码流程18.关于Android`系统默认屏保`19.关于Android 11 Settings添加新的选项界面的细节20.Android 11 自由窗口模式 || 全屏模式启动app21.强制app横屏显示或者竖屏显示(动态)22.Android 11 禁止从SD卡上安装第三方应用23.实体物理音量键替换为home键24.AMS- kill Launcher进程的代码流程25.Android 11 recovery恢复出厂设置保留某些文件26.Android 11 禁用 adb root (userdebug版本)27.Android11 应用默认获取通知使用权限(可以获取系统所有通知信息)28.Android 11 UsbDebug 关于adb RSA 认证29.Android 11 NavigationBar && Status Bar 如果改变背景颜色30.Anroid 11 关于NotificationManager && NotificationManagerService -- 衍生到权限管理31.Android13 控制设置界面 双栏显示或单栏显示32.Android 13 大屏显示时关于SystemUI和Launcher3问题33.Android 系统适配无源码app34.Android 11 关于app的权限重置35.Android 11.0 关于app进程保活36.Android 11 关于按键拦截/按键事件处理分享37.Android R Settings关于屏保/PowerManagerService欺骗系统不让其进入休眠状态38.Android13 关于SystemUI更新/Nav Bar add volume button&&other button39.Android 13 移植EthernetSettings/Ethernet更新40.Anrdoir 13 关于设置静态IP后,突然断电,在上电开机卡动画41.Android T(13) The app is granted permissions by default42.Android T 关于屏幕旋转 (一)43.Android T about screen rotation(二)44.Android 13 about launcher3 (1)45.Android T don't abort background activity starts46.Android T adout replace bootanimation47.Launcher start App WINDOWING_MODE_FREEFORM48.Android 11 About SleepToken / (Settings)Screen timeout49.Settings.System数据监听/prop&SystemProperties数据监听蓝牙术语
蓝牙术语:
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) {
分类:
Android
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· 实操Deepseek接入个人知识库
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· 【.NET】调用本地 Deepseek 模型
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库
2022-01-13 属性动画实现-LoadingView
2022-01-13 BottomDotTextView--底部有个小圆点