From 4ca42faee9a5eb6556f567a630ac2e75f9a23bb9 Mon Sep 17 00:00:00 2001 From: csf Date: Tue, 29 Mar 2022 23:10:43 +0800 Subject: [PATCH] file cancel job; update android --- .../com/carriez/flutter_hbb/MainActivity.kt | 4 +- .../com/carriez/flutter_hbb/MainService.kt | 45 +++++++++++-------- android_doc.md | 27 ++++++----- lib/models/file_model.dart | 5 ++- lib/models/server_model.dart | 9 ++-- lib/pages/file_manager_page.dart | 11 +---- 6 files changed, 57 insertions(+), 44 deletions(-) diff --git a/android/app/src/main/kotlin/com/carriez/flutter_hbb/MainActivity.kt b/android/app/src/main/kotlin/com/carriez/flutter_hbb/MainActivity.kt index 28ca43880..41ea6b594 100644 --- a/android/app/src/main/kotlin/com/carriez/flutter_hbb/MainActivity.kt +++ b/android/app/src/main/kotlin/com/carriez/flutter_hbb/MainActivity.kt @@ -30,11 +30,11 @@ class MainActivity : FlutterActivity() { @RequiresApi(Build.VERSION_CODES.M) override fun configureFlutterEngine(flutterEngine: FlutterEngine) { + super.configureFlutterEngine(flutterEngine) Log.d(logTag, "MainActivity configureFlutterEngine,bind to main service") Intent(this, MainService::class.java).also { bindService(it, serviceConnection, Context.BIND_AUTO_CREATE) } - super.configureFlutterEngine(flutterEngine) // 必要 否则无法正确初始化flutter checkPermissions(this) updateMachineInfo() flutterMethodChannel = MethodChannel( @@ -180,7 +180,6 @@ class MainActivity : FlutterActivity() { w /= scale h /= scale } - Log.d(logTag, "Real size - width:$w,height:$h") INFO.screenWidth = w INFO.screenHeight = h @@ -188,6 +187,7 @@ class MainActivity : FlutterActivity() { INFO.username = "test" INFO.hostname = "hostname" // TODO username hostname + Log.d(logTag, "INIT INFO:$INFO") } else { Log.e(logTag, "Got Screen Size Fail!") diff --git a/android/app/src/main/kotlin/com/carriez/flutter_hbb/MainService.kt b/android/app/src/main/kotlin/com/carriez/flutter_hbb/MainService.kt index 4e876806a..b4cf948c9 100644 --- a/android/app/src/main/kotlin/com/carriez/flutter_hbb/MainService.kt +++ b/android/app/src/main/kotlin/com/carriez/flutter_hbb/MainService.kt @@ -1,5 +1,6 @@ /** - * video_service and audio_service + * Capture screen,get video and audio,send to rust. + * Handle notification */ package com.carriez.flutter_hbb @@ -96,7 +97,7 @@ class MainService : Service() { when (name) { "try_start_without_auth" -> { // TODO notify - + loginRequestActionNotification("test","name","id") } "start_capture" -> { Log.d(logTag, "from rust:start_capture") @@ -118,8 +119,7 @@ class MainService : Service() { // jvm call rust private external fun init(ctx: Context) private external fun startServer() - private external fun ready() - private external fun sendVp9(data: ByteArray) + // private external fun sendVp9(data: ByteArray) private val logTag = "LOG_SERVICE" private val useVP9 = false @@ -157,7 +157,7 @@ class MainService : Service() { override fun onCreate() { super.onCreate() initNotification() - startServer() // 开启了rust服务但是没有设置可以接收连接 如果不开启 首次启动没法获得服务ID + startServer() } override fun onBind(intent: Intent): IBinder { @@ -188,15 +188,14 @@ class MainService : Service() { checkMediaPermission() surface = createSurface() init(this) - ready() _isReady = true } ?: let { Log.d(logTag, "获取mMediaProjection失败!") } - } else if (intent?.action == ACTION_LOGIN_REQ_NOTIFY) { - // TODO notify 重新适配多连接的情况 - val notifyLoginRes = intent.getBooleanExtra(EXTRA_LOGIN_REQ_NOTIFY, false) - Log.d(logTag, "从通知栏点击了:$notifyLoginRes") +// } else if (intent?.action == ACTION_LOGIN_REQ_NOTIFY) { + // 暂时不开启通知从通知栏确认登录 +// val notifyLoginRes = intent.getBooleanExtra(EXTRA_LOGIN_REQ_NOTIFY, false) +// Log.d(logTag, "从通知栏点击了:$notifyLoginRes") } return super.onStartCommand(intent, flags, startId) } @@ -208,6 +207,7 @@ class MainService : Service() { // TODO null } else { + Log.d(logTag,"ImageReader.newInstance:INFO:$INFO") imageReader = ImageReader.newInstance( INFO.screenWidth, @@ -361,7 +361,7 @@ class MainService : Service() { // TODO 优化内存使用方式 val byteArray = ByteArray(buf.limit()) buf.get(byteArray) - sendVp9(byteArray) + // sendVp9(byteArray) codec.releaseOutputBuffer(index, false) } } @@ -466,7 +466,7 @@ class MainService : Service() { val channelName = "RustDesk Service" val channel = NotificationChannel( channelId, - channelName, NotificationManager.IMPORTANCE_DEFAULT + channelName, NotificationManager.IMPORTANCE_HIGH ).apply { description = "RustDesk Service Channel" } @@ -494,6 +494,8 @@ class MainService : Service() { val notification = notificationBuilder .setOngoing(true) .setSmallIcon(R.mipmap.ic_launcher) + .setDefaults(Notification.DEFAULT_ALL) + .setAutoCancel(true) .setPriority(NotificationCompat.PRIORITY_DEFAULT) .setContentTitle(DEFAULT_NOTIFY_TITLE) .setContentText(DEFAULT_NOTIFY_TEXT) @@ -502,18 +504,25 @@ class MainService : Service() { .setColor(ContextCompat.getColor(this, R.color.primary)) .setWhen(System.currentTimeMillis()) .build() + // 这里满足前台服务首次启动时5s内设定好通知内容,这里使用startForeground,后续普通调用使用notificationManager即可 startForeground(NOTIFY_ID, notification) } private fun loginRequestActionNotification(type: String, name: String, id: String) { + // notificationBuilder 第一次使用时状态已保存,再次生成时只需要调整需要修改的部分 val notification = notificationBuilder + .setPriority(NotificationCompat.PRIORITY_HIGH) .setContentTitle("收到${type}连接请求") - .setContentText("来自:$name-$id 是否接受") - .setStyle(MediaStyle().setShowActionsInCompactView(0, 1)) - .addAction(R.drawable.check_blue, "check", genLoginRequestPendingIntent(true)) - .addAction(R.drawable.close_red, "close", genLoginRequestPendingIntent(false)) + .setContentText("来自:$name-$id") + + // 暂时不开启通知栏接受请求,防止用户误操作 +// .setStyle(MediaStyle().setShowActionsInCompactView(0, 1)) +// .addAction(R.drawable.check_blue, "check", genLoginRequestPendingIntent(true)) +// .addAction(R.drawable.close_red, "close", genLoginRequestPendingIntent(false)) .build() - notificationManager.notify(NOTIFY_ID, notification) + // TODO 为每个login req定义id ,notify id 不能是0 可以定义为client id + 100,如101,102,103 + // 登录成功 取消notify时可以直接使用 + notificationManager.notify(NOTIFY_ID + 1, notification) } private fun genLoginRequestPendingIntent(res: Boolean): PendingIntent { @@ -539,4 +548,4 @@ class MainService : Service() { .build() notificationManager.notify(NOTIFY_ID, notification) } -} \ No newline at end of file +} diff --git a/android_doc.md b/android_doc.md index e68198b62..674a85a71 100644 --- a/android_doc.md +++ b/android_doc.md @@ -1,5 +1,10 @@ # RustDesk 安卓端被控文档记录 +### 开发环境注意 + +- AS IDE Android 启动service时的闪退问题,开发安卓使用到service时,在Android IDE模式下用AS重新启动app前,如果已启动Service,需要确保已开启的app已经完全关闭,否则可能会出现下次启动service时闪退的怪问题。 +- 如果IDE时Flutter模式无此问题,flutter模式每次编译开启app的时间较长,推测flutter每次编译会重新安装一次apk包,而Android有热编译机制,启动Service时候,可能会带来闪退bug。 + ### 1.获取屏幕录像 ##### 原理 流程 @@ -31,7 +36,7 @@ MediaProjectionManager -> MediaProjection - **注意**:安卓捕获到的数据是RGBA格式,暂无BRGA的输出,在rust端需要调用libyuv中相应的rgbatoi420方法 - 捕获到的数据存入一个bytearray,等待rust端调用获取 -#####方案B 捕获原始数据传入rust进行编码 !等待完善! +#####方案B 使用内置vp9编码器直接获取编码后的数据 传入rust进行编码 !暂不启用,等待完善! - **自带的编码器无法直接控制流量,默认情况输出的帧率比较高,会造成网络堵塞延迟** - 获取编码后的buf - 通过MediaCodec回调获取到可用的数据 @@ -241,19 +246,13 @@ Config::set_option("stop_service","Y") Config::set_option("stop_service","") -### TODO -完善CM 当前连接的状态 控制音频和输入等开关 断开连接等功能 -横屏模式 -首次登录不显示id密码 -安卓前后分离的问题 通过IPC或者广播解耦 - ### 关于安卓的service和进程 实际测试 安卓7和安卓11表现不同 同一个apk下若有多个activity或service -安卓7 关闭activity后所有的服务都会强制关闭 可能是锤子手机特有 +安卓7 关闭activity后所有的服务都会强制关闭 可能是部分安卓厂商ROM手机特有 安卓8.1 和7类似 且安卓8.1和7录屏权限比较宽松 只需要获取一次 不需要每次播放都要获取录屏权限 -*安卓7/8.1关闭activity 后就关闭service 可能是锤子OS的特质 +*安卓7/8.1关闭activity 后就关闭service 可能是部分安卓厂商ROM手机特有 理论上 非bind启动的service可以脱离activity运行 就像三星安卓11上测试的情况 @@ -291,6 +290,14 @@ https://developer.android.com/about/versions/oreo/background?hl=zh-cn#services
+### 安卓通知 +- 注册前台服务startForegroundService 首次注册需要在5s内正确设置前台服务的通知栏显示内容。 +- MainService初始化时注册一个notificationManager,后续除了上条“前台服务依赖的通知内容”外的正常通知,都可以使用notificationManager来激活。 +- notificationManager.notify(id,notification) 用于普通的激活通知,注意 第一个id如果存在是更新之前的通知,更新通知不会有震动提示,如需新通知也发出震动提示用另一个id。 + +
+ + ### 开机自启动 利用接收RECEIVE_BOOT_COMPLETED的系统广播 - 权限: @@ -347,4 +354,4 @@ https://developer.android.com/about/versions/oreo/background?hl=zh-cn#services compileSdkVersion 30 ndkVersion '22.1.7171670' ... - ``` \ No newline at end of file + ``` diff --git a/lib/models/file_model.dart b/lib/models/file_model.dart index cdde40fea..1b5f792eb 100644 --- a/lib/models/file_model.dart +++ b/lib/models/file_model.dart @@ -328,6 +328,7 @@ class FileModel extends ChangeNotifier { } catch (e) {} } }); + _selectMode = false; refresh(); } @@ -407,7 +408,9 @@ class FileModel extends ChangeNotifier { FFI.setByName("create_dir", jsonEncode(msg)); } - cancelJob(int id) {} + cancelJob(int id) { + FFI.setByName("cancel_job",id.toString()); + } changeSortStyle(SortBy sort) { _sortStyle = sort; diff --git a/lib/models/server_model.dart b/lib/models/server_model.dart index a7efd25bc..1b177a250 100644 --- a/lib/models/server_model.dart +++ b/lib/models/server_model.dart @@ -261,11 +261,14 @@ class ServerModel with ChangeNotifier { void onClientRemove(Map evt) { try { final id = int.parse(evt['id'] as String); - _clients.remove(id); + if(_clients.containsKey(id)){ + _clients.remove(id); + }else{ + // reset the login dialog, to-do,it will close any showing dialog + DialogManager.reset(); + } notifyListeners(); } catch (e) { - // singleWhere fail ,reset the login dialog - DialogManager.reset(); debugPrint("onClientRemove failed,error:$e"); } } diff --git a/lib/pages/file_manager_page.dart b/lib/pages/file_manager_page.dart index e93c72c10..256d8708a 100644 --- a/lib/pages/file_manager_page.dart +++ b/lib/pages/file_manager_page.dart @@ -333,15 +333,6 @@ class _FileManagerPageState extends State { ], )); - Widget emptyPage() { - return Column( - children: [ - headTools(), - Expanded(child: Center(child: Text("Empty Directory"))) - ], - ); - } - Widget listTail() { return Container( height: 100, @@ -411,7 +402,7 @@ class _FileManagerPageState extends State { title: translate("Waiting"), text: "${translate("Speed")}: ${readableFileSize(model.jobProgress.speed)}/s", - onCanceled: null, + onCanceled: model.cancelJob(model.jobProgress.id), ); case JobState.done: return BottomSheetBody(