update android server notification

This commit is contained in:
csf 2022-03-30 17:31:32 +08:00
parent 4ca42faee9
commit d66939244e
6 changed files with 126 additions and 39 deletions

View File

@ -15,6 +15,7 @@ import androidx.annotation.RequiresApi
import io.flutter.embedding.android.FlutterActivity import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodChannel import io.flutter.plugin.common.MethodChannel
import java.lang.Exception
const val MEDIA_REQUEST_CODE = 42 const val MEDIA_REQUEST_CODE = 42
@ -97,6 +98,13 @@ class MainActivity : FlutterActivity() {
mapOf("name" to "input", "value" to InputService.isOpen.toString()) mapOf("name" to "input", "value" to InputService.isOpen.toString())
) )
} }
"cancel_notification" -> {
try {
val id = call.arguments as Int
Log.d(logTag,"cancel_notification id:$id")
mainService?.cancelNotification(id)
}finally { }
}
else -> {} else -> {}
} }
} }

View File

@ -30,7 +30,8 @@ import androidx.core.app.NotificationCompat
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import java.util.concurrent.Executors import java.util.concurrent.Executors
import kotlin.concurrent.thread import kotlin.concurrent.thread
import androidx.media.app.NotificationCompat.MediaStyle import org.json.JSONException
import org.json.JSONObject
const val EXTRA_MP_DATA = "mp_intent" const val EXTRA_MP_DATA = "mp_intent"
const val INIT_SERVICE = "init_service" const val INIT_SERVICE = "init_service"
@ -38,8 +39,9 @@ const val ACTION_LOGIN_REQ_NOTIFY = "ACTION_LOGIN_REQ_NOTIFY"
const val EXTRA_LOGIN_REQ_NOTIFY = "EXTRA_LOGIN_REQ_NOTIFY" const val EXTRA_LOGIN_REQ_NOTIFY = "EXTRA_LOGIN_REQ_NOTIFY"
const val DEFAULT_NOTIFY_TITLE = "RustDesk" const val DEFAULT_NOTIFY_TITLE = "RustDesk"
const val DEFAULT_NOTIFY_TEXT = "Service is listening" const val DEFAULT_NOTIFY_TEXT = "Service is running"
const val NOTIFY_ID = 11 const val DEFAULT_NOTIFY_ID = 1
const val NOTIFY_ID_OFFSET = 100 // 为每个客户端ID增加这个偏移量而得到通知栏ID避免使用0且防止和默认ID冲突
const val NOTIFY_TYPE_START_CAPTURE = "NOTIFY_TYPE_START_CAPTURE" const val NOTIFY_TYPE_START_CAPTURE = "NOTIFY_TYPE_START_CAPTURE"
@ -96,17 +98,42 @@ class MainService : Service() {
fun rustSetByName(name: String, arg1: String, arg2: String) { fun rustSetByName(name: String, arg1: String, arg2: String) {
when (name) { when (name) {
"try_start_without_auth" -> { "try_start_without_auth" -> {
// TODO notify try {
loginRequestActionNotification("test","name","id") val jsonObject = JSONObject(arg1)
val id = jsonObject["id"] as Int
val username = jsonObject["name"] as String
val peerId = jsonObject["peer_id"] as String
val type = if (jsonObject["is_file_transfer"] as Boolean){
translate("File Connection")
}else{
translate("Screen Connection")
} }
"start_capture" -> { loginRequestNotification(id,type,username,peerId)
Log.d(logTag, "from rust:start_capture") }catch (e:JSONException){
if (isStart) { e.printStackTrace()
Log.d(logTag, "正在录制")
return
} }
}
"on_client_authorized" -> {
Log.d(logTag, "from rust:on_client_authorized")
try {
val jsonObject = JSONObject(arg1)
val id = jsonObject["id"] as Int
val username = jsonObject["name"] as String
val peerId = jsonObject["peer_id"] as String
val isFileTransfer = jsonObject["is_file_transfer"] as Boolean
val type = if (isFileTransfer){
translate("File Connection")
}else{
translate("Screen Connection")
}
if(!isFileTransfer && !isStart){
startCapture() startCapture()
// TODO notify }
onClientAuthorizedNotification(id,type,username,peerId)
}catch (e:JSONException){
e.printStackTrace()
}
} }
"stop_capture" -> { "stop_capture" -> {
Log.d(logTag, "from rust:stop_capture") Log.d(logTag, "from rust:stop_capture")
@ -119,8 +146,14 @@ class MainService : Service() {
// jvm call rust // jvm call rust
private external fun init(ctx: Context) private external fun init(ctx: Context)
private external fun startServer() private external fun startServer()
private external fun translateLocale(localeName:String,input: String) : String
// private external fun sendVp9(data: ByteArray) // private external fun sendVp9(data: ByteArray)
private fun translate(input:String):String{
Log.d(logTag,"translate:$LOCAL_NAME")
return translateLocale(LOCAL_NAME,input)
}
private val logTag = "LOG_SERVICE" private val logTag = "LOG_SERVICE"
private val useVP9 = false private val useVP9 = false
private val binder = LocalBinder() private val binder = LocalBinder()
@ -498,31 +531,54 @@ class MainService : Service() {
.setAutoCancel(true) .setAutoCancel(true)
.setPriority(NotificationCompat.PRIORITY_DEFAULT) .setPriority(NotificationCompat.PRIORITY_DEFAULT)
.setContentTitle(DEFAULT_NOTIFY_TITLE) .setContentTitle(DEFAULT_NOTIFY_TITLE)
.setContentText(DEFAULT_NOTIFY_TEXT) .setContentText(translate(DEFAULT_NOTIFY_TEXT) + '!')
.setOnlyAlertOnce(true) .setOnlyAlertOnce(true)
.setContentIntent(pendingIntent) .setContentIntent(pendingIntent)
.setColor(ContextCompat.getColor(this, R.color.primary)) .setColor(ContextCompat.getColor(this, R.color.primary))
.setWhen(System.currentTimeMillis()) .setWhen(System.currentTimeMillis())
.build() .build()
// 这里满足前台服务首次启动时5s内设定好通知内容这里使用startForeground后续普通调用使用notificationManager即可 // 这里满足前台服务首次启动时5s内设定好通知内容这里使用startForeground后续普通调用使用notificationManager即可
startForeground(NOTIFY_ID, notification) startForeground(DEFAULT_NOTIFY_ID, notification)
} }
private fun loginRequestActionNotification(type: String, name: String, id: String) { private fun loginRequestNotification(clientID:Int, type: String, username: String, peerId: String) {
// notificationBuilder 第一次使用时状态已保存,再次生成时只需要调整需要修改的部分 // notificationBuilder 第一次使用时状态已保存,再次生成时只需要调整需要修改的部分
cancelNotification(clientID)
val notification = notificationBuilder val notification = notificationBuilder
.setOngoing(false)
.setPriority(NotificationCompat.PRIORITY_HIGH) .setPriority(NotificationCompat.PRIORITY_HIGH)
.setContentTitle("收到${type}连接请求") .setContentTitle(translate("Do you accept?"))
.setContentText("来自:$name-$id") .setContentText("$type:$username-$peerId")
// 暂时不开启通知栏接受请求
// 暂时不开启通知栏接受请求,防止用户误操作 // .setStyle(MediaStyle().setShowActionsInCompactView(0, 1))
// .setStyle(MediaStyle().setShowActionsInCompactView(0, 1)) // .addAction(R.drawable.check_blue, "check", genLoginRequestPendingIntent(true))
// .addAction(R.drawable.check_blue, "check", genLoginRequestPendingIntent(true)) // .addAction(R.drawable.close_red, "close", genLoginRequestPendingIntent(false))
// .addAction(R.drawable.close_red, "close", genLoginRequestPendingIntent(false))
.build() .build()
// TODO 为每个login req定义id notify id 不能是0 可以定义为client id + 100,如101,102,103 notificationManager.notify(getClientNotifyID(clientID), notification)
// 登录成功 取消notify时可以直接使用 }
notificationManager.notify(NOTIFY_ID + 1, notification)
private fun onClientAuthorizedNotification(clientID: Int, type: String, username: String, peerId: String) {
cancelNotification(clientID)
val notification = notificationBuilder
.setOngoing(false)
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setContentTitle("$type ${translate("Established")}")
.setContentText("$username - $peerId")
.build()
notificationManager.notify(getClientNotifyID(clientID), notification)
}
private fun getClientNotifyID(clientID:Int):Int{
return clientID + NOTIFY_ID_OFFSET
}
/**
* 关闭通知的情况
* 1.UI端接受或拒绝
* 2.peer端通过密码建立了连接在onClientAuthorizedNotification中已处理 peer端手动取消了连接
*/
fun cancelNotification(clientID:Int){
notificationManager.cancel(getClientNotifyID(clientID))
} }
private fun genLoginRequestPendingIntent(res: Boolean): PendingIntent { private fun genLoginRequestPendingIntent(res: Boolean): PendingIntent {
@ -539,13 +595,13 @@ class MainService : Service() {
private fun setTextNotification(_title: String?, _text: String?) { private fun setTextNotification(_title: String?, _text: String?) {
val title = _title ?: DEFAULT_NOTIFY_TITLE val title = _title ?: DEFAULT_NOTIFY_TITLE
val text = _text ?: DEFAULT_NOTIFY_TEXT val text = _text ?: translate(DEFAULT_NOTIFY_TEXT) + '!'
val notification = notificationBuilder val notification = notificationBuilder
.clearActions() .clearActions()
.setStyle(null) .setStyle(null)
.setContentTitle(title) .setContentTitle(title)
.setContentText(text) .setContentText(text)
.build() .build()
notificationManager.notify(NOTIFY_ID, notification) notificationManager.notify(DEFAULT_NOTIFY_ID, notification)
} }
} }

View File

@ -1,5 +1,6 @@
package com.carriez.flutter_hbb package com.carriez.flutter_hbb
import android.annotation.SuppressLint
import android.app.* import android.app.*
import android.app.PendingIntent.FLAG_UPDATE_CURRENT import android.app.PendingIntent.FLAG_UPDATE_CURRENT
import android.content.Context import android.content.Context
@ -13,6 +14,10 @@ import androidx.annotation.RequiresApi
import androidx.core.app.NotificationCompat import androidx.core.app.NotificationCompat
import com.hjq.permissions.Permission import com.hjq.permissions.Permission
import com.hjq.permissions.XXPermissions import com.hjq.permissions.XXPermissions
import java.util.*
@SuppressLint("ConstantLocale")
val LOCAL_NAME = Locale.getDefault().toString()
val INFO = Info("", "", 0, 0) val INFO = Info("", "", 0, 0)

View File

@ -849,8 +849,8 @@ class FFI {
PlatformFFI.setMethodCallHandler(callback); PlatformFFI.setMethodCallHandler(callback);
} }
static Future<bool> invokeMethod(String method) async { static Future<bool> invokeMethod(String method,[ dynamic arguments ]) async {
return await PlatformFFI.invokeMethod(method); return await PlatformFFI.invokeMethod(method, arguments);
} }
} }

View File

@ -123,8 +123,8 @@ class PlatformFFI {
}); });
} }
static invokeMethod(String method) async { static invokeMethod(String method,[ dynamic arguments ]) async {
return await toAndroidChannel.invokeMethod(method); return await toAndroidChannel.invokeMethod(method,arguments);
} }
} }

