diff --git a/android/app/build.gradle b/android/app/build.gradle index 9aa6a16d0..24d927b25 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -33,7 +33,7 @@ apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" android { compileSdkVersion 30 - // ndkVersion '22.1.7171670' // * 仅个人使用 存在多版本NDK无法自动选择 需要使用此配置指定NDK版本 [CSF] + ndkVersion '22.1.7171670' // * 仅个人使用 存在多版本NDK无法自动选择 需要使用此配置指定NDK版本 [CSF] sourceSets { main.java.srcDirs += 'src/main/kotlin' } diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index e096196e9..c83ccf780 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -1,51 +1,76 @@ + - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/android/app/src/main/kotlin/com/carriez/flutter_hbb/InputService.kt b/android/app/src/main/kotlin/com/carriez/flutter_hbb/InputService.kt new file mode 100644 index 000000000..6b23eaddd --- /dev/null +++ b/android/app/src/main/kotlin/com/carriez/flutter_hbb/InputService.kt @@ -0,0 +1,106 @@ +package com.carriez.flutter_hbb + +import android.accessibilityservice.AccessibilityService +import android.accessibilityservice.GestureDescription +import android.content.Context +import android.graphics.Path +import android.os.Build +import android.util.Log +import android.view.accessibility.AccessibilityEvent +import androidx.annotation.RequiresApi +import kotlin.concurrent.thread + +class InputService : AccessibilityService() { +// companion object { +// var inputService:InputService? = null +// } + private val logTag = "input service" + private var leftIsDown = false + private var mPath = Path() + private var mLastGestureStartTime = 0L + private var mouseX = 0 + private var mouseY = 0 + + @RequiresApi(Build.VERSION_CODES.N) + fun mouseInput(mask: Int, _x: Int, _y: Int) { + Log.w(logTag, "got mouse input:x:$_x ,y:$_y ,mask:$mask ") + + // TODO 临时倍数 + // TODO 按键抬起按下时候 x y 都是0 + if ( !(mask == 9 || mask == 10) ) { + mouseX = _x * 2 + mouseY = _y * 2 + } + + // left button down ,was up + if (mask == 9){ + leftIsDown = true + startGesture(mouseX,mouseY) + } + + // left down ,was down + if (mask == 9){ + continueGesture(mouseX,mouseY) + } + + // left up ,was down + if (mask == 10){ + leftIsDown = false + endGesture(mouseX, mouseY) + } + } + + private fun startGesture(x: Int, y: Int) { + mPath = Path() + mPath.moveTo(x.toFloat(), y.toFloat()) + mLastGestureStartTime = System.currentTimeMillis() + } + + private fun continueGesture(x: Int, y: Int) { + mPath.lineTo(x.toFloat(), y.toFloat()) + } + @RequiresApi(Build.VERSION_CODES.N) + private fun endGesture(x: Int, y: Int) { + mPath.lineTo(x.toFloat(), y.toFloat()) + val stroke = GestureDescription.StrokeDescription( + mPath, + 0, + System.currentTimeMillis() - mLastGestureStartTime + ) + val builder = GestureDescription.Builder() + builder.addStroke(stroke) + Log.d(logTag, "end gesture $x $y") + dispatchGesture(builder.build(), object : GestureResultCallback() { + override fun onCompleted(gestureDescription: GestureDescription) { + super.onCompleted(gestureDescription) + Log.d(logTag, "滑动成功") + } + + override fun onCancelled(gestureDescription: GestureDescription) { + super.onCancelled(gestureDescription) + Log.d(logTag, "滑动失败 ") + } + }, null) + } + + external fun init(ctx: Context) + + init { + System.loadLibrary("rustdesk") + } + + private val LOG_TAG = "INPUT_LOG" + @RequiresApi(Build.VERSION_CODES.O) + override fun onServiceConnected() { + super.onServiceConnected() + Log.d(LOG_TAG,"onServiceConnected!") + init(this) + } + override fun onAccessibilityEvent(event: AccessibilityEvent?) { +// TODO("Not yet implemented") + } + + override fun onInterrupt() { +// TODO("Not yet implemented") + } +} \ No newline at end of file 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 393e96a98..372bd3cfe 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 @@ -1,12 +1,14 @@ package com.carriez.flutter_hbb import android.app.Activity +import android.app.AlertDialog import android.content.Context import android.content.Intent import android.media.projection.MediaProjectionManager import android.os.Build import android.os.Bundle import android.os.PersistableBundle +import android.provider.Settings import android.util.Log import androidx.annotation.RequiresApi import io.flutter.embedding.android.FlutterActivity @@ -50,6 +52,10 @@ class MainActivity : FlutterActivity() { mStopService() result.success(true) } + "checkInput" ->{ + checkInput() + result.success(true) + } else -> {} } } @@ -96,6 +102,25 @@ class MainActivity : FlutterActivity() { } } + private fun checkInput() { + AlertDialog.Builder(this) + .setCancelable(false) + .setTitle("检查Input服务") + .setMessage("请开启相关服务") + .setPositiveButton("Yes") { dialog, which -> + val intent = Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS) + if (intent.resolveActivity(packageManager) != null) startActivityForResult( + intent, + 11 + ) else AlertDialog.Builder(this) + .setTitle("错误") + .setMessage("无法启动服务") + .show() + } + .setNegativeButton("No") { dialog, which -> } + .show() + } + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { super.onActivityResult(requestCode, resultCode, data) if (resultCode == Activity.RESULT_OK && data != null) { 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 77b2f9c9e..1c6fba716 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 @@ -34,11 +34,11 @@ const val M_KEY_FRAME_RATE = 30 class MainService : Service() { - fun rustGetRaw():ByteArray{ + fun rustGetRaw(): ByteArray { return rawByteArray!! } - external fun init(ctx:Context) + external fun init(ctx: Context) init { System.loadLibrary("rustdesk") @@ -49,7 +49,7 @@ class MainService : Service() { private var surface: Surface? = null private val singleThread = Executors.newSingleThreadExecutor() private var mEncoder: MediaCodec? = null - private var rawByteArray :ByteArray? = null + private var rawByteArray: ByteArray? = null override fun onBind(intent: Intent): IBinder? { return null @@ -90,7 +90,8 @@ class MainService : Service() { return super.onStartCommand(intent, flags, startId) } - lateinit var mImageReader:ImageReader // * 注意 这里要成为成员变量,防止被回收 https://www.cnblogs.com/yongdaimi/p/11004560.html + lateinit var mImageReader: ImageReader // * 注意 这里要成为成员变量,防止被回收 https://www.cnblogs.com/yongdaimi/p/11004560.html + @SuppressLint("WrongConstant") @RequiresApi(Build.VERSION_CODES.LOLLIPOP) private fun startRecorder() { @@ -100,23 +101,23 @@ class MainService : Service() { mImageReader = ImageReader.newInstance(FIXED_WIDTH, FIXED_HEIGHT, PixelFormat.RGBA_8888, 2) // 至少是2 mImageReader.setOnImageAvailableListener({ imageReader: ImageReader -> - Log.d(logTag, "on image") - try { - imageReader.acquireLatestImage().use { image -> - if (image == null) return@setOnImageAvailableListener - val planes = image.planes - val buffer = planes[0].buffer - buffer.rewind() - // 这里注意 处理不当会引发OOM - if (rawByteArray == null){ - rawByteArray = ByteArray(buffer.capacity()) - buffer.get(rawByteArray!!) - }else{ - buffer.get(rawByteArray!!) - } +// Log.d(logTag, "on image") + try { + imageReader.acquireLatestImage().use { image -> + if (image == null) return@setOnImageAvailableListener + val planes = image.planes + val buffer = planes[0].buffer + buffer.rewind() + // 这里注意 处理不当会引发OOM + if (rawByteArray == null) { + rawByteArray = ByteArray(buffer.capacity()) + buffer.get(rawByteArray!!) + } else { + buffer.get(rawByteArray!!) } - } catch (ignored: java.lang.Exception) { } + } catch (ignored: java.lang.Exception) { + } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { imageReader.discardFreeBuffers() } diff --git a/android/app/src/main/res/values/strings.xml b/android/app/src/main/res/values/strings.xml new file mode 100644 index 000000000..9acb4104b --- /dev/null +++ b/android/app/src/main/res/values/strings.xml @@ -0,0 +1,4 @@ + + RustDesk + 测试服务 输入服务 + \ No newline at end of file diff --git a/android/app/src/main/res/xml/accessibility_service_config.xml b/android/app/src/main/res/xml/accessibility_service_config.xml new file mode 100644 index 000000000..fa9407128 --- /dev/null +++ b/android/app/src/main/res/xml/accessibility_service_config.xml @@ -0,0 +1,6 @@ + diff --git a/android/build.gradle b/android/build.gradle index 110174e8d..18592b640 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -7,7 +7,7 @@ buildscript { dependencies { classpath 'com.android.tools.build:gradle:4.1.0' - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.10" classpath 'com.google.gms:google-services:4.3.3' } } diff --git a/lib/home_page.dart b/lib/home_page.dart index 70f444703..8d5cde352 100644 --- a/lib/home_page.dart +++ b/lib/home_page.dart @@ -100,7 +100,8 @@ class _HomePageState extends State { getPeers(), ElevatedButton(onPressed:_toAndroidGetPer, child: Text("获取权限事件")), ElevatedButton(onPressed:_toAndroidStartSer, child: Text("开启录屏服务")), - ElevatedButton(onPressed:_toAndroidStopSer, child: Text("停止录屏服务")) + ElevatedButton(onPressed:_toAndroidStopSer, child: Text("停止录屏服务")), + ElevatedButton(onPressed:_toAndroidCheckInput, child: Text("检查输入权限")), ]), )); } @@ -116,6 +117,10 @@ class _HomePageState extends State { bool res = await toAndroidChannel.invokeMethod("stopSer"); debugPrint("_toAndroidStopSer:$res"); } + Future _toAndroidCheckInput() async{ + bool res = await toAndroidChannel.invokeMethod("checkInput"); + debugPrint("_toAndroidStopSer:$res"); +} void onConnect() { var id = _idController.text.trim();