Android 15 蓝牙OPP文件接收功能修改说明文档
Android 15 蓝牙OPP文件接收功能修改说明文档文章目录Android 15 蓝牙OPP文件接收功能修改说明文档一、修改概述需求列表源码路径二、修改文件清单2.1 新增文件2.2 修改文件三、功能实现说明3.1 需求1拦截文件接收弹出确认对话框3.2 需求2传输进度对话框3.3 需求3接收完成 Toast 关闭对话框3.4 需求4缩小为全局悬浮窗3.5 需求5接收失败显示 ✕3.6 中止接收功能四、效果和数据流图1、效果2、流程图如下所示五、移植到其他方案的说明5.1 文件复制清单5.2 AndroidManifest.xml 修改5.3 字符串资源5.4 原有文件修改点5.5 悬浮窗权限授予六、问题排查与解决6.1 调试日志6.2 常见问题七、版本记录Android Kiro AI软件开发实战教程一、修改概述本次修改针对 Android AOSP 蓝牙应用com.android.bluetooth的 OPP文件接收功能适配无状态栏/通知栏的设备如 RK3588 Android 15 开发板实现完整的蓝牙文件接收交互流程。需求列表拦截蓝牙文件接收弹出确认对话框替代通知栏确认确认接收后显示传输进度对话框实时显示进度和已接收文件列表接收完成后 Toast 提示并关闭对话框支持缩小为全局悬浮窗TYPE_APPLICATION_OVERLAY显示接收计数 N/M接收失败或中断时显示红色 ✕ 标记支持中止接收功能源码路径release/packages/modules/Bluetooth/android/app/二、修改文件清单2.1 新增文件文件路径说明src/.../opp/BluetoothOppTransferDialogActivity.java文件传输进度对话框 Activity显示当前传输进度、已接收文件列表支持缩小/中止src/.../opp/BluetoothOppFloatService.java全局悬浮窗 Service使用 TYPE_APPLICATION_OVERLAY 实现显示蓝色图标接收计数res/layout/bt_file_transfer_dialog.xml传输对话框布局标题栏含缩小按钮 文件信息 进度条含百分比和中止按钮 已接收文件列表res/layout/bt_file_transfer_item.xml已接收文件列表项布局文件名 时间 大小 状态标记res/layout/bt_file_transfer_float.xml悬浮窗布局透明背景 蓝色文件图标 计数文字2.2 修改文件文件路径修改内容AndroidManifest.xml添加 SYSTEM_ALERT_WINDOW 权限注册 BluetoothOppTransferDialogActivitysingleTask和 BluetoothOppFloatServicesrc/.../opp/BluetoothOppNotification.javaupdateIncomingFileConfirmNotification() 中添加直接启动确认 Activity 的逻辑绕过通知栏添加 mConfirmActivityLaunched 防重复启动标志src/.../opp/BluetoothOppIncomingFileConfirmActivity.javaonIncomingFileConfirmOk() 中确认后启动 BluetoothOppTransferDialogActivity传递设备名、文件名、文件大小、share URIsrc/.../opp/BluetoothOppObexServerSession.javareceiveFile() 中发送 ACTION_PROGRESS_UPDATE 广播含进度百分比、文件名、文件大小、当前文件索引onPut() 中发送 ACTION_FILE_COMPLETE / ACTION_TRANSFER_FAIL 广播onDisconnect() 中发送 ACTION_TRANSFER_DONE 广播src/.../opp/BluetoothOppReceiver.java添加 lwzbt 调试日志res/values/strings.xml新增 15 个英文字符串资源传输对话框、悬浮窗、中止、权限提示等res/values-zh-rCN/strings.xml新增对应简体中文字符串res/values-zh-rTW/strings.xml新增对应繁体中文字符串res/values-zh-rHK/strings.xml新增对应香港繁体中文字符串res/values/styles.xml新增 FloatWindowTheme 样式透明背景浮窗主题三、功能实现说明3.1 需求1拦截文件接收弹出确认对话框修改文件:BluetoothOppNotification.java实现方式:在updateIncomingFileConfirmNotification()方法中检测到待确认的传输记录时直接调用startActivity()启动BluetoothOppIncomingFileConfirmActivity添加mConfirmActivityLaunched标志防止重复启动当没有待确认记录时重置标志原理: 原生流程通过通知栏 Notification 让用户点击确认无状态栏设备无法操作。修改后绕过通知栏直接弹出确认对话框AlertActivity。3.2 需求2传输进度对话框新增文件:BluetoothOppTransferDialogActivity.java实现方式:用户在确认对话框点击接受后BluetoothOppIncomingFileConfirmActivity.onIncomingFileConfirmOk()启动BluetoothOppTransferDialogActivity传递设备名、文件名、文件大小、share URI对话框通过 BroadcastReceiver 监听 4 种广播ACTION_PROGRESS_UPDATE: 更新进度条和百分比ACTION_FILE_COMPLETE: 添加已接收文件到列表ACTION_TRANSFER_DONE: Toast 提示完成并关闭ACTION_TRANSFER_FAIL: 在文件列表显示红色 ✕广播发送方:BluetoothOppObexServerSessionreceiveFile()循环中每次进度变化发送ACTION_PROGRESS_UPDATE文件传输成功后发送ACTION_FILE_COMPLETE文件传输失败后发送ACTION_TRANSFER_FAILonDisconnect()中发送ACTION_TRANSFER_DONE3.3 需求3接收完成 Toast 关闭对话框实现方式:BluetoothOppObexServerSession.onDisconnect()发送ACTION_TRANSFER_DONE广播BluetoothOppTransferDialogActivity收到后显示 Toast 并调用dismissAndFinish()3.4 需求4缩小为全局悬浮窗新增文件:BluetoothOppFloatService.java实现方式:点击对话框右上角缩小按钮时先检查Settings.canDrawOverlays()悬浮窗权限无权限Toast 提示 跳转ACTION_MANAGE_OVERLAY_PERMISSION设置页有权限启动BluetoothOppFloatServicefinish()关闭 ActivityFloatService 使用WindowManagerTYPE_APPLICATION_OVERLAY创建全局悬浮窗悬浮窗默认显示在左下角可拖动悬浮窗直接监听 ObexServerSession 广播实时更新 N/M 计数点击悬浮窗启动新的 TransferDialogActivity stopSelf()权限说明: Android 13 的android.uid.bluetooth不再自动获得SYSTEM_ALERT_WINDOW权限需要通过系统应用如自定义 Settings 模块为com.android.bluetooth授予悬浮窗权限。3.5 需求5接收失败显示 ✕实现方式:BluetoothOppObexServerSession.onPut()中传输失败/被拒绝时发送ACTION_TRANSFER_FAIL广播对话框收到后在已接收文件列表中添加红色 “✕” 标记Toast 显示文件接收异常3.6 中止接收功能实现方式:进度条右侧添加红色中止接收按钮点击后调用contentResolverDelete(mShareUri)删除 share 记录与原生取消机制一致Toast 提示文件接收已中止3 秒后关闭对话框四、效果和数据流图1、效果确认蓝牙文件接收第一个蓝牙文件第二个文件接收过程如果是很多文件可以点击右上角把接收任务缩小只显示缩略图在左下角。缩略图缩略图可以上下左右移动点击缩略图可以重新显示蓝牙文件接收过程。蓝牙文件接收完成会自动关闭界面。2、流程图如下所示五、移植到其他方案的说明5.1 文件复制清单将以下文件复制到目标方案的对应路径# 新增 Java 文件 src/com/android/bluetooth/opp/BluetoothOppTransferDialogActivity.java src/com/android/bluetooth/opp/BluetoothOppFloatService.java # 新增布局文件 res/layout/bt_file_transfer_dialog.xml res/layout/bt_file_transfer_item.xml res/layout/bt_file_transfer_float.xml5.2 AndroidManifest.xml 修改在manifest中添加权限uses-permissionandroid:nameandroid.permission.SYSTEM_ALERT_WINDOW/在application中注册组件activityandroid:namecom.android.bluetooth.opp.BluetoothOppTransferDialogActivityandroid:processstring/processandroid:excludeFromRecentstrueandroid:themeandroid:style/Theme.Translucent.NoTitleBarandroid:launchModesingleTaskandroid:enabledtrue/activityserviceandroid:namecom.android.bluetooth.opp.BluetoothOppFloatServiceandroid:processstring/processandroid:enabledtrueandroid:exportedfalse/service5.3 字符串资源在res/values/strings.xml中添加以bt_file_transfer_开头的字符串资源。如需中文支持同步添加到res/values-zh-rCN/strings.xml等。5.4 原有文件修改点需要修改的原有文件及关键修改点BluetoothOppNotification.java:搜索updateIncomingFileConfirmNotification()方法在遍历待确认记录的循环中添加直接startActivity(BluetoothOppIncomingFileConfirmActivity)的逻辑添加mConfirmActivityLaunched标志防重复BluetoothOppIncomingFileConfirmActivity.java:搜索onIncomingFileConfirmOk()方法在确认数据库更新后添加启动BluetoothOppTransferDialogActivity的代码通过intent.setData(mUri)传递 share URIBluetoothOppObexServerSession.java:搜索receiveFile()方法在进度更新处添加ACTION_PROGRESS_UPDATE广播搜索onPut()方法在文件完成/失败处添加ACTION_FILE_COMPLETE/ACTION_TRANSFER_FAIL广播搜索onDisconnect()方法添加ACTION_TRANSFER_DONE广播所有广播需要setPackage(mContext.getPackageName())并携带EXTRA_CURRENT_INDEX和EXTRA_TOTAL_COUNT5.5 悬浮窗权限授予Android 13 的蓝牙应用不再自动获得 SYSTEM_ALERT_WINDOW 权限。需要通过以下方式之一授予adb 命令调试用adb shell appopssetcom.android.bluetooth SYSTEM_ALERT_WINDOW allow系统应用预置在系统 Settings 或自定义系统应用/服务中通过 AppOpsManager 为蓝牙应用授权privatevoidinitOppPermission(Contextcontext){try{setPackageAppOpsPermission(context,com.android.bluetooth,AppOpsManager.OPSTR_SYSTEM_ALERT_WINDOW);}catch(Exceptione){LogUtil.error(error e.getMessage());}}//设置特殊权限通过privatevoidsetPackageAppOpsPermission(Contextcontext,StringpackageName,StringopsString){booleanisNeedSetPermissionSystemProperties.getBoolean(persist.sys.debug.need_ops_permission,true);LogUtil.debug(isNeedSetPermission isNeedSetPermission);if(!isNeedSetPermission){return;}AppOpsManagermAppOps(AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);PackageManagermanagercontext.getPackageManager();intuid1;try{ApplicationInfopackageInfomanager.getApplicationInfo(packageName,0);uidpackageInfo.uid;}catch(Exceptione){e.printStackTrace();LogUtil.error(error e.getMessage());return;}LogUtil.debug(uid uid);mAppOps.setUidMode(opsString,uid,AppOpsManager.MODE_ALLOWED);}六、问题排查与解决6.1 调试日志所有自定义日志包含关键字lwzbt使用以下命令过滤adb logcat|greplwzbt关键日志标签标签组件lwzbt [Notification]通知拦截直接启动确认 Activitylwzbt [ConfirmActivity]确认对话框生命周期用户接受/拒绝lwzbt [ObexServer]OBEX 文件接收过程广播发送lwzbt [TransferDialog]传输对话框进度更新文件完成lwzbt [FloatService]悬浮窗服务计数更新lwzbt [Receiver]广播接收器6.2 常见问题问题1确认对话框不弹出检查日志lwzbt [Notification]是否有 “directly launching confirm activity”确认BluetoothOppNotification.java的修改已编译进固件清理编译make clean后重新编译问题2确认后传输对话框不显示检查日志lwzbt [ConfirmActivity]是否有 “user ACCEPTED”检查日志lwzbt [TransferDialog]是否有 “onCreate”确认 AndroidManifest.xml 中 TransferDialogActivity 的android:enabledtrue问题3进度不更新检查日志lwzbt [ObexServer]是否有 “sent ACTION_PROGRESS_UPDATE”检查日志lwzbt [TransferDialog]是否有 “onReceive”确认广播接收器使用RECEIVER_EXPORTED问题4悬浮窗崩溃BadTokenException / permission denied for window type 2003蓝牙应用缺少 SYSTEM_ALERT_WINDOW 权限执行adb shell appops set com.android.bluetooth SYSTEM_ALERT_WINDOW allow或通过系统应用授权见 5.5 节问题5悬浮窗计数不更新始终显示 0/N检查日志lwzbt [FloatService]是否有 “file complete”确认 FloatService 的广播接收器使用RECEIVER_EXPORTED确认 ObexServerSession 广播中包含EXTRA_CURRENT_INDEX和EXTRA_TOTAL_COUNT问题6修改后编译报错JavaUtilDate错误使用LocalTime.now(ZoneId.systemDefault())替代new Date()JavaTimeDefaultTimeZone警告LocalTime.now()改为LocalTime.now(ZoneId.systemDefault())UnusedMethod错误删除未使用的方法AOSP 使用 errorprone 严格检查需遵守其规则问题7编译后固件中没有新代码确认编译路径正确release/packages/modules/Bluetooth/android/app/尝试清理后重新编译先删除 out 目录下对应的中间产物确认.java文件在src/com/android/bluetooth/opp/目录下AOSP 自动编译该目录所有 java 文件七、版本记录日期修改内容2025-04-13初始实现确认对话框拦截、传输进度对话框、悬浮窗、失败标记2025-04-14修复 TYPE_SYSTEM_ALERT 崩溃改用 TYPE_APPLICATION_OVERLAY2025-04-14修复悬浮窗计数不更新改为直接监听 ObexServerSession 广播2025-04-14修复恢复后已接收文件列表丢失添加 onSaveInstanceState 持久化2025-04-14修复对话框恢复时左上角闪烁改用 moveTaskToBack2025-04-14添加中止接收功能进度条右侧红色中止接收按钮2025-04-14悬浮窗改为全局 Service 方案TYPE_APPLICATION_OVERLAY添加权限检查和跳转设置2025-04-14缩小时 finish() Activity 释放资源FloatService 独立运行该需求的代码是我用Kiro工具实现的虽然调试了很多次但是总体还是比较满意的具体实现的代码和Google写的一样精简。比我自己写得好之前没用Kiro前在不同Android版本的移动代码差异大也是会有报错也是需要多次调试修改。Android Kiro AI软件开发实战教程Kiro 是 AWS 推出的 AI 辅助开发 IDE基于 VS Code 内核集成了 AI Agent 能力。它能理解代码上下文、执行文件操作、运行命令、搜索代码并通过对话式交互帮助开发者完成复杂的编码任务。最近我用Kiro解决了不少Android Studio 应用的问题和系统源码应用的问题使用Kiro写Android代码确实可以减少 80%的精力并且生成和修改的代码简洁功能完善还有总结文档:https://blog.csdn.net/wenzhi20102321/article/details/160190206