View File

@ -81,7 +81,12 @@ class ServerModel with ChangeNotifier {
toggleService() async { toggleService() async {
if(_isStart){ if(_isStart){
final res = await DialogManager.show<bool>((setState, close) => CustomAlertDialog( final res = await DialogManager.show<bool>((setState, close) => CustomAlertDialog(
title: Text(translate("Warning")), title: Row(children: [
Icon(Icons.warning_amber_sharp,
color: Colors.redAccent, size: 28),
SizedBox(width: 10),
Text(translate("Warning")),
]),
content: Text(translate("android_stop_service_tip")), content: Text(translate("android_stop_service_tip")),
actions: [ actions: [
TextButton(onPressed: ()=>close(), child: Text(translate("Cancel"))), TextButton(onPressed: ()=>close(), child: Text(translate("Cancel"))),
@ -93,7 +98,12 @@ class ServerModel with ChangeNotifier {
} }
}else{ }else{
final res = await DialogManager.show<bool>((setState, close) => CustomAlertDialog( final res = await DialogManager.show<bool>((setState, close) => CustomAlertDialog(
title: Text(translate("Warning")), title: Row(children: [
Icon(Icons.warning_amber_sharp,
color: Colors.redAccent, size: 28),
SizedBox(width: 10),
Text(translate("Warning")),
]),
content: Text(translate("android_service_will_start_tip")), content: Text(translate("android_service_will_start_tip")),
actions: [ actions: [
TextButton(onPressed: ()=>close(), child: Text(translate("Cancel"))), TextButton(onPressed: ()=>close(), child: Text(translate("Cancel"))),
@ -208,7 +218,12 @@ class ServerModel with ChangeNotifier {
final Map<String, dynamic> response = Map(); final Map<String, dynamic> response = Map();
response["id"] = client.id; response["id"] = client.id;
DialogManager.show((setState, close) => CustomAlertDialog( DialogManager.show((setState, close) => CustomAlertDialog(
title: Text(translate(client.isFileTransfer?"File Connection":"Screen Connection")), title: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(translate(client.isFileTransfer?"File Connection":"Screen Connection")),
IconButton(onPressed: close, icon: Icon(Icons.close))
]),
content: Column( content: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
@ -226,6 +241,7 @@ class ServerModel with ChangeNotifier {
onPressed: () { onPressed: () {
response["res"] = false; response["res"] = false;
FFI.setByName("login_res", jsonEncode(response)); FFI.setByName("login_res", jsonEncode(response));
FFI.invokeMethod("cancel_notification",client.id);
close(); close();
}), }),
ElevatedButton( ElevatedButton(
@ -234,10 +250,9 @@ class ServerModel with ChangeNotifier {
response["res"] = true; response["res"] = true;
FFI.setByName("login_res", jsonEncode(response)); FFI.setByName("login_res", jsonEncode(response));
if (!client.isFileTransfer) { if (!client.isFileTransfer) {
bool res = await FFI.invokeMethod( FFI.invokeMethod("start_capture");
"start_capture"); // to Android service
debugPrint("_toAndroidStartCapture:$res");
} }
FFI.invokeMethod("cancel_notification",client.id);
_clients[client.id] = client; _clients[client.id] = client;
notifyListeners(); notifyListeners();
close(); close();
@ -251,6 +266,8 @@ class ServerModel with ChangeNotifier {
void onClientAuthorized(Map<String, dynamic> evt) { void onClientAuthorized(Map<String, dynamic> evt) {
try{ try{
final client = Client.fromJson(jsonDecode(evt['client'])); final client = Client.fromJson(jsonDecode(evt['client']));
// reset the login dialog, to-do,it will close any showing dialog
DialogManager.reset();
_clients[client.id] = client; _clients[client.id] = client;
notifyListeners(); notifyListeners();
}catch(e){ }catch(e){
@ -266,6 +283,7 @@ class ServerModel with ChangeNotifier {
}else{ }else{
// reset the login dialog, to-do,it will close any showing dialog // reset the login dialog, to-do,it will close any showing dialog
DialogManager.reset(); DialogManager.reset();
FFI.invokeMethod("cancel_notification",id);
} }
notifyListeners(); notifyListeners();
} catch (e) { } catch (e) {