Android 蓝牙弹框接收传输的文件实现
Android 蓝牙弹框接收传输的文件实现
文章目录
一、前言
Android 原生系统蓝牙接收是在通知栏显示和操作,但是部分定制设备比如大屏或者盒子设备是没有通知栏的。
如果要接收蓝牙文件就要自己接收蓝牙广播进行弹框提示,大概包括:确认接收,显示接收进度,确认取消/完成接收等弹框和实现,具体修改就要适配系统的蓝牙应用。
本文基于Android13 系统蓝牙应用Bluetooth文件传输Opp部分代码适配进行介绍。
也许你工作中不一定有这个需求,但是安卓屏显开发大概率是有这个需求的,
部分有兴趣的并且有系统源码编译运行条件的,可以尝试修改系统源码试试,
有需求的或者有兴趣的可以了解。
二、修改效果
1、确认接收
这里是中间弹框提示是否接收文件。背景是浏览器界面不用管。
2、接收过程
这里是中间弹框提示进度。
3、接收完成或者其他异常
目前方案是接收完成直接是隐藏了对话框,toast提示完成。
也有的方案要求在接收的列表下面添加一个完成按钮,点击完成隐藏传输框。
点击取消或者另外一边取消发送都是可以收到广播的,直接显示取消接收/接收异常即可。
在Android 的蓝牙传输中是无法跳过某个文件再接收后面的文件的,只能一个一个接收,
多个文件接收的情况,中途取消后,后面的文件都是无法再接收的,只能让另外一个设备重新发送。
三、代码修改
1、主要文件和目录
(1)目录
Android 文件传输协议是opp协议,蓝牙文件接收各种处理是在opp文件夹目录内。
具体目录:
package\modules\Bluetooth\android\app\src\com\android\bluetooth\opp
Android 11 或者更低的版本蓝牙相关代码是在 package\apps\Bluetooth\src\com\android\bluetooth\opp
(2)广播接收代码
package\modules\Bluetooth\android\app\src\com\android\bluetooth\opp\BluetoothOppReceiver.java
<receiver android:process="@string/process" android:name="com.android.bluetooth.opp.BluetoothOppReceiver"
android:exported="true"
android:enabled="false">
<intent-filter>
<action android:name="android.btopp.intent.action.OPEN_RECEIVED_FILES"/>
</intent-filter>
</receiver>
上面那个静态广播接收只有一个Action?
但是Java 代码中有很多接收的Action?并且代码中确实有其他广播接收的,为啥可以这样,暂时不清楚!
有个猜测:本应用内之间可以指定某个广播接收类给它发送广播。
public class BluetoothOppReceiver extends BroadcastReceiver {
private static final String TAG = "BluetoothOppReceiver";
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (D) Log.d(TAG, " action :" + action);
mContext = context;
if (action == null) return;
if (action.equals(BluetoothDevicePicker.ACTION_DEVICE_SELECTED)) {
} else if (action.equals(Constants.ACTION_ACCEPT)) { //点击接收触发,其实是自身发送的
if (V) {
Log.v(TAG, "Receiver ACTION_ACCEPT");
}
} else if (action.equals(BluetoothShare.TRANSFER_COMPLETED_ACTION)) { //文件接收完成
if (V) {
Log.v(TAG, "Receiver Transfer Complete Intent for " + intent.getData());
}
//自定义添加的代码逻辑
if (BluetoothShare.isStatusSuccess(transInfo.mStatus)) { //文件成功
//以前的逻辑
/**if (transInfo.mDirection == BluetoothShare.DIRECTION_OUTBOUND) {
toastMsg = context.getString(R.string.notification_sent, transInfo.mFileName);
} else if (transInfo.mDirection == BluetoothShare.DIRECTION_INBOUND) {
toastMsg =
context.getString(R.string.notification_received, transInfo.mFileName);
}**/
//自定义弹框的逻辑
Intent is = new Intent(NotifyDialogManager.ACTION_RECEIVER_SUCCEED);
is.putExtra("fileName", transInfo.mFileName);
is.putExtra("fileType", transInfo.mFileType);
notifyDialogManager(is);
} else if (BluetoothShare.isStatusError(transInfo.mStatus)) { //文件失败
//自定义弹框的逻辑
Intent is = new Intent(NotifyDialogManager.ACTION_RECEIVER_FAILED);
is.putExtra("fileName", transInfo.mFileName);
is.putExtra("fileType", transInfo.mFileType);
notifyDialogManager(is);
}
}//还有很多其他相关广播这里不一一罗列
}
}
这里只是广播的一个过程,很多重要的过程是在BluetoothOppService.java 和 BluetoothOppNotification.java 发生的。
其实最关键的是: BluetoothShare.CONTENT_URI 变量,无论蓝牙的开始,传输过程,和结束都跟里面的数据相关。
本次自定义输入框的开发,数据交互用的是本地广播。
(3)传输服务类 BluetoothOppService
BluetoothOppService 是 文件能够传输的重要保障,如果该服务异常,或者未启动也是无法进行文件传输的。
主要代码如下:
public class BluetoothOppService extends ProfileService { //父类是普通的Service类
private static final boolean D = Constants.DEBUG; //日志文件,已经手动设置成true
private static final boolean V = Constants.VERBOSE;//日志文件,已经手动设置成true
private static final String TAG = "BtOppService"; //注意这才是本来的TAG打印
@Override
public boolean start() { //Service 生命周期方法
if (V) {
Log.v(TAG, "start()");
}
// BluetoothShare.CONTENT_URI 属性变化监听
mObserver = new BluetoothShareContentObserver();
getContentResolver().registerContentObserver(BluetoothShare.CONTENT_URI, true, mObserver);
return true;
}
//属性变化监听,类似Settings.Global 那些属性的监听
private class BluetoothShareContentObserver extends ContentObserver {
BluetoothShareContentObserver() {
super(new Handler());
}
@Override
public void onChange(boolean selfChange) { //传输开始过程一直是有这个日志的
if (V) {
Log.v(TAG, "ContentObserver received notification");
}
updateFromProvider();
}
}
//每接收一个文件,mUpdateThread 会置空一次,所以每个接收的文件是new一个thread
private void updateFromProvider() {
synchronized (BluetoothOppService.this) {
mPendingUpdate = true;
if (mUpdateThread == null) {
mUpdateThread = new UpdateThread();
mUpdateThread.start();
mUpdateThreadRunning = true;
}
}
}
}
在蓝牙打开的情况,查看opp服务,可以看到如下信息:
130|console:/ # dumpsys activity services | grep opp
* ServiceRecord{e9e9e2e u0 com.android.bluetooth/.opp.BluetoothOppService}
intent={cmp=com.android.bluetooth/.opp.BluetoothOppService}
infoAllowStartForeground=[callingPackage: com.android.bluetooth; callingUid: 1002; uidState: PER ; intent: Intent { cmp=com.android.bluetooth/.opp.BluetoothOppService (has extras) }; code:PROC_STATE_PERSISTENT; tempAllowListReason:<broadcast:1000:android.bluetooth.adapter.action.STATE_CHANGED,reason:,reasonCode:BLUETOOTH_BROADCAST,duration:10000,callingUid:1000>; targetSdkVersion:33; callerTargetSdkVersion:33; startForegroundCount:0; bindFromPackage:null]
console:/ #
蓝牙关闭的情况是无法获取到该信息的。所以如果蓝牙文件无法传输的情况,可以查看该服务是否正常运行。
BluetoothOppService 服务正常运行的情况,才能正常传输文件。
(3)接收数据重要过程
这里可以看到 从BluetoothOppNotification.java 的代码可以看到接收文件的确认,过程和结束方法,并且这三个方法是一直有回调打印的。
package\modules\Bluetooth\android\app\src\com\android\bluetooth\opp\BluetoothOppNotification.java
private class NotificationUpdateThread extends Thread {
NotificationUpdateThread() {
super("Notification Update Thread");
}
@Override
public void run() {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
synchronized (BluetoothOppNotification.this) {
if (mUpdateNotificationThread != this) {
throw new IllegalStateException(
"multiple UpdateThreads in BluetoothOppNotification");
}
mPendingUpdate = 0;
}
//重要的过程,三个
updateActiveNotification();//更新文件接收过程,这里有判断总共接收的文件数,文件大小,文件名称和已接收问大小等基本数据
updateCompletedNotification(); //文件是否接收完成通知?自定义没有用到
updateIncomingFileConfirmNotification(); //确认接收文件
synchronized (BluetoothOppNotification.this) {
mUpdateNotificationThread = null;
}
}
}
2、蓝牙文件接收最开始的地方到整个过程
这个具体过程要追寻估计有点麻烦,有兴趣的可以看看完整的蓝牙文件接收日志梳理梳理。
这里大概描述一下。
(1)蓝牙打开的情况,BluetoothOppService 会启动
(2)BluetoothOppService 调用 startSocketListener();
(3)蓝牙配对后,其他设备发送蓝牙文件,ObexServerSockets 接收到蓝牙文件接收任务,其实是底层会先接收
具体过程可以看日志打印了解
(4)BluetoothOppService 监听到 BluetoothShare.CONTENT_URI 变化,updateFromProvider()。
(5)BluetoothOppService 启动线程 一直遍历 BluetoothShare.CONTENT_URI 的值,并且一直调用 updateNotification 发送消息给 BluetoothOppNotification ,BluetoothOppNotification 判断 蓝牙文件确认,蓝牙过程显示,蓝牙结束等重要过程
3、蓝牙文件确认
BluetoothOppNotification 的 updateIncomingFileConfirmNotification() 方法,
在遍历到 BluetoothShare.CONTENT_URI 数据 数据的时候弹框提示,是否确认接收
//提示蓝牙文件确认方法
void updateIncomingFileConfirmNotification() {
//注意这个的游标是关于 WHERE_CONFIRM_PENDING 的,确认的
Cursor cursor = BluetoothMethodProxy.getInstance().contentResolverQuery(mContentResolver,
BluetoothShare.CONTENT_URI, null, WHERE_CONFIRM_PENDING,
null, BluetoothShare._ID);
if (cursor == null) {
return;
}
for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) {
BluetoothOppTransferInfo info = new BluetoothOppTransferInfo();
BluetoothOppUtility.fillRecord(mContext, cursor, info);
Uri contentUri = Uri.parse(BluetoothShare.CONTENT_URI + "/" + info.mID);
String fileNameSafe = info.mFileName.replaceAll("\\s", "_");
Intent baseIntent = new Intent().setDataAndNormalize(contentUri)
.setClassName(mContext,
BluetoothOppReceiver.class.getName());
//创建自定义的弹框对象
NotifyDialogManager.Info sinfo = new NotifyDialogManager.Info();
//接收的文件名
sinfo.filename = info.mFileName;
//点击取消接收按钮的操作
sinfo.cancel = new View.OnClickListener() {
@Override
public void onClick(View v) {
mContext.sendBroadcast(new Intent(baseIntent).setAction(Constants.ACTION_DECLINE));
mNotifyDialogManager.cancel(NotifyDialogManager.RECEIVER_CONFIRM_DIALOG);
}
};
//点击接收按钮,确认文件接收操作
sinfo.confirm = new View.OnClickListener() {
@Override
public void onClick(View v) {
mContext.sendBroadcast(new Intent(baseIntent).setAction(Constants.ACTION_ACCEPT));
mNotifyDialogManager.cancel(NotifyDialogManager.RECEIVER_CONFIRM_DIALOG);
}
};
mNotifyDialogManager.setDeviceName(info.mDeviceName);
mNotifyDialogManager.notify(NotifyDialogManager.RECEIVER_CONFIRM_DIALOG, sinfo);
mInitialState = getCurrentState();
break;
。。。
}
这里可以看到,蓝牙文件接收实际操作是发送广播:
mContext.sendBroadcast(new Intent(baseIntent).setAction(Constants.ACTION_ACCEPT));
蓝牙文件拒绝是发送了广播:
mContext.sendBroadcast(new Intent(baseIntent).setAction(Constants.ACTION_DECLINE));
上面看到重要过程有三个,为啥在最后的 updateIncomingFileConfirmNotification 方法做接收文件处理?
具体原因不清楚,因为原生代码也是在这个方法里面发送通知消息给通知栏,让其确认和取消,所以自定义接收框同样写在了这里。
这里的发送广播确认和取消 都是在 BluetoothOppReceiver 的广播接收者里面有进行处理。
4、蓝牙文件进度更新
@VisibleForTesting
void updateActiveNotification() {
// Active transfers
//注意这个的游标是关于 WHERE_RUNNING 的,过程的,和其他的不同
Cursor cursor = BluetoothMethodProxy.getInstance().contentResolverQuery(mContentResolver,
BluetoothShare.CONTENT_URI, null, WHERE_RUNNING, null, BluetoothShare._ID);
if (cursor == null) {
return;
}
// If there is active transfers, then no need to update completed transfer
// notifications
if (cursor.getCount() > 0) {
mUpdateCompleteNotification = false;
} else {
mUpdateCompleteNotification = true;
}
if (V) {
Log.v(TAG, "mUpdateCompleteNotification = " + mUpdateCompleteNotification);
}
// Collate the notifications
final int timestampIndex = cursor.getColumnIndexOrThrow(BluetoothShare.TIMESTAMP);
final int directionIndex = cursor.getColumnIndexOrThrow(BluetoothShare.DIRECTION);
final int idIndex = cursor.getColumnIndexOrThrow(BluetoothShare._ID);
final int totalBytesIndex = cursor.getColumnIndexOrThrow(BluetoothShare.TOTAL_BYTES);
final int currentBytesIndex = cursor.getColumnIndexOrThrow(BluetoothShare.CURRENT_BYTES);
final int dataIndex = cursor.getColumnIndexOrThrow(BluetoothShare._DATA);
final int filenameHintIndex = cursor.getColumnIndexOrThrow(BluetoothShare.FILENAME_HINT);
final int confirmIndex = cursor.getColumnIndexOrThrow(BluetoothShare.USER_CONFIRMATION);
final int destinationIndex = cursor.getColumnIndexOrThrow(BluetoothShare.DESTINATION);
mNotifications.clear();
//从日志看,这里只取 cursor 一帧的数据,并不是这里for循环取完整个的蓝牙文件
for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) {
long timeStamp = cursor.getLong(timestampIndex);
int dir = cursor.getInt(directionIndex);
int id = cursor.getInt(idIndex);
long total = cursor.getLong(totalBytesIndex);
long current = cursor.getLong(currentBytesIndex);
int confirmation = cursor.getInt(confirmIndex);
String destination = cursor.getString(destinationIndex);
String fileName = cursor.getString(dataIndex);
if (fileName == null) {
fileName = cursor.getString(filenameHintIndex);
}
if (fileName == null) {
fileName = mContext.getString(R.string.unknown_file);
}
String batchID = Long.toString(timeStamp);
// sending objects in one batch has same timeStamp
if (mNotifications.containsKey(batchID)) {
// NOTE: currently no such case
// Batch sending case
} else {
//load file
Log.v(TAG, "ACTION_INCOMING_FILE_CONFIRM " + current + "/" + total);
//Intent intent = new Intent(Constants.ACTION_INCOMING_FILE_CONFIRM);
//mContext.sendBroadcast(intent);
//显示自定义对话框,更新文件接收过程
int[] state = getCurrentState();
NotifyDialogManager.Info rinfo = new NotifyDialogManager.Info();
rinfo.all = (int) total; //文件总共大小
rinfo.done = (int) current;// 当前已经接收的文件大小
rinfo.filename = fileName; //文件名称
mNotifyDialogManager.notify(NotifyDialogManager.RECEIVER_PROGRESS_DIALOG, rinfo);
}
}
cursor.close();
LogUtil.debug("end");
}
为啥在 updateActiveNotification 方法里面处理文件接收过程?原生也是在这里发消息给通知栏的!
5、蓝牙文件传输完成
文件接收完成处理比较特殊。
/**
* Receives and handles: system broadcasts; Intents from other applications;
* Intents from OppService; Intents from modules in Opp application layer.
*/
public class BluetoothOppReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
。。。//很多其他不是主要的广播,这里不一一罗列
} else if (action.equals(BluetoothShare.TRANSFER_COMPLETED_ACTION)) { //文件接收完成
if (V) {
Log.v(TAG, "Receiver Transfer Complete Intent for " + intent.getData());
}
if (BluetoothShare.isStatusSuccess(transInfo.mStatus)) {
//自定义弹框,提示文件接收成功
Intent is = new Intent(NotifyDialogManager.ACTION_RECEIVER_SUCCEED);
is.putExtra("fileName", transInfo.mFileName);
is.putExtra("fileType", transInfo.mFileType);
notifyDialogManager(is);
} else if (BluetoothShare.isStatusError(transInfo.mStatus)) {
//自定义弹框,提示文件接收失败
Intent is = new Intent(NotifyDialogManager.ACTION_RECEIVER_FAILED);
is.putExtra("fileName", transInfo.mFileName);
is.putExtra("fileType", transInfo.mFileType);
notifyDialogManager(is);
}
}
}
为啥接收完成不用 updateCompletedNotification 方法里面进行处理?
看了下原生的 updateCompletedNotification 方法里面逻辑还是比较多的,
有判断成功接收多少个,失败接收多少个;从日志上看接收成功也有可能显示失败,具体原因不清楚。
6、蓝牙文件传输异常
对方设备异常,比如关闭蓝牙或者取消发送,都是会有广播:BluetoothShare.TRANSFER_COMPLETED_ACTION
在里面进行处理即可。
另外本机设备如果要 中断接收文件可以发送下面的广播:
//取消接收
Intent intent = new Intent();
intent.setAction(BluetoothOppService.ACTION_BLUETOOTH_TRANSFER_STOP);
getContext().sendBroadcast(intent);
注意,多个文件接收的情况,取消接收后,后面的文件是无法继续接收的,
如果还有传输,只能让对方设备需要重新传输。
7、 整个opp文件Java部分修改的patch
代码修改还是比较多的,有需要的可以下载下来看看。
Change-Id: Ifef37f272a81b09d0707443c6bc09ee9786bd893
---
.../modules/Bluetooth/android/app/Android.bp | 6 +-
.../Bluetooth/android/app/AndroidManifest.xml | 11 +-
.../drawable/bluetooth_dialog_background.xml | 5 +
.../bluetooth_dialog_button_background.xml | 15 +
.../bluetooth_dialog_cancel_background.xml | 15 +
.../bluetooth_dialog_confirm_background.xml | 15 +
.../drawable/receiver_progress_background.xml | 23 ++
.../app/res/drawable/selector_hide_narror.xml | 6 +
.../res/drawable/shape_rectangle_cancel.xml | 16 +
.../res/drawable/shape_rectangle_confirm.xml | 5 +
.../res/drawable/shape_rectangle_count.xml | 19 +
.../res/drawable/shape_transfer_cancel.xml | 16 +
.../res/layout/bluetooth_progress_adapter.xml | 62 +++
.../bluetooth_progress_dialog_header.xml | 48 +++
.../bluetooth_receiver_confirm_dialog.xml | 63 ++++
.../bluetooth_receiver_finish_dialog.xml | 41 ++
.../bluetooth_receiver_floating_button.xml | 23 ++
.../bluetooth_receiver_progress_dialog.xml | 215 +++++++++++
.../app/res/mipmap-xxxhdpi/bt_share.png | Bin 0 -> 14942 bytes
.../app/res/mipmap-xxxhdpi/delivery_nor.png | Bin 0 -> 4878 bytes
.../app/res/mipmap-xxxhdpi/delivery_pre.png | Bin 0 -> 6785 bytes
.../android/app/res/mipmap-xxxhdpi/fail.png | Bin 0 -> 1100 bytes
.../app/res/mipmap-xxxhdpi/ic_narrow_nor.png | Bin 0 -> 950 bytes
.../app/res/mipmap-xxxhdpi/ic_narrow_pre.png | Bin 0 -> 895 bytes
.../app/res/mipmap-xxxhdpi/success.png | Bin 0 -> 1363 bytes
.../android/app/res/values-zh-rCN/strings.xml | 25 ++
.../android/app/res/values/strings.xml | 28 ++
.../bluetooth/opp/BluetoothBaseUI.java | 43 +++
.../opp/BluetoothOppNotification.java | 176 +++++----
.../opp/BluetoothOppObexServerSession.java | 16 +-
.../bluetooth/opp/BluetoothOppReceiver.java | 27 +-
.../bluetooth/opp/BluetoothOppService.java | 54 +++
.../opp/BluetoothOppTransferActivity.java | 2 +-
.../opp/BluetoothOppTransferEntity.java | 31 ++
.../opp/BluetoothOppTransferHistory.java | 2 +
.../BluetoothOppTransferProgressAdapter.java | 87 +++++
.../bluetooth/opp/BluetoothOppUtility.java | 4 +
.../opp/BluetoothReceiverConfirmDialog.java | 71 ++++
.../opp/BluetoothReceiverFinishDialog.java | 61 +++
.../opp/BluetoothReceiverProgressDialog.java | 352 ++++++++++++++++++
.../com/android/bluetooth/opp/Constants.java | 2 +-
.../bluetooth/opp/NotifyDialogManager.java | 243 ++++++++++++
42 files changed, 1741 insertions(+), 87 deletions(-)
mode change 100644 => 100755 release/packages/modules/Bluetooth/android/app/Android.bp
mode change 100644 => 100755 release/packages/modules/Bluetooth/android/app/AndroidManifest.xml
create mode 100755 release/packages/modules/Bluetooth/android/app/res/drawable/bluetooth_dialog_background.xml
create mode 100755 release/packages/modules/Bluetooth/android/app/res/drawable/bluetooth_dialog_button_background.xml
create mode 100755 release/packages/modules/Bluetooth/android/app/res/drawable/bluetooth_dialog_cancel_background.xml
create mode 100755 release/packages/modules/Bluetooth/android/app/res/drawable/bluetooth_dialog_confirm_background.xml
create mode 100755 release/packages/modules/Bluetooth/android/app/res/drawable/receiver_progress_background.xml
create mode 100755 release/packages/modules/Bluetooth/android/app/res/drawable/selector_hide_narror.xml
create mode 100755 release/packages/modules/Bluetooth/android/app/res/drawable/shape_rectangle_cancel.xml
create mode 100755 release/packages/modules/Bluetooth/android/app/res/drawable/shape_rectangle_confirm.xml
create mode 100755 release/packages/modules/Bluetooth/android/app/res/drawable/shape_rectangle_count.xml
create mode 100755 release/packages/modules/Bluetooth/android/app/res/drawable/shape_transfer_cancel.xml
create mode 100755 release/packages/modules/Bluetooth/android/app/res/layout/bluetooth_progress_adapter.xml
create mode 100755 release/packages/modules/Bluetooth/android/app/res/layout/bluetooth_progress_dialog_header.xml
create mode 100755 release/packages/modules/Bluetooth/android/app/res/layout/bluetooth_receiver_confirm_dialog.xml
create mode 100755 release/packages/modules/Bluetooth/android/app/res/layout/bluetooth_receiver_finish_dialog.xml
create mode 100755 release/packages/modules/Bluetooth/android/app/res/layout/bluetooth_receiver_floating_button.xml
create mode 100755 release/packages/modules/Bluetooth/android/app/res/layout/bluetooth_receiver_progress_dialog.xml
create mode 100755 release/packages/modules/Bluetooth/android/app/res/mipmap-xxxhdpi/bt_share.png
create mode 100755 release/packages/modules/Bluetooth/android/app/res/mipmap-xxxhdpi/delivery_nor.png
create mode 100755 release/packages/modules/Bluetooth/android/app/res/mipmap-xxxhdpi/delivery_pre.png
create mode 100755 release/packages/modules/Bluetooth/android/app/res/mipmap-xxxhdpi/fail.png
create mode 100755 release/packages/modules/Bluetooth/android/app/res/mipmap-xxxhdpi/ic_narrow_nor.png
create mode 100755 release/packages/modules/Bluetooth/android/app/res/mipmap-xxxhdpi/ic_narrow_pre.png
create mode 100755 release/packages/modules/Bluetooth/android/app/res/mipmap-xxxhdpi/success.png
mode change 100644 => 100755 release/packages/modules/Bluetooth/android/app/res/values-zh-rCN/strings.xml
mode change 100644 => 100755 release/packages/modules/Bluetooth/android/app/res/values/strings.xml
create mode 100755 release/packages/modules/Bluetooth/android/app/src/com/android/bluetooth/opp/BluetoothBaseUI.java
mode change 100644 => 100755 release/packages/modules/Bluetooth/android/app/src/com/android/bluetooth/opp/BluetoothOppNotification.java
mode change 100644 => 100755 release/packages/modules/Bluetooth/android/app/src/com/android/bluetooth/opp/BluetoothOppObexServerSession.java
mode change 100644 => 100755 release/packages/modules/Bluetooth/android/app/src/com/android/bluetooth/opp/BluetoothOppReceiver.java
mode change 100644 => 100755 release/packages/modules/Bluetooth/android/app/src/com/android/bluetooth/opp/BluetoothOppService.java
mode change 100644 => 100755 release/packages/modules/Bluetooth/android/app/src/com/android/bluetooth/opp/BluetoothOppTransferActivity.java
create mode 100755 release/packages/modules/Bluetooth/android/app/src/com/android/bluetooth/opp/BluetoothOppTransferEntity.java
mode change 100644 => 100755 release/packages/modules/Bluetooth/android/app/src/com/android/bluetooth/opp/BluetoothOppTransferHistory.java
create mode 100755 release/packages/modules/Bluetooth/android/app/src/com/android/bluetooth/opp/BluetoothOppTransferProgressAdapter.java
mode change 100644 => 100755 release/packages/modules/Bluetooth/android/app/src/com/android/bluetooth/opp/BluetoothOppUtility.java
create mode 100755 release/packages/modules/Bluetooth/android/app/src/com/android/bluetooth/opp/BluetoothReceiverConfirmDialog.java
create mode 100755 release/packages/modules/Bluetooth/android/app/src/com/android/bluetooth/opp/BluetoothReceiverFinishDialog.java
create mode 100755 release/packages/modules/Bluetooth/android/app/src/com/android/bluetooth/opp/BluetoothReceiverProgressDialog.java
mode change 100644 => 100755 release/packages/modules/Bluetooth/android/app/src/com/android/bluetooth/opp/Constants.java
create mode 100755 release/packages/modules/Bluetooth/android/app/src/com/android/bluetooth/opp/NotifyDialogManager.java
diff --git a/release/packages/modules/Bluetooth/android/app/src/com/android/bluetooth/opp/BluetoothBaseUI.java b/release/packages/modules/Bluetooth/android/app/src/com/android/bluetooth/opp/BluetoothBaseUI.java
new file mode 100755
index 0000000000..f377d11763
--- /dev/null
+++ b/release/packages/modules/Bluetooth/android/app/src/com/android/bluetooth/opp/BluetoothBaseUI.java
@@ -0,0 +1,43 @@
+package com.android.bluetooth.opp;
+
+import android.app.NotificationManager;
+import android.content.Context;
+import android.view.LayoutInflater;
+import android.view.Window;
+import android.view.WindowManager;
+import android.widget.FrameLayout;
+import android.view.ViewTreeObserver;
+
+
+public abstract class BluetoothBaseUI extends FrameLayout {
+
+ protected boolean hide = false;
+
+ public BluetoothBaseUI(Context context) {
+ super(context);
+ LayoutInflater.from(context).inflate(getLayoutId(), this, true);
+ customInit();
+ }
+
+ abstract int getLayoutId();
+ abstract void customInit();
+
+ public void setInfo(final NotifyDialogManager ndm, NotifyDialogManager.Info info) {
+
+ }
+
+ public boolean isHide() {
+ return hide;
+ }
+
+ public void setHide(boolean _h) {
+ hide = _h;
+ }
+
+ public void update(NotifyDialogManager ndm, NotifyDialogManager.Info info) {
+ if (hide && getVisibility() == VISIBLE) setVisibility(GONE);
+ }
+
+ void onCancel() {}
+
+}
diff --git a/release/packages/modules/Bluetooth/android/app/src/com/android/bluetooth/opp/BluetoothOppNotification.java b/release/packages/modules/Bluetooth/android/app/src/com/android/bluetooth/opp/BluetoothOppNotification.java
old mode 100644
new mode 100755
index 44a9c1864b..25f15e5da3
--- a/release/packages/modules/Bluetooth/android/app/src/com/android/bluetooth/opp/BluetoothOppNotification.java
+++ b/release/packages/modules/Bluetooth/android/app/src/com/android/bluetooth/opp/BluetoothOppNotification.java
@@ -47,12 +47,19 @@ import android.os.Message;
import android.os.Process;
import android.text.format.Formatter;
import android.util.Log;
+import android.os.Build;
+import android.hardware.display.DisplayManager;
+import android.view.Display;
+import android.view.View;
import com.android.bluetooth.R;
import com.android.bluetooth.Utils;
import java.util.HashMap;
+import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
+
/**
* This class handles the updating of the Notification Manager for the cases
* where there is an ongoing transfer, incoming transfer need confirm and
@@ -147,6 +154,8 @@ class BluetoothOppNotification {
* @param ctx The context to use to obtain access to the Notification
* Service
*/
+ NotifyDialogManager mNotifyDialogManager;
+
BluetoothOppNotification(Context ctx) {
mContext = ctx;
mNotificationMgr = mContext.getSystemService(NotificationManager.class);
@@ -158,6 +167,18 @@ class BluetoothOppNotification {
mNotifications = new HashMap<String, NotificationItem>();
// Get Content Resolver object one time
mContentResolver = mContext.getContentResolver();
+
+ //mNotifyDialogManager = new NotifyDialogManager(ctx);
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
+ DisplayManager dm = mContext.getSystemService(DisplayManager.class);
+ Display primaryDisplay = dm.getDisplay(DEFAULT_DISPLAY);
+ Context windowContext =mContext.createDisplayContext(primaryDisplay)
+ .createWindowContext(TYPE_APPLICATION_OVERLAY, null);
+ mNotifyDialogManager = new NotifyDialogManager(windowContext);
+ } else {
+ mNotifyDialogManager = new NotifyDialogManager(ctx);
+ }
+
}
/**
@@ -168,13 +189,13 @@ class BluetoothOppNotification {
mPendingUpdate++;
if (mPendingUpdate > 1) {
if (V) {
- Log.v(TAG, "update too frequent, put in queue");
+ Log.v(TAG, "update too frequent, put in queue 22");
}
return;
}
if (!mHandler.hasMessages(NOTIFY)) {
if (V) {
- Log.v(TAG, "send message");
+ Log.v(TAG, "send message 22");
}
mHandler.sendMessage(mHandler.obtainMessage(NOTIFY));
}
@@ -298,6 +319,20 @@ class BluetoothOppNotification {
// NOTE: currently no such case
// Batch sending case
} else {
+
+ //load file
+ Log.v(TAG, "ACTION_INCOMING_FILE_CONFIRM ");
+ //Intent intent = new Intent(Constants.ACTION_INCOMING_FILE_CONFIRM);
+ //mContext.sendBroadcast(intent);
+
+ int[] state = getCurrentState();
+ NotifyDialogManager.Info rinfo = new NotifyDialogManager.Info();
+ rinfo.all = (int) total;
+ rinfo.done = (int) current;
+ rinfo.filename = fileName;
+ mNotifyDialogManager.notify(NotifyDialogManager.RECEIVER_PROGRESS_DIALOG, rinfo);
+
+ /**
NotificationItem item = new NotificationItem();
item.timeStamp = timeStamp;
item.id = id;
@@ -323,9 +358,12 @@ class BluetoothOppNotification {
Log.v(TAG, "ID=" + item.id + "; batchID=" + batchID + "; totoalCurrent"
+ item.totalCurrent + "; totalTotal=" + item.totalTotal);
}
+ **/
+
}
}
cursor.close();
+ /**
// Add the notifications
for (NotificationItem item : mNotifications.values()) {
@@ -394,9 +432,31 @@ class BluetoothOppNotification {
PendingIntent.FLAG_IMMUTABLE));
mNotificationMgr.notify(NOTIFICATION_ID_PROGRESS, b.build());
}
+ **/
}
private void updateCompletedNotification() {
+
+ if (mInitialState != null) {
+ int[] currentState = getCurrentState();
+ if (isStateChange(mInitialState, currentState)) {
+
+ NotifyDialogManager.Info sinfo = new NotifyDialogManager.Info();
+ // mNotifyDialogManager.cancel(NotifyDialogManager.RECEIVER_PROGRESS_DIALOG);
+ // mNotifyDialogManager.notify(NotifyDialogManager.RECEIVER_FINISH_DIALOG, sinfo);
+ }
+ }
+ }
+
+ int[] mInitialState;
+
+ private boolean isStateChange(int[] state1, int[] state2) {
+ for (int i = 0; i < state1.length; i++) {
+ if (state1[i] != state2[i]) return false;
+ }
+ return true;
+ }
+ private int[] getCurrentState() {
long timeStamp = 0;
int outboundSuccNumber = 0;
int outboundFailNumber = 0;
@@ -404,13 +464,14 @@ class BluetoothOppNotification {
int inboundNum;
int inboundSuccNumber = 0;
int inboundFailNumber = 0;
+ int[] state = new int[6];
// Creating outbound notification
Cursor cursor =
mContentResolver.query(BluetoothShare.CONTENT_URI, null, WHERE_COMPLETED_OUTBOUND,
null, BluetoothShare.TIMESTAMP + " DESC");
if (cursor == null) {
- return;
+ return state;
}
final int timestampIndex = cursor.getColumnIndexOrThrow(BluetoothShare.TIMESTAMP);
@@ -435,49 +496,15 @@ class BluetoothOppNotification {
cursor.close();
outboundNum = outboundSuccNumber + outboundFailNumber;
- // create the outbound notification
- if (outboundNum > 0) {
- String caption = BluetoothOppUtility.formatResultText(outboundSuccNumber,
- outboundFailNumber, mContext);
- Intent contentIntent = new Intent(Constants.ACTION_OPEN_OUTBOUND_TRANSFER).setClassName(
- mContext, BluetoothOppReceiver.class.getName());
- Intent deleteIntent = new Intent(Constants.ACTION_COMPLETE_HIDE).setClassName(
- mContext, BluetoothOppReceiver.class.getName());
- Notification outNoti =
- new Notification.Builder(mContext, OPP_NOTIFICATION_CHANNEL).setOnlyAlertOnce(
- true)
- .setContentTitle(mContext.getString(R.string.outbound_noti_title))
- .setContentText(caption)
- .setSmallIcon(android.R.drawable.stat_sys_upload_done)
- .setColor(mContext.getResources()
- .getColor(
- android.R.color
- .system_notification_accent_color,
- mContext.getTheme()))
- .setContentIntent(
- PendingIntent.getBroadcast(mContext, 0, contentIntent,
- PendingIntent.FLAG_IMMUTABLE))
- .setDeleteIntent(
- PendingIntent.getBroadcast(mContext, 0, deleteIntent,
- PendingIntent.FLAG_IMMUTABLE))
- .setWhen(timeStamp)
- .setLocalOnly(true)
- .build();
- mNotificationMgr.notify(NOTIFICATION_ID_OUTBOUND_COMPLETE, outNoti);
- } else {
- if (mNotificationMgr != null) {
- mNotificationMgr.cancel(NOTIFICATION_ID_OUTBOUND_COMPLETE);
- if (V) {
- Log.v(TAG, "outbound notification was removed.");
- }
- }
- }
+ state[0] = outboundSuccNumber;
+ state[1] = outboundFailNumber;
+ state[2] = outboundNum;
// Creating inbound notification
cursor = mContentResolver.query(BluetoothShare.CONTENT_URI, null, WHERE_COMPLETED_INBOUND,
null, BluetoothShare.TIMESTAMP + " DESC");
if (cursor == null) {
- return;
+ return state;
}
for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) {
@@ -499,44 +526,10 @@ class BluetoothOppNotification {
cursor.close();
inboundNum = inboundSuccNumber + inboundFailNumber;
- // create the inbound notification
- if (inboundNum > 0) {
- String caption = BluetoothOppUtility.formatResultText(inboundSuccNumber,
- inboundFailNumber, mContext);
- Intent contentIntent = new Intent(Constants.ACTION_OPEN_INBOUND_TRANSFER).setClassName(
- mContext, BluetoothOppReceiver.class.getName());
- Intent deleteIntent = new Intent(Constants.ACTION_COMPLETE_HIDE).setClassName(
- mContext, BluetoothOppReceiver.class.getName());
- Notification inNoti =
- new Notification.Builder(mContext, OPP_NOTIFICATION_CHANNEL).setOnlyAlertOnce(
- true)
- .setContentTitle(mContext.getString(R.string.inbound_noti_title))
- .setContentText(caption)
- .setSmallIcon(android.R.drawable.stat_sys_download_done)
- .setColor(mContext.getResources()
- .getColor(
- android.R.color
- .system_notification_accent_color,
- mContext.getTheme()))
-
- .setContentIntent(
- PendingIntent.getBroadcast(mContext, 0, contentIntent,
- PendingIntent.FLAG_IMMUTABLE))
- .setDeleteIntent(
- PendingIntent.getBroadcast(mContext, 0, deleteIntent,
- PendingIntent.FLAG_IMMUTABLE))
- .setWhen(timeStamp)
- .setLocalOnly(true)
- .build();
- mNotificationMgr.notify(NOTIFICATION_ID_INBOUND_COMPLETE, inNoti);
- } else {
- if (mNotificationMgr != null) {
- mNotificationMgr.cancel(NOTIFICATION_ID_INBOUND_COMPLETE);
- if (V) {
- Log.v(TAG, "inbound notification was removed.");
- }
- }
- }
+ state[3] = inboundSuccNumber;
+ state[4] = inboundFailNumber;
+ state[5] = inboundNum;
+ return state;
}
private void updateIncomingFileConfirmNotification() {
@@ -556,6 +549,30 @@ class BluetoothOppNotification {
Intent baseIntent = new Intent().setDataAndNormalize(contentUri)
.setClassName(mContext,
BluetoothOppReceiver.class.getName());
+
+ NotifyDialogManager.Info sinfo = new NotifyDialogManager.Info();
+ sinfo.filename = info.mFileName;
+ sinfo.cancel = new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ mContext.sendBroadcast(new Intent(baseIntent).setAction(Constants.ACTION_DECLINE));
+ mNotifyDialogManager.cancel(NotifyDialogManager.RECEIVER_CONFIRM_DIALOG);
+ }
+ };
+
+ sinfo.confirm = new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ mContext.sendBroadcast(new Intent(baseIntent).setAction(Constants.ACTION_ACCEPT));
+ mNotifyDialogManager.cancel(NotifyDialogManager.RECEIVER_CONFIRM_DIALOG);
+ }
+ };
+ mNotifyDialogManager.setDeviceName(info.mDeviceName);
+ mNotifyDialogManager.notify(NotifyDialogManager.RECEIVER_CONFIRM_DIALOG, sinfo);
+ mInitialState = getCurrentState();
+ break;
+
+ /**
Notification.Action actionDecline =
new Notification.Action.Builder(Icon.createWithResource(mContext,
R.drawable.ic_decline),
@@ -628,6 +645,7 @@ class BluetoothOppNotification {
.setPublicVersion(public_n)
.build();
mNotificationMgr.notify(NOTIFICATION_ID_PROGRESS, n);
+ **/
}
cursor.close();
}
diff --git a/release/packages/modules/Bluetooth/android/app/src/com/android/bluetooth/opp/BluetoothOppObexServerSession.java b/release/packages/modules/Bluetooth/android/app/src/com/android/bluetooth/opp/BluetoothOppObexServerSession.java
old mode 100644
new mode 100755
index 6520f512e3..4931632b2b
--- a/release/packages/modules/Bluetooth/android/app/src/com/android/bluetooth/opp/BluetoothOppObexServerSession.java
+++ b/release/packages/modules/Bluetooth/android/app/src/com/android/bluetooth/opp/BluetoothOppObexServerSession.java
@@ -60,6 +60,7 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Arrays;
+import androidx.localbroadcastmanager.content.LocalBroadcastManager;
/**
* This class runs as an OBEX server
@@ -302,6 +303,9 @@ public class BluetoothOppObexServerSession extends ServerRequestHandler
try {
while (mServerBlocking) {
+ if (V) {
+ Log.v(TAG, "mServerBlocking wait");
+ }
wait(1000);
if (mCallback != null && !mTimeoutMsgSent) {
mCallback.sendMessageDelayed(mCallback.obtainMessage(
@@ -408,9 +412,12 @@ public class BluetoothOppObexServerSession extends ServerRequestHandler
if (mFileInfo.mInsertUri != null) {
mContext.getContentResolver().delete(mFileInfo.mInsertUri, null, null);
}
+
+ Intent is = new Intent(NotifyDialogManager.ACTION_CANCEL_CONFIRM_DIALOG);
+ notifyDialogManager(is);
// set status as local cancel
status = BluetoothShare.STATUS_CANCELED;
- Constants.updateShareStatus(mContext, mInfo.mId, status);
+ //Constants.updateShareStatus(mContext, mInfo.mId, status);
obexResponse = ResponseCodes.OBEX_HTTP_FORBIDDEN;
Message msg = Message.obtain(mCallback);
@@ -422,6 +429,10 @@ public class BluetoothOppObexServerSession extends ServerRequestHandler
return obexResponse;
}
+ private void notifyDialogManager(Intent intent) {
+ LocalBroadcastManager.getInstance(mContext).sendBroadcast(intent);
+ }
+
private int receiveFile(BluetoothOppReceiveFileInfo fileInfo, Operation op) {
/*
* implement receive file
@@ -610,6 +621,9 @@ public class BluetoothOppObexServerSession extends ServerRequestHandler
}
mTimestamp = System.currentTimeMillis();
mNumFilesAttemptedToReceive = 0;
+ BluetoothReceiverProgressDialog.globalSurplus = objectCount != null ? objectCount : 1L;
+ BluetoothReceiverProgressDialog.isSend = false;
+ Log.v(TAG, "onConnect(): objectCount =" + objectCount);
return ResponseCodes.OBEX_HTTP_OK;
}
diff --git a/release/packages/modules/Bluetooth/android/app/src/com/android/bluetooth/opp/BluetoothOppReceiver.java b/release/packages/modules/Bluetooth/android/app/src/com/android/bluetooth/opp/BluetoothOppReceiver.java
old mode 100644
new mode 100755
index 3540c4d716..cae6b8784e
--- a/release/packages/modules/Bluetooth/android/app/src/com/android/bluetooth/opp/BluetoothOppReceiver.java
+++ b/release/packages/modules/Bluetooth/android/app/src/com/android/bluetooth/opp/BluetoothOppReceiver.java
@@ -44,6 +44,8 @@ import android.net.Uri;
import android.util.Log;
import android.widget.Toast;
+import androidx.localbroadcastmanager.content.LocalBroadcastManager;
+
import com.android.bluetooth.R;
import com.android.bluetooth.Utils;
@@ -56,12 +58,15 @@ public class BluetoothOppReceiver extends BroadcastReceiver {
private static final boolean D = Constants.DEBUG;
private static final boolean V = Constants.VERBOSE;
+ Context mContext;
+
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (D) Log.d(TAG, " action :" + action);
+ mContext = context;
if (action == null) return;
- if (action.equals(BluetoothDevicePicker.ACTION_DEVICE_SELECTED)) {
+ if (action.equals(BluetoothDevicePicker.ACTION_DEVICE_SELECTED) || action.equals("com.skg.filemanager.devicepicker.action.DEVICE_SELECTED")) {
BluetoothOppManager mOppManager = BluetoothOppManager.getInstance(context);
BluetoothDevice remoteDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
@@ -255,27 +260,39 @@ public class BluetoothOppReceiver extends BroadcastReceiver {
}
if (BluetoothShare.isStatusSuccess(transInfo.mStatus)) {
+ Intent is = new Intent(NotifyDialogManager.ACTION_RECEIVER_SUCCEED);
+ is.putExtra("fileName", transInfo.mFileName);
+ is.putExtra("fileType", transInfo.mFileType);
+ notifyDialogManager(is);
+ /**
if (transInfo.mDirection == BluetoothShare.DIRECTION_OUTBOUND) {
toastMsg = context.getString(R.string.notification_sent, transInfo.mFileName);
} else if (transInfo.mDirection == BluetoothShare.DIRECTION_INBOUND) {
toastMsg =
context.getString(R.string.notification_received, transInfo.mFileName);
}
+ **/
} else if (BluetoothShare.isStatusError(transInfo.mStatus)) {
+ Intent is = new Intent(NotifyDialogManager.ACTION_RECEIVER_FAILED);
+ is.putExtra("fileName", transInfo.mFileName);
+ is.putExtra("fileType", transInfo.mFileType);
+ notifyDialogManager(is);
+ /**
if (transInfo.mDirection == BluetoothShare.DIRECTION_OUTBOUND) {
toastMsg =
context.getString(R.string.notification_sent_fail, transInfo.mFileName);
} else if (transInfo.mDirection == BluetoothShare.DIRECTION_INBOUND) {
toastMsg = context.getString(R.string.download_fail_line1);
}
+ **/
}
if (V) {
Log.v(TAG, "Toast msg == " + toastMsg);
}
- if (toastMsg != null) {
+ /** if (toastMsg != null) {
Toast.makeText(context, toastMsg, Toast.LENGTH_SHORT).show();
- }
+ } **/
}
}
@@ -289,4 +306,8 @@ public class BluetoothOppReceiver extends BroadcastReceiver {
Log.v(TAG, "notMgr.cancel called");
}
}
+
+ private void notifyDialogManager(Intent intent) {
+ LocalBroadcastManager.getInstance(mContext).sendBroadcast(intent);
+ }
}
diff --git a/release/packages/modules/Bluetooth/android/app/src/com/android/bluetooth/opp/BluetoothOppService.java b/release/packages/modules/Bluetooth/android/app/src/com/android/bluetooth/opp/BluetoothOppService.java
old mode 100644
new mode 100755
index 27bfe509c3..28bbc94342
--- a/release/packages/modules/Bluetooth/android/app/src/com/android/bluetooth/opp/BluetoothOppService.java
+++ b/release/packages/modules/Bluetooth/android/app/src/com/android/bluetooth/opp/BluetoothOppService.java
@@ -214,6 +214,26 @@ public class BluetoothOppService extends ProfileService implements IObexConnecti
}
}
+ static final String ACTION_BLUETOOTH_TRANSFER_STOP = "com.skg.bluetooth.transfer.stop";
+
+ private final BroadcastReceiver stopTransferReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ Log.i(TAG + "20210104", "receiver transfer stop" + action);
+ if (action.equals(ACTION_BLUETOOTH_TRANSFER_STOP)) {
+ if (mTransfer != null) {
+ Log.i(TAG + "20210104", "stop operation");
+ mTransfer.stop();
+ }
+ if (mServerTransfer != null) {
+ Log.i(TAG + "20210104", "stop operation");
+ mServerTransfer.stop();
+ }
+ }
+ }
+ };
+
@Override
protected void create() {
if (V) {
@@ -226,6 +246,9 @@ public class BluetoothOppService extends ProfileService implements IObexConnecti
IntentFilter filter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);
registerReceiver(mBluetoothReceiver, filter);
+ IntentFilter stopFilter = new IntentFilter();
+ stopFilter.addAction(ACTION_BLUETOOTH_TRANSFER_STOP);
+ registerReceiver(stopTransferReceiver, stopFilter);
if (V) {
BluetoothOppPreference preference = BluetoothOppPreference.getInstance(this);
if (preference != null) {
@@ -546,6 +569,7 @@ public class BluetoothOppService extends ProfileService implements IObexConnecti
mObserver = null;
}
unregisterReceiver(mBluetoothReceiver);
+ unregisterReceiver(stopTransferReceiver);
} catch (IllegalArgumentException e) {
Log.w(TAG, "unregisterReceivers " + e.toString());
}
@@ -699,6 +723,9 @@ public class BluetoothOppService extends ProfileService implements IObexConnecti
}
}
+ if (shouldScanFile(arrayPos)) {
+ scanFile(arrayPos);
+ }
deleteShare(arrayPos); // this advances in the array
} else {
int id = cursor.getInt(idColumn);
@@ -722,6 +749,9 @@ public class BluetoothOppService extends ProfileService implements IObexConnecti
Log.v(TAG,
"Array update: removing " + arrayId + " @ " + arrayPos);
}
+ if (shouldScanFile(arrayPos)) {
+ scanFile(arrayPos);
+ }
deleteShare(arrayPos);
} else if (arrayId == id) {
// This cursor row already exists in the stored array.
@@ -1094,6 +1124,30 @@ public class BluetoothOppService extends ProfileService implements IObexConnecti
}
}
+
+ private boolean scanFile(int arrayPos) {
+ BluetoothOppShareInfo info = mShares.get(arrayPos);
+ synchronized (BluetoothOppService.this) {
+ if (D) {
+ Log.d(TAG, "Scanning file " + info.mFilename);
+ }
+ if (!mMediaScanInProgress) {
+ mMediaScanInProgress = true;
+ new MediaScannerNotifier(this, info, mHandler);
+ return true;
+ } else {
+ return false;
+ }
+ }
+ }
+
+ private boolean shouldScanFile(int arrayPos) {
+ BluetoothOppShareInfo info = mShares.get(arrayPos);
+ return BluetoothShare.isStatusSuccess(info.mStatus)
+ && info.mDirection == BluetoothShare.DIRECTION_INBOUND && !info.mMediaScanned
+ && info.mConfirm != BluetoothShare.USER_CONFIRMATION_HANDOVER_CONFIRMED;
+ }
+
private void scanFileIfNeeded(int arrayPos) {
BluetoothOppShareInfo info = mShares.get(arrayPos);
boolean isFileReceived = BluetoothShare.isStatusSuccess(info.mStatus)
diff --git a/release/packages/modules/Bluetooth/android/app/src/com/android/bluetooth/opp/BluetoothOppTransferActivity.java b/release/packages/modules/Bluetooth/android/app/src/com/android/bluetooth/opp/BluetoothOppTransferActivity.java
old mode 100644
new mode 100755
index bba67586f2..aaab70a0bc
--- a/release/packages/modules/Bluetooth/android/app/src/com/android/bluetooth/opp/BluetoothOppTransferActivity.java
+++ b/release/packages/modules/Bluetooth/android/app/src/com/android/bluetooth/opp/BluetoothOppTransferActivity.java
@@ -135,7 +135,7 @@ public class BluetoothOppTransferActivity extends AlertActivity
getWindow().addSystemFlags(SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
Intent intent = getIntent();
mUri = intent.getData();
-
+ Log.v(TAG, "onCreate lwz mUri = " + mUri);
mTransInfo = new BluetoothOppTransferInfo();
mTransInfo = BluetoothOppUtility.queryRecord(this, mUri);
if (mTransInfo == null) {
diff --git a/release/packages/modules/Bluetooth/android/app/src/com/android/bluetooth/opp/BluetoothOppTransferEntity.java b/release/packages/modules/Bluetooth/android/app/src/com/android/bluetooth/opp/BluetoothOppTransferEntity.java
new file mode 100755
index 0000000000..33866e5228
--- /dev/null
+++ b/release/packages/modules/Bluetooth/android/app/src/com/android/bluetooth/opp/BluetoothOppTransferEntity.java
@@ -0,0 +1,31 @@
+package com.android.bluetooth.opp;
+
+public class BluetoothOppTransferEntity {
+ String name;
+ String size;
+ Boolean result;
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getSize() {
+ return size;
+ }
+
+ public void setSize(String size) {
+ this.size = size;
+ }
+
+ public Boolean getResult() {
+ return result;
+ }
+
+ public void setResult(Boolean result) {
+ this.result = result;
+ }
+}
diff --git a/release/packages/modules/Bluetooth/android/app/src/com/android/bluetooth/opp/BluetoothOppTransferHistory.java b/release/packages/modules/Bluetooth/android/app/src/com/android/bluetooth/opp/BluetoothOppTransferHistory.java
old mode 100644
new mode 100755
index e4f978d83b..fd37077826
--- a/release/packages/modules/Bluetooth/android/app/src/com/android/bluetooth/opp/BluetoothOppTransferHistory.java
+++ b/release/packages/modules/Bluetooth/android/app/src/com/android/bluetooth/opp/BluetoothOppTransferHistory.java
@@ -317,10 +317,12 @@ public class BluetoothOppTransferHistory extends Activity
if (transInfo.mDirection == BluetoothShare.DIRECTION_INBOUND
&& BluetoothShare.isStatusSuccess(transInfo.mStatus)) {
// if received file successfully, open this file
+ Log.i(TAG, "lwz DIRECTION_INBOUND");
BluetoothOppUtility.updateVisibilityToHidden(this, contentUri);
BluetoothOppUtility.openReceivedFile(this, transInfo.mFileName, transInfo.mFileType,
transInfo.mTimeStamp, contentUri);
} else {
+ Log.i(TAG, "lwz startActivity");
Intent in = new Intent(this, BluetoothOppTransferActivity.class);
in.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
in.setDataAndNormalize(contentUri);
diff --git a/release/packages/modules/Bluetooth/android/app/src/com/android/bluetooth/opp/BluetoothOppTransferProgressAdapter.java b/release/packages/modules/Bluetooth/android/app/src/com/android/bluetooth/opp/BluetoothOppTransferProgressAdapter.java
new file mode 100755
index 0000000000..43c2730e46
--- /dev/null
+++ b/release/packages/modules/Bluetooth/android/app/src/com/android/bluetooth/opp/BluetoothOppTransferProgressAdapter.java
@@ -0,0 +1,87 @@
+package com.android.bluetooth.opp;
+
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.recyclerview.widget.RecyclerView;
+import androidx.recyclerview.widget.RecyclerView.Adapter;
+
+import java.util.List;
+
+import com.android.bluetooth.R;
+
+public class BluetoothOppTransferProgressAdapter extends Adapter<BluetoothOppTransferProgressAdapter.ViewHolder> {
+ private List<BluetoothOppTransferEntity> bluetoothOppTransferEntityList;
+
+ public BluetoothOppTransferProgressAdapter(List<BluetoothOppTransferEntity> list) {
+ this.bluetoothOppTransferEntityList = list;
+ }
+ @Override
+ public int getItemViewType(int position) {
+ if (position == 0) {
+ return 0;
+ } else {
+ return position;
+ }
+ }
+
+ @NonNull
+ @Override
+ public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
+ View view;
+// if (viewType == 0) {
+// view = LayoutInflater.from(parent.getContext()).inflate(R.layout.bluetooth_progress_dialog_header, parent, false);
+// } else {
+// view = LayoutInflater.from(parent.getContext()).inflate(R.layout.bluetooth_progress_adapter, parent, false);
+// }
+ view = LayoutInflater.from(parent.getContext()).inflate(R.layout.bluetooth_progress_adapter, parent, false);
+ ViewHolder holder = new ViewHolder(view);
+ return holder;
+ }
+
+ @Override
+ public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
+ BluetoothOppTransferEntity entity = bluetoothOppTransferEntityList.get(position);
+ String[] names = entity.getName().split("/");
+ holder.name.setText(names[names.length - 1]);
+ holder.size.setText(entity.getSize());
+ if (entity.getResult()) {
+ if (BluetoothReceiverProgressDialog.isSend) {
+ holder.result.setText(R.string.bluetooth_opp_send_success);
+ } else {
+ holder.result.setText(R.string.bluetooth_opp_receiver_success);
+ }
+ holder.icon.setImageResource(R.mipmap.success);
+ } else {
+ if (BluetoothReceiverProgressDialog.isSend) {
+ holder.result.setText(R.string.bluetooth_opp_send_failed);
+ } else {
+ holder.result.setText(R.string.bluetooth_opp_receiver_failed);
+ }
+ holder.icon.setImageResource(R.mipmap.fail);
+ }
+ }
+
+ @Override
+ public int getItemCount() {
+ return bluetoothOppTransferEntityList.size();
+ }
+
+ class ViewHolder extends RecyclerView.ViewHolder {
+ TextView name;
+ TextView size;
+ ImageView icon;
+ TextView result;
+ public ViewHolder(View itemView) {
+ super(itemView);
+ name = itemView.findViewById(R.id.tvName);
+ size = itemView.findViewById(R.id.tvSize);
+ icon = itemView.findViewById(R.id.ivIcon);
+ result = itemView.findViewById(R.id.tvResult);
+ }
+ }
+}
diff --git a/release/packages/modules/Bluetooth/android/app/src/com/android/bluetooth/opp/BluetoothOppUtility.java b/release/packages/modules/Bluetooth/android/app/src/com/android/bluetooth/opp/BluetoothOppUtility.java
old mode 100644
new mode 100755
index f1f1faa2c3..0395578ade
--- a/release/packages/modules/Bluetooth/android/app/src/com/android/bluetooth/opp/BluetoothOppUtility.java
+++ b/release/packages/modules/Bluetooth/android/app/src/com/android/bluetooth/opp/BluetoothOppUtility.java
@@ -189,6 +189,8 @@ public class BluetoothOppUtility {
*/
public static void openReceivedFile(Context context, String fileName, String mimetype,
Long timeStamp, Uri uri) {
+ Log.i(TAG, "lwz openReceivedFile fileName = " + fileName + " ,mimetype = " + mimetype );
+ Log.i(TAG, "lwz openReceivedFile uri = " + uri);
if (fileName == null || mimetype == null) {
Log.e(TAG, "ERROR: Para fileName ==null, or mimetype == null");
return;
@@ -198,6 +200,8 @@ public class BluetoothOppUtility {
Log.e(TAG, "Trying to open a file that wasn't transfered over Bluetooth");
return;
}
+ File f = new File(fileName);
+ Log.i(TAG, "lwz openReceivedFile f.exists() = " + f.exists());
Uri path = null;
Cursor metadataCursor = context.getContentResolver().query(uri, new String[]{
diff --git a/release/packages/modules/Bluetooth/android/app/src/com/android/bluetooth/opp/BluetoothReceiverConfirmDialog.java b/release/packages/modules/Bluetooth/android/app/src/com/android/bluetooth/opp/BluetoothReceiverConfirmDialog.java
new file mode 100755
index 0000000000..05d6efbf8b
--- /dev/null
+++ b/release/packages/modules/Bluetooth/android/app/src/com/android/bluetooth/opp/BluetoothReceiverConfirmDialog.java
@@ -0,0 +1,71 @@
+package com.android.bluetooth.opp;
+
+import android.annotation.SuppressLint;
+import android.app.NotificationManager;
+import android.content.Context;
+import android.graphics.PixelFormat;
+import android.util.Log;
+import android.view.Gravity;
+import android.view.WindowManager;
+import android.widget.TextView;
+
+import com.android.bluetooth.R;
+
+@SuppressLint("ViewConstructor")
+public class BluetoothReceiverConfirmDialog extends BluetoothBaseUI {
+
+
+ public BluetoothReceiverConfirmDialog(Context context) {
+ super(context);
+ }
+
+ private String deviceName;
+
+ public void setDeviceName(String deviceName) {
+ this.deviceName = deviceName;
+ }
+
+ @Override
+ int getLayoutId() {
+ return R.layout.bluetooth_receiver_confirm_dialog;
+ }
+
+ TextView tvMessage, tvConfirm, tvCancel;
+
+ @Override
+ void customInit() {
+ tvMessage = findViewById(R.id.tvMessage);
+ tvConfirm = findViewById(R.id.tvConfirm);
+ tvCancel = findViewById(R.id.tvCancel);
+ }
+
+ @Override
+ public void setInfo(NotifyDialogManager ndm, NotifyDialogManager.Info info) {
+ super.setInfo(ndm, info);
+ tvMessage.setText(getResources().getString(R.string.bluetooth_receiver_confirm_dialog_accept) + deviceName
+ + getResources().getString(R.string.bluetooth_receiver_confirm_dialog_file) + info.filename + " ?");
+ tvCancel.setOnClickListener(info.cancel);
+ tvConfirm.setOnClickListener(info.confirm);
+ }
+
+
+ public static WindowManager.LayoutParams createLayoutParams() {
+ WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams();
+ layoutParams.gravity = Gravity.CENTER;
+ layoutParams.height = android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
+ layoutParams.width = 800;
+ layoutParams.format = PixelFormat.TRANSLUCENT;
+ layoutParams.x = 50;
+ layoutParams.y = 50;
+ layoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
+ layoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
+ return layoutParams;
+ }
+
+ @Override
+ public void update(NotifyDialogManager ndm, NotifyDialogManager.Info info) {
+
+ }
+
+
+}
diff --git a/release/packages/modules/Bluetooth/android/app/src/com/android/bluetooth/opp/BluetoothReceiverFinishDialog.java b/release/packages/modules/Bluetooth/android/app/src/com/android/bluetooth/opp/BluetoothReceiverFinishDialog.java
new file mode 100755
index 0000000000..0c3d1bc026
--- /dev/null
+++ b/release/packages/modules/Bluetooth/android/app/src/com/android/bluetooth/opp/BluetoothReceiverFinishDialog.java
@@ -0,0 +1,61 @@
+package com.android.bluetooth.opp;
+
+import android.content.Context;
+import android.graphics.PixelFormat;
+import android.view.Gravity;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.widget.ProgressBar;
+import android.widget.TextView;
+
+import com.android.bluetooth.R;
+
+public class BluetoothReceiverFinishDialog extends BluetoothBaseUI {
+
+ public BluetoothReceiverFinishDialog(Context context) {
+ super(context);
+ }
+
+ @Override
+ int getLayoutId() {
+ return R.layout.bluetooth_receiver_finish_dialog;
+ }
+
+ TextView tvReceiverResult, tvOperation;
+
+ @Override
+ void customInit() {
+ tvReceiverResult = findViewById(R.id.tvReceiverResult);
+ tvOperation = findViewById(R.id.tvOperation);
+ }
+
+
+ @Override
+ public void setInfo(final NotifyDialogManager ndm, NotifyDialogManager.Info info) {
+ super.setInfo(ndm, info);
+ tvReceiverResult.setText(String.format("Receive (%s) %s", info.filename,
+ info.receiverSucceed ? " success": "failed"));
+ tvOperation.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ ndm.cancel(NotifyDialogManager.RECEIVER_FINISH_DIALOG);
+ }
+ });
+ }
+
+
+ public static WindowManager.LayoutParams createLayoutParams() {
+ WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams();
+ layoutParams.gravity = Gravity.CENTER | Gravity.TOP;
+ layoutParams.height = android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
+ layoutParams.width = 500;
+ layoutParams.format = PixelFormat.TRANSLUCENT;
+ layoutParams.y = 30;
+ layoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
+ layoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
+ return layoutParams;
+ }
+
+
+}
diff --git a/release/packages/modules/Bluetooth/android/app/src/com/android/bluetooth/opp/BluetoothReceiverProgressDialog.java b/release/packages/modules/Bluetooth/android/app/src/com/android/bluetooth/opp/BluetoothReceiverProgressDialog.java
new file mode 100755
index 0000000000..83a36a03c5
--- /dev/null
+++ b/release/packages/modules/Bluetooth/android/app/src/com/android/bluetooth/opp/BluetoothReceiverProgressDialog.java
@@ -0,0 +1,352 @@
+package com.android.bluetooth.opp;
+
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.PixelFormat;
+import android.text.TextUtils;
+import android.text.Html;
+import android.util.DisplayMetrics;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.widget.Button;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.ProgressBar;
+import android.widget.TextView;
+import android.view.View;
+import com.android.bluetooth.R;
+import android.util.Log;
+import android.os.Build;
+import android.hardware.display.DisplayManager;
+import android.view.Display;
+
+import com.android.bluetooth.R;
+
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.List;
+
+import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
+
+public class BluetoothReceiverProgressDialog extends BluetoothBaseUI {
+ String TAG = "BluetoothReceiverProgressDialog";
+ public interface Callback {
+ void sendSuccess();
+ void sendFail();
+ void receiveSuccess();
+ void receiveFail();
+ }
+
+ private Callback callback;
+
+ public void setCallback(Callback callback) {
+ this.callback = callback;
+ }
+
+ private WindowManager wm;
+ public BluetoothReceiverProgressDialog(Context context) {
+ super(context);
+ transferComplete = false;
+ }
+
+ @Override
+ int getLayoutId() {
+ return R.layout.bluetooth_receiver_progress_dialog;
+ }
+
+ NotifyDialogManager.Info info;
+
+ TextView tvFileName, tvFileSize, tvCancelTransfer, tvTitle;
+ ImageView tvHide;
+ ProgressBar pbProgress;
+ private LinearLayout llCurrentFile, llLoadingCount;
+
+ private RecyclerView rvTransferFile;
+ private BluetoothOppTransferProgressAdapter bluetoothOppTransferProgressAdapter;
+ private List<BluetoothOppTransferEntity> bluetoothOppTransferEntityList;
+
+ @Override
+ void customInit() {
+ wm = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
+ tvTitle = findViewById(R.id.tvTitle);
+ if (isSend) {
+ tvTitle.setText(R.string.bluetooth_opp_send_file);
+ } else {
+ tvTitle.setText(R.string.bluetooth_opp_receive_file);
+ }
+ tvFileName = findViewById(R.id.tvFileName);
+ tvFileSize = findViewById(R.id.tvFileSize);
+ tvHide = findViewById(R.id.tvHide);
+ pbProgress = findViewById(R.id.pbProgress);
+ llLoadingCount = findViewById(R.id.llLoadingCount);
+ llCurrentFile = findViewById(R.id.llCurrentFile);
+
+ btnReceiverFloating = LayoutInflater.from(getContext()).inflate(R.layout.bluetooth_receiver_floating_button, null);
+ tvFileCount = btnReceiverFloating.findViewById(R.id.tvCount);
+
+ //RecyclerView
+ rvTransferFile = findViewById(R.id.rvTransferFile);
+ bluetoothOppTransferEntityList = new ArrayList<>();
+// bluetoothOppTransferEntityList.add(new BluetoothOppTransferEntity());
+ bluetoothOppTransferProgressAdapter = new BluetoothOppTransferProgressAdapter((bluetoothOppTransferEntityList));
+ rvTransferFile.setAdapter(bluetoothOppTransferProgressAdapter);
+ LinearLayoutManager layoutManager = new LinearLayoutManager(getContext());
+ rvTransferFile.setLayoutManager(layoutManager);
+
+ updateTipCount();
+ setViewListener();
+ }
+
+ private void updateTipCount() {
+ View view = LayoutInflater.from(getContext()).inflate(R.layout.bluetooth_receiver_progress_dialog, null);
+ if (globalSurplus <= 1) {
+ llLoadingCount.setVisibility(View.GONE);
+ } else {
+ llLoadingCount.setVisibility(View.VISIBLE);
+ tvSurplus = llLoadingCount.findViewById(R.id.tvLoadingCount);
+ tvSurplus.setText(String.format("%d", globalSurplus - 1));
+ }
+ tvFileCount.setText(globalSurplus.toString());
+ }
+
+ private void setViewListener() {
+ btnDone = findViewById(R.id.btnDone);
+ tvCancelTransfer = findViewById(R.id.tvCancelTransfer);
+ }
+
+ private final View.OnClickListener receiverFloatingBtnListener = new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ setVisibility(View.VISIBLE);
+ btnReceiverFloating.setVisibility(View.GONE);
+ }
+ };
+
+ private final View.OnClickListener cancelTransferListener = new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ Log.i(TAG, "stop broadcast " + BluetoothOppService.ACTION_BLUETOOTH_TRANSFER_STOP);
+ //取消接收或发送
+ Intent intent = new Intent();
+ intent.setAction(BluetoothOppService.ACTION_BLUETOOTH_TRANSFER_STOP);
+ getContext().sendBroadcast(intent);
+ }
+ };
+
+ private View.OnClickListener doneListener;
+
+ public void setDoneListener(View.OnClickListener listener) {
+ if (doneListener == null) {
+ this.doneListener = listener;
+ }
+ }
+
+ private boolean isTouch;
+
+ private final View.OnTouchListener receiverFloatingBtnTouchListener = new View.OnTouchListener() {
+ private float rawX,rawY;
+ @Override
+ public boolean onTouch(View v, MotionEvent event) {
+ switch (event.getAction()){
+ case MotionEvent.ACTION_DOWN:
+ isTouch = false;
+ int[] viewLocation=new int[2];
+ btnReceiverFloating.getLocationOnScreen(viewLocation);
+ rawX=event.getRawX();
+ rawY=event.getRawY();
+ if (!(rawX>viewLocation[0]&&rawX<viewLocation[0]+btnReceiverFloating.getWidth()&&rawY>viewLocation[1]&&rawY<viewLocation[1])){
+ return false;
+ }
+ break;
+ case MotionEvent.ACTION_UP:
+ rawX=0;
+ rawY=0;
+ if (isTouch) return true;
+ break;
+ case MotionEvent.ACTION_MOVE:
+ float x=event.getRawX();
+ float y=event.getRawY();
+ if (Math.abs(x-rawX)>20||Math.abs(y-rawY)>20){
+ WindowManager.LayoutParams params = (WindowManager.LayoutParams) btnReceiverFloating.getLayoutParams();
+ params.x+= (int) (x-rawX);
+ params.y+= (int) (y-rawY);
+ wm.updateViewLayout(btnReceiverFloating,params);
+ rawX=event.getRawX();
+ rawY=event.getRawY();
+ isTouch = true;
+ }
+ break;
+
+ }
+ return false;
+ }
+ };
+
+ private NotifyDialogManager.Info lastInfo;
+ @Override
+ public void update(NotifyDialogManager ndm, NotifyDialogManager.Info info) {
+ int progress = (int) (info.done * 1f / info.all * 100);
+ if (lastInfo == null) {
+ lastInfo = info;
+ } else {
+ if (!lastInfo.filename.equals(info.filename)) {
+ updateFileName(info.filename);
+ tvFileSize.setText(android.text.format.Formatter.formatFileSize(getContext(), info.all));
+ lastInfo = info;
+ }
+ }
+ updateReceiver(progress);
+ }
+
+ static Long globalSurplus = 0L;
+ static Boolean isSend = false;
+ static Boolean transferComplete = false;
+ private Boolean existFailed = false;
+ //finish single
+ public void finish(NotifyDialogManager.Info info) {
+ BluetoothOppTransferEntity entity = new BluetoothOppTransferEntity();
+ Log.i(TAG, "finish info = " + info);
+ if(info == null) {
+ Log.e(TAG, "-------------------------------->info = " + info + ",lastInfo = " + lastInfo);
+ return;
+ }
+ entity.setName(info.filename.toString());
+ if (info.all == 0 && lastInfo != null && info.filename.equals(lastInfo.filename)) {
+ info.all = lastInfo.all;
+ }
+ entity.setSize(android.text.format.Formatter.formatFileSize(getContext(), info.all));
+ entity.setResult(info.receiverSucceed);
+ bluetoothOppTransferEntityList.add(entity);
+
+ ViewGroup.LayoutParams rvLayoutParams = rvTransferFile.getLayoutParams();
+ int singleHeight = (tvFileName.getHeight() + (int) (getContext().getResources().getDisplayMetrics().density * 10 + 0.5f));
+ if (bluetoothOppTransferEntityList.size() > 4) {
+ rvLayoutParams.height = singleHeight * 5;
+ } else {
+ rvLayoutParams.height = singleHeight * bluetoothOppTransferEntityList.size();
+ }
+ rvTransferFile.setLayoutParams(rvLayoutParams);
+
+ if (!info.receiverSucceed) {
+ existFailed = true;
+ if (!isSend) {
+ transferComplete = true;
+ globalSurplus = (long)0;
+ showDoneButton();
+ callback.receiveFail();
+ }
+ }
+
+ if (globalSurplus <= 1) {
+ transferComplete = true;
+ if (existFailed) {
+ showDoneButton();
+ if (isSend) {
+ callback.sendFail();
+ } else {
+ callback.receiveFail();
+ }
+ } else {
+ btnReceiverFloating.setVisibility(View.GONE);
+ if (isSend) {
+ callback.sendSuccess();
+ } else {
+ callback.receiveSuccess();
+ }
+ }
+ } else {
+ bluetoothOppTransferProgressAdapter.notifyDataSetChanged();
+ updateReceiver(0);
+ globalSurplus--;
+ updateTipCount();
+ }
+ }
+
+ private void showDoneButton() {
+ bluetoothOppTransferProgressAdapter.notifyDataSetChanged();
+ btnDone.setVisibility(View.VISIBLE);
+ btnDone.setOnClickListener(doneListener);
+ llLoadingCount.setVisibility(View.GONE);
+ tvFileCount.setVisibility(View.GONE);
+ btnReceiverFloating.setVisibility(View.GONE);
+ tvHide.setVisibility(View.GONE);
+ llCurrentFile.setVisibility(View.GONE);
+ setVisibility(View.VISIBLE);
+ }
+
+ public static WindowManager.LayoutParams createLayoutParams() {
+ WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams();
+ layoutParams.gravity = Gravity.CENTER;
+ layoutParams.height = android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
+ layoutParams.width = 650;
+ layoutParams.format = PixelFormat.TRANSLUCENT;
+ layoutParams.y = 30;
+ layoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
+ layoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
+ return layoutParams;
+ }
+
+ public void setInfo(final NotifyDialogManager ndm, NotifyDialogManager.Info info) {
+ this.info = info;
+ updateFileName(info.filename);
+ tvFileSize.setText(android.text.format.Formatter.formatFileSize(getContext(), info.all));
+ tvHide.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ setHide(true);
+ }
+ });
+ tvCancelTransfer.setOnClickListener(cancelTransferListener);
+ updateReceiver(0);
+ }
+
+
+ public void updateFileName(CharSequence fileName) {
+ String[] names = fileName.toString().split("/");
+ tvFileName.setText(names[names.length - 1]);
+ }
+
+ public void updateReceiver(int progress) {
+ pbProgress.setProgress(progress);
+
+ }
+
+ boolean addedReceiverFloatingBtn;
+ View btnReceiverFloating;
+ TextView tvFileCount, tvSurplus;
+ Button btnDone;
+
+ @Override
+ public void setHide(boolean _h) {
+ super.setHide(_h);
+ if (_h) setVisibility(GONE);
+ if (!addedReceiverFloatingBtn) {
+ addedReceiverFloatingBtn = true;
+ wm.addView(btnReceiverFloating, countLayoutParams());
+ btnReceiverFloating.setOnClickListener(receiverFloatingBtnListener);
+ btnReceiverFloating.setOnTouchListener(receiverFloatingBtnTouchListener);
+ } else {
+ btnReceiverFloating.setVisibility(View.VISIBLE);
+ }
+ }
+
+ private WindowManager.LayoutParams countLayoutParams() {
+ WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams();
+ layoutParams.gravity = Gravity.LEFT | Gravity.TOP;
+ layoutParams.height = android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
+ layoutParams.width = android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
+ layoutParams.format = PixelFormat.TRANSLUCENT;
+ layoutParams.x = 50;
+ layoutParams.y = getContext().getResources().getDisplayMetrics().heightPixels - (int) (getContext().getResources().getDisplayMetrics().density * 80 + 10f);
+ layoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
+ layoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
+ return layoutParams;
+ }
+}
diff --git a/release/packages/modules/Bluetooth/android/app/src/com/android/bluetooth/opp/Constants.java b/release/packages/modules/Bluetooth/android/app/src/com/android/bluetooth/opp/Constants.java
old mode 100644
new mode 100755
index 84f735d0b1..9b1f650ff2
--- a/release/packages/modules/Bluetooth/android/app/src/com/android/bluetooth/opp/Constants.java
+++ b/release/packages/modules/Bluetooth/android/app/src/com/android/bluetooth/opp/Constants.java
@@ -207,7 +207,7 @@ public class Constants {
static final boolean DEBUG = true;
- static final boolean VERBOSE = false;
+ static final boolean VERBOSE = true;
static final int MAX_RECORDS_IN_DATABASE = 50;
diff --git a/release/packages/modules/Bluetooth/android/app/src/com/android/bluetooth/opp/NotifyDialogManager.java b/release/packages/modules/Bluetooth/android/app/src/com/android/bluetooth/opp/NotifyDialogManager.java
new file mode 100755
index 0000000000..4a3256f743
--- /dev/null
+++ b/release/packages/modules/Bluetooth/android/app/src/com/android/bluetooth/opp/NotifyDialogManager.java
@@ -0,0 +1,243 @@
+package com.android.bluetooth.opp;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.os.Handler;
+import android.os.Message;
+import android.content.BroadcastReceiver;
+import android.util.Log;
+import android.view.View;
+import android.view.WindowManager;
+import android.widget.Toast;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Build;
+import android.hardware.display.DisplayManager;
+import android.view.Display;
+
+import com.android.bluetooth.R;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
+
+import androidx.localbroadcastmanager.content.LocalBroadcastManager;
+import androidx.core.widget.ListViewAutoScrollHelper;
+
+import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
+
+public class NotifyDialogManager {
+
+ //todo string extra
+ private String TAG = "NotifyDialogManager";
+ private Context context;
+ private WindowManager wm;
+ private Map<Integer, BluetoothBaseUI> dialogs = new HashMap<>();
+
+
+ public static final int RECEIVER_CONFIRM_DIALOG = 0;
+ public static final int RECEIVER_PROGRESS_DIALOG = 1;
+ public static final int RECEIVER_FINISH_DIALOG = 2;
+
+ Handler handler;
+
+ public NotifyDialogManager(Context context) {
+ this.context = context;
+ wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
+
+ handler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ super.handleMessage(msg);
+ handleMyMessage(msg);
+ }
+ };
+
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(ACTION_CANCEL_CONFIRM_DIALOG);
+ filter.addAction(ACTION_RECEIVER_FAILED);
+ filter.addAction(ACTION_RECEIVER_SUCCEED);
+ LocalBroadcastManager.getInstance(context).registerReceiver(new NotifyDialogReceiver(), filter);
+ }
+
+ public boolean isCreated(int type) {
+ return dialogs.containsKey(type);
+ }
+
+
+ private final View.OnClickListener doneListener = new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ cancel(RECEIVER_PROGRESS_DIALOG);
+ }
+ };
+
+ private Info lastInfo;
+ private String deviceName;
+
+ public void setDeviceName(String deviceName) {
+ this.deviceName = deviceName;
+ }
+
+ private void handleMyMessage(Message msg) {
+ int type = msg.what;
+ Info info = (Info)msg.obj;
+ if (BluetoothReceiverProgressDialog.transferComplete) {
+ if (dialogs.get(RECEIVER_PROGRESS_DIALOG) != null) {
+ cancel(RECEIVER_PROGRESS_DIALOG);
+ }
+ if (dialogs.get(RECEIVER_CONFIRM_DIALOG) != null) {
+ cancel(RECEIVER_CONFIRM_DIALOG);
+ }
+ }
+ BluetoothBaseUI ui = dialogs.get(type);
+ if (lastInfo == null) lastInfo = info;
+ if (ui != null) {
+ ui.update(NotifyDialogManager.this, info);
+ } else {
+ switch (type) {
+ case RECEIVER_CONFIRM_DIALOG:
+ createReceiverConfirmDialog(info);
+ break;
+ case RECEIVER_PROGRESS_DIALOG:
+ createReceiverProgressDialog(info);
+ break;
+
+ case RECEIVER_FINISH_DIALOG:
+
+ BluetoothReceiverProgressDialog dialog = (BluetoothReceiverProgressDialog) dialogs.get(RECEIVER_PROGRESS_DIALOG);
+ if (dialog == null) {
+ createReceiverProgressDialog(info);
+ }
+ dialog = (BluetoothReceiverProgressDialog) dialogs.get(RECEIVER_PROGRESS_DIALOG);
+ info.all = lastInfo.all;
+ dialog.setDoneListener(doneListener);
+ dialog.finish(info);
+ lastInfo = null;
+ break;
+ }
+
+ }
+ }
+
+ public void notify(final int type, final Info info) {
+ Log.i(TAG, "notify type = " + type + ",info = " + info);
+ Message message = Message.obtain();
+ message.what = type;
+ message.obj = info;
+ handler.sendMessage(message);
+ }
+
+ private BluetoothReceiverProgressDialog.Callback btProgressDialogCallback = new BluetoothReceiverProgressDialog.Callback() {
+ @Override
+ public void sendSuccess() {
+ cancel(RECEIVER_PROGRESS_DIALOG);
+ Toast.makeText(context, R.string.bluetooth_opp_send_success, Toast.LENGTH_LONG).show();
+ }
+
+ @Override
+ public void sendFail() {
+
+ }
+
+ @Override
+ public void receiveSuccess() {
+ cancel(RECEIVER_PROGRESS_DIALOG);
+ Toast.makeText(context, R.string.bluetooth_opp_receiver_success, Toast.LENGTH_LONG).show();
+ }
+
+ @Override
+ public void receiveFail() {
+
+ }
+ };
+
+ private void createReceiverConfirmDialog(Info info) {
+ BluetoothReceiverConfirmDialog view = new BluetoothReceiverConfirmDialog(context);
+ view.setDeviceName(deviceName);
+ view.setInfo(this, info);
+ WindowManager.LayoutParams layoutParams = BluetoothReceiverConfirmDialog.createLayoutParams();
+ //layoutParams.width = (int) (context.getResources().getDisplayMetrics().density * 106 + 0.5f);
+ dialogs.put(RECEIVER_CONFIRM_DIALOG, view);
+ wm.addView(view, layoutParams);
+ }
+
+ private void createReceiverProgressDialog(Info info) {
+ BluetoothReceiverProgressDialog view = new BluetoothReceiverProgressDialog(context);
+ view.setInfo(this, info);
+ view.setCallback(btProgressDialogCallback);
+ view.setHide(true);
+ WindowManager.LayoutParams layoutParams = BluetoothReceiverProgressDialog.createLayoutParams();
+ layoutParams.width = (int) (context.getResources().getDisplayMetrics().density * 291 + 0.5f);
+ dialogs.put(RECEIVER_PROGRESS_DIALOG, view);
+ wm.addView(view, layoutParams);
+ }
+
+ private void createReceiverResult(Info info) {
+ BluetoothReceiverFinishDialog view = new BluetoothReceiverFinishDialog(context);
+ view.setInfo(this, info);
+ WindowManager.LayoutParams layoutParams = BluetoothReceiverFinishDialog.createLayoutParams();
+ dialogs.put(RECEIVER_FINISH_DIALOG, view);
+ wm.addView(view, layoutParams);
+ }
+
+ public void cancel(final int type) {
+ boolean isCreated = isCreated(type);
+ BluetoothBaseUI ui = dialogs.get(type);
+ if (isCreated) {
+ wm.removeView(ui);
+ dialogs.remove(type);
+ }
+ }
+
+ public void cancelAll() {
+ cancel(RECEIVER_CONFIRM_DIALOG);
+ cancel(RECEIVER_PROGRESS_DIALOG);
+ cancel(RECEIVER_FINISH_DIALOG);
+ }
+
+ public static class Info {
+ public CharSequence filename;
+ public int all;
+ public int done;
+ public boolean finish;
+ public View.OnClickListener cancel;
+ public View.OnClickListener confirm;
+ public boolean receiverSucceed;
+ }
+
+ class NotifyDialogReceiver extends BroadcastReceiver {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (intent.getAction() == null) return;
+ String fileName = intent.getStringExtra("fileName");
+ Log.i(TAG, "fileName = " + fileName);
+// cancel(RECEIVER_PROGRESS_DIALOG);
+ Info sinfo = new Info();
+ sinfo.filename = fileName;
+ switch (intent.getAction()) {
+ case ACTION_RECEIVER_FAILED: {
+ sinfo.receiverSucceed = false;
+ break;
+ }
+ case ACTION_RECEIVER_SUCCEED: {
+ sinfo.receiverSucceed = true;
+ break;
+ }
+ case ACTION_CANCEL_CONFIRM_DIALOG: {
+ cancel(RECEIVER_CONFIRM_DIALOG);
+ return;
+ }
+
+ }
+ NotifyDialogManager.this.notify(RECEIVER_FINISH_DIALOG, sinfo);
+ }
+ }
+
+ public static final String ACTION_RECEIVER_FAILED = "notify_manager_receiver_failed";
+ public static final String ACTION_RECEIVER_SUCCEED = "notify_manager_receiver_succeed";
+ public static final String ACTION_CANCEL_CONFIRM_DIALOG = "notify_manager_receiver_cancel_confirm_dialog";
+
+
+}
可能跟不同厂商的代码会有差异,仅供参考。
opp相关修改代码下载地址:
https://download.csdn.net/download/wenzhi20102321/88601215
8、重要过程日志
其实整个蓝牙的接收过程,还是比较复杂的,估计只有开发那个工程师能够知道整个思路。
所以大部分人要进行分析研究,使用日志看出主要过程是最方便和有效的。
一次接收两个文件的部分日志:
//(1)接收socket过程
11-09 18:52:38.890 29667 29755 D BtOppService: onConnect BluetoothSocket :android.bluetooth.BluetoothSocket@af26de5
11-09 18:52:38.890 29667 29755 D BtOppService: :device :18:87:40:11:16:0E
11-09 18:52:38.890 29667 29755 D ObexServerSockets0: Accepting socket connection...
11-09 18:52:38.891 29667 29667 D BtOppService: Get incoming connection
11-09 18:52:38.892 29667 29667 I BtOppService: Start Obex Server
//(2)文件名称
11-09 18:52:39.232 29667 3468 D BluetoothOpp: File Name IMG_20230830_143647
//(3)确认接收第一个文件
11-09 18:52:46.668 29667 29667 D BluetoothOppReceiver: action :android.btopp.intent.action.ACCEPT
11-09 18:52:46.668 29667 29667 V BluetoothOppReceiver: Receiver ACTION_ACCEPT
11-09 18:52:46.681 29667 29667 V BtOppService: ContentObserver received notification
11-09 18:52:46.701 29667 3554 V BluetoothOppNotification: mUpdateCompleteNotification = true
11-09 18:52:47.706 29667 3567 V BluetoothOppNotification: inbound: succ-0 fail-0
11-09 18:52:47.708 29667 3567 I NotifyDialogManager: notify type = 1,info = com.android.bluetooth.opp.NotifyDialogManager$Info@7178928
//(4)文件接收过程
11-09 18:52:46.688 29667 29667 V BluetoothOppNotification: new notify threadi!
11-09 18:52:46.691 29667 3551 V BtOppService: pendingUpdate is false sListenStarted is true isInterrupted :false
11-09 18:52:46.694 29667 29667 V BluetoothOppNotification: send delay message
11-09 18:52:47.706 29667 3567 V BluetoothOppNotification: inbound: succ-0 fail-0
11-09 18:52:47.708 29667 3567 I NotifyDialogManager: notify type = 1,info = com.android.bluetooth.opp.NotifyDialogManager$Info@7178928
11-09 18:52:49.698 29667 29667 V BluetoothOppNotification: new notify threadi!
11-09 18:52:49.699 29667 29667 V BluetoothOppNotification: send delay message
11-09 18:52:49.701 29667 3589 V BluetoothOppNotification: mUpdateCompleteNotification = false
11-09 18:52:49.701 29667 3589 V BluetoothOppNotification: ACTION_INCOMING_FILE_CONFIRM
11-09 18:52:49.706 29667 3589 V BluetoothOppNotification: inbound: succ-0 fail-0
11-09 18:52:49.707 29667 3589 I NotifyDialogManager: notify type = 1,info = com.android.bluetooth.opp.NotifyDialogManager$Info@8a6d146
//接收过程可能比较长。。。
//(5)第一个蓝牙文件接收完成
11-09 18:55:17.694 29667 29667 D BluetoothOppReceiver: action :android.btopp.intent.action.TRANSFER_COMPLETE
11-09 18:55:17.694 29667 29667 V BluetoothOppReceiver: Receiver Transfer Complete Intent for content://com.android.bluetooth.opp/btopp/1
//(6)接收第二个文件的socket日志
11-09 18:55:54.444 29667 29755 D BtOppService: onConnect BluetoothSocket :android.bluetooth.BluetoothSocket@c44b63
11-09 18:55:54.444 29667 29755 D BtOppService: :device :18:87:40:11:16:0E
11-09 18:55:54.445 29667 29755 D ObexServerSockets0: Accepting socket connection...
11-09 18:55:54.445 29667 29667 D BtOppService: Get incoming connection
11-09 18:55:54.445 29667 29667 I BtOppService: Start Obex Server
//(7)名称和信息
11-09 18:55:54.662 29667 5202 D BluetoothOpp: file crated, insertUri:content://media/external/downloads/1000000084
11-09 18:55:54.662 29667 5202 V BtOppObexServer: Generate BluetoothOppReceiveFileInfo:
11-09 18:55:54.662 29667 5202 V BtOppObexServer: filename :Screenshot_2023-11-09-18-55-30-669_com.miui.gallery_065554.jpg
11-09 18:55:54.662 29667 5202 V BtOppObexServer: length :752526
11-09 18:55:54.662 29667 5202 V BtOppObexServer: status :0
//(8)确认接收第二个文件
11-09 18:55:54.684 29667 5204 I NotifyDialogManager: notify type = 0,info = com.android.bluetooth.opp.NotifyDialogManager$Info@56b4e78
11-09 18:55:58.226 29667 29667 D BluetoothOppReceiver: action :android.btopp.intent.action.ACCEPT
11-09 18:55:58.227 29667 29667 V BluetoothOppReceiver: Receiver ACTION_ACCEPT
//(9)接收第二个文件过程
11-09 18:55:59.280 29667 29667 V BluetoothOppNotification: new notify threadi!
11-09 18:55:59.281 29667 29667 V BluetoothOppNotification: send delay message
11-09 18:55:59.286 29667 5261 V BluetoothOppNotification: mUpdateCompleteNotification = false
11-09 18:55:59.286 29667 5261 V BluetoothOppNotification: ACTION_INCOMING_FILE_CONFIRM
11-09 18:55:59.292 29667 5261 I NotifyDialogManager: notify type = 1,info = com.android.bluetooth.opp.NotifyDialogManager$Info@b2951af
11-09 18:56:00.293 29667 5288 I NotifyDialogManager: notify type = 1,info = com.android.bluetooth.opp.NotifyDialogManager$Info@25e3a84
11-09 18:56:00.283 29667 29667 V BluetoothOppNotification: new notify threadi!
11-09 18:56:00.284 29667 29667 V BluetoothOppNotification: send delay message
11-09 18:56:00.288 29667 5288 V BluetoothOppNotification: ACTION_INCOMING_FILE_CONFIRM
11-09 18:56:00.293 29667 5288 I NotifyDialogManager: notify type = 1,info = com.android.bluetooth.opp.NotifyDialogManager$Info@25e3a84
//如果是大文件,上面的接收文件过程就比较长。
//(10)接收第二个文件结束
11-09 18:56:05.119 29667 29667 D BluetoothOppReceiver: action :android.btopp.intent.action.TRANSFER_COMPLETE
11-09 18:56:05.119 29667 29667 V BluetoothOppReceiver: Receiver Transfer Complete Intent for content://com.android.bluetooth.opp/btopp/2
11-09 18:56:05.150 29667 29667 I NotifyDialogManager: fileName = Screenshot_2023-11-09-18-55-30-669_com.miui.gallery_065554.jpg
11-09 18:56:05.151 29667 29667 I NotifyDialogManager: notify type = 2,info = com.android.bluetooth.opp.NotifyDialogManager$Info@4796225
11-09 18:56:05.151 29667 29667 I BluetoothReceiverProgressDialog: finish info = com.android.bluetooth.opp.NotifyDialogManager$Info@4796225
从上面看关键日志就是进程 29667 相关的日志。
这里只贴了部分日志,有需要的可以看完整日志。
完整logcat日志下载:
https://download.csdn.net/download/wenzhi20102321/88601280
这的日志已经加入patch 的代码,是对话框提示接收和自定义进行对话框显示的日志。
四、总结
1、蓝牙文件接收设计到的广播
文件接收确认,需要自己发送广播:
mContext.sendBroadcast(new Intent(baseIntent).setAction(Constants.ACTION_DECLINE));
文件完成确认
BluetoothOppReceiver.java广播监听:
BluetoothShare.TRANSFER_COMPLETED_ACTION
2、蓝牙文件接收的过程
蓝牙文件确认接收和接收过程已经接收完成都是在 BluetoothOppNotification.java 有体现。
具体过程可以看日志进行确认。
确认接收后,后续的文件是默认自动接收的,如果中间断开接收,后续的文件是无法接收的。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!