diff --git a/scrcpy_android/.idea/deploymentTargetDropDown.xml b/scrcpy_android/.idea/deploymentTargetDropDown.xml index 23521723..ea49ab6c 100644 --- a/scrcpy_android/.idea/deploymentTargetDropDown.xml +++ b/scrcpy_android/.idea/deploymentTargetDropDown.xml @@ -1,6 +1,17 @@ + + + + + + + + + + + @@ -12,6 +23,6 @@ - + \ No newline at end of file diff --git a/scrcpy_android/app/build.gradle b/scrcpy_android/app/build.gradle index 72cfa356..5e77169b 100644 --- a/scrcpy_android/app/build.gradle +++ b/scrcpy_android/app/build.gradle @@ -11,8 +11,8 @@ android { applicationId "top.saymzx.scrcpy.android" minSdk 23 targetSdk 33 - versionCode 1211 - versionName "12.1.1" + versionCode 1250 + versionName "12.5.0" resConfigs "zh" resConfigs "xhdpi" ndk { diff --git a/scrcpy_android/app/src/main/java/top/saymzx/scrcpy/adb/Adb.kt b/scrcpy_android/app/src/main/java/top/saymzx/scrcpy/adb/Adb.kt index f00b2bd1..2036973b 100644 --- a/scrcpy_android/app/src/main/java/top/saymzx/scrcpy/adb/Adb.kt +++ b/scrcpy_android/app/src/main/java/top/saymzx/scrcpy/adb/Adb.kt @@ -105,6 +105,8 @@ class Adb(host: String, port: Int, keyPair: AdbKeyPair) { fun tcpForward(port: Int, isNeedSource: Boolean): AdbStream = open("tcp:$port", isNeedSource) + fun localSocketForward(socketName: String, isNeedSource: Boolean): AdbStream = open("localabstract:$socketName", isNeedSource) + // 读取线程 private fun readAdb() { try { diff --git a/scrcpy_android/app/src/main/java/top/saymzx/scrcpy/adb/AdbWriter.kt b/scrcpy_android/app/src/main/java/top/saymzx/scrcpy/adb/AdbWriter.kt index 85e3c5a9..04875134 100644 --- a/scrcpy_android/app/src/main/java/top/saymzx/scrcpy/adb/AdbWriter.kt +++ b/scrcpy_android/app/src/main/java/top/saymzx/scrcpy/adb/AdbWriter.kt @@ -108,14 +108,11 @@ class AdbWriter(sink: Sink) : AutoCloseable { bufferedSink.close() } - companion object { - - private fun payloadChecksum(payload: ByteArray): Int { - var checksum = 0 - for (byte in payload) { - checksum += byte.toUByte().toInt() - } - return checksum + private fun payloadChecksum(payload: ByteArray): Int { + var checksum = 0 + for (byte in payload) { + checksum += byte.toUByte().toInt() } + return checksum } } \ No newline at end of file diff --git a/scrcpy_android/app/src/main/java/top/saymzx/scrcpy/android/MainActivity.kt b/scrcpy_android/app/src/main/java/top/saymzx/scrcpy/android/MainActivity.kt index 75eea530..689edcd4 100644 --- a/scrcpy_android/app/src/main/java/top/saymzx/scrcpy/android/MainActivity.kt +++ b/scrcpy_android/app/src/main/java/top/saymzx/scrcpy/android/MainActivity.kt @@ -1,22 +1,27 @@ package top.saymzx.scrcpy.android -import android.annotation.SuppressLint -import android.app.* -import android.content.* -import android.content.Intent.* -import android.media.* +import android.app.Activity +import android.app.AlertDialog +import android.content.Intent import android.net.Uri -import android.os.* +import android.os.Bundle import android.provider.Settings -import android.view.* -import android.view.KeyEvent.* -import android.view.MotionEvent.* -import android.widget.* +import android.view.LayoutInflater +import android.view.View +import android.widget.ArrayAdapter +import android.widget.Toast import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelStore import androidx.lifecycle.ViewModelStoreOwner +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import top.saymzx.scrcpy.adb.Adb +import top.saymzx.scrcpy.adb.AdbKeyPair import top.saymzx.scrcpy.android.databinding.ActivityMainBinding import top.saymzx.scrcpy.android.databinding.AddDeviceBinding +import top.saymzx.scrcpy.android.databinding.EditPortBinding import top.saymzx.scrcpy.android.entity.Scrcpy import top.saymzx.scrcpy.android.entity.defaultAudioCodec import top.saymzx.scrcpy.android.entity.defaultFps @@ -26,10 +31,7 @@ import top.saymzx.scrcpy.android.entity.defaultSetResolution import top.saymzx.scrcpy.android.entity.defaultVideoBit import top.saymzx.scrcpy.android.entity.defaultVideoCodec import top.saymzx.scrcpy.android.helper.AppData -import java.io.* -import java.util.* -@SuppressLint("StaticFieldLeak") lateinit var appData: AppData class MainActivity : Activity(), ViewModelStoreOwner { @@ -56,6 +58,33 @@ class MainActivity : Activity(), ViewModelStoreOwner { this, ShowAppActivity::class.java ), 1 ) + else readMode() + } + + // 其他页面回调 + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { + // ShowApp页面回调 + if (requestCode == 1) { + readMode() + } + super.onActivityResult(requestCode, resultCode, data) + } + + // 选择模式 + private fun readMode() { + if (appData.settings.getInt("appMode", 1) == 1) { + asMaster() + } else { + asSlave() + } + } + + // 作为控制端 + private fun asMaster() { + // 检查权限 + checkPermission() + // 启动默认设备 + startDefault() // 设置设备列表适配器 setDevicesList() // 添加按钮监听 @@ -68,42 +97,20 @@ class MainActivity : Activity(), ViewModelStoreOwner { checkUpdate() } - override fun onResume() { - // 检查权限 - if (checkPermission()) { - // 仅在第一次启动默认设备 - if (!appData.isShowDefultDevice) { - appData.isShowDefultDevice = true - // 启动默认设备 - val defalueDevice = appData.settings.getString("DefaultDevice", "") - if (defalueDevice != "") { - for (i in appData.devices) { - if (i.name == defalueDevice) { - if (i.status == -1) { - i.scrcpy = Scrcpy(i) - i.scrcpy!!.start() - } - break - } + // 启动默认设备 + private fun startDefault() { + val defalueDevice = appData.settings.getString("DefaultDevice", "") + if (defalueDevice != "") { + for (i in appData.devices) { + if (i.name == defalueDevice) { + if (i.status == -1) { + i.scrcpy = Scrcpy(i) + i.scrcpy!!.start() } + break } } } - super.onResume() - } - - // 其他页面回调 - override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { - // ShowApp页面回调 - if (requestCode == 1) { - if (resultCode == 1) { - appData.settings.edit().apply { - putBoolean("FirstUse", false) - apply() - } - } - } - super.onActivityResult(requestCode, resultCode, data) } // 检查权限 @@ -236,6 +243,73 @@ class MainActivity : Activity(), ViewModelStoreOwner { } } + // 作为被控端 + private fun asSlave() { + // 防止多次调用 + if (mainActivity.addDevice.visibility == View.GONE) return + // 取消画面 + mainActivity.addDevice.visibility = View.GONE + mainActivity.set.visibility = View.GONE + // 要求用户输入ADB端口 + if (!appData.settings.getBoolean("isSetSlaveAdbPort", false)) setSlaveAdbPort() + else slaveBack() + } + + // 弹窗输入adb端口 + private fun setSlaveAdbPort() { + val builder: AlertDialog.Builder = AlertDialog.Builder(this) + builder.setCancelable(false) + val editPortDialog = builder.create() + editPortDialog.setCanceledOnTouchOutside(false) + editPortDialog.window?.setBackgroundDrawableResource(android.R.color.transparent) + val editPortBinding = EditPortBinding.inflate(LayoutInflater.from(this)) + editPortDialog.setView(editPortBinding.root) + // 设置监听 + editPortBinding.editPortOk.setOnClickListener { + appData.settings.edit().apply { + putBoolean("isSetSlaveAdbPort", true) + putInt( + "slaveAdbPort", + editPortBinding.editPortPort.text.toString().toInt() + ) + apply() + } + editPortDialog.cancel() + slaveBack() + } + editPortDialog.show() + } + + // 恢复 + private fun slaveBack() { + appData.mainScope.launch { + withContext(Dispatchers.IO) { + try { + val adb = Adb( + "127.0.0.1", + appData.settings.getInt("slaveAdbPort", 5555), + AdbKeyPair.read(appData.privateKey, appData.publicKey) + ) + adb.runAdbCmd( + "ps aux | grep scrcpy | grep -v grep | awk '{print \$2}' | xargs kill -9", false + ) + adb.runAdbCmd("wm size reset", false) + adb.close() + withContext(Dispatchers.Main) { + Toast.makeText(appData.main, "恢复程序执行完毕,将自动退出", Toast.LENGTH_LONG).show() + delay(1000) + finishAndRemoveTask() + Runtime.getRuntime().exit(0) + } + } catch (_: Exception) { + withContext(Dispatchers.Main) { + Toast.makeText(appData.main, "连接失败", Toast.LENGTH_LONG).show() + } + } + } + } + } + // ViewModel override fun getViewModelStore(): ViewModelStore { if (VIEWMODEL_STORE == null) { diff --git a/scrcpy_android/app/src/main/java/top/saymzx/scrcpy/android/SetActivity.kt b/scrcpy_android/app/src/main/java/top/saymzx/scrcpy/android/SetActivity.kt index df4a13f9..d43286f3 100644 --- a/scrcpy_android/app/src/main/java/top/saymzx/scrcpy/android/SetActivity.kt +++ b/scrcpy_android/app/src/main/java/top/saymzx/scrcpy/android/SetActivity.kt @@ -1,6 +1,5 @@ package top.saymzx.scrcpy.android -import android.annotation.SuppressLint import android.app.Activity import android.content.Intent import android.net.Uri @@ -23,9 +22,7 @@ import top.saymzx.scrcpy.android.entity.defaultSetResolution import top.saymzx.scrcpy.android.entity.defaultVideoBit import top.saymzx.scrcpy.android.entity.defaultVideoCodec import java.io.File -import java.io.FileNotFoundException import java.io.FileOutputStream -import java.io.IOException class SetActivity : Activity() { private lateinit var setActivity: ActivitySetBinding @@ -346,7 +343,6 @@ class SetActivity : Activity() { Toast.makeText(this, "请不要选择Download或其他隐私位置", Toast.LENGTH_LONG).show() } - @SuppressLint("Range") override fun onActivityResult( requestCode: Int, resultCode: Int, resultData: Intent? ) { @@ -430,10 +426,7 @@ class SetActivity : Activity() { } } } - } catch (e: FileNotFoundException) { - e.printStackTrace() - } catch (e: IOException) { - e.printStackTrace() + } catch (_: Exception) { } } @@ -461,10 +454,7 @@ class SetActivity : Activity() { } } } - } catch (e: FileNotFoundException) { - e.printStackTrace() - } catch (e: IOException) { - e.printStackTrace() + } catch (_: Exception) { } return "" } diff --git a/scrcpy_android/app/src/main/java/top/saymzx/scrcpy/android/ShowAppActivity.kt b/scrcpy_android/app/src/main/java/top/saymzx/scrcpy/android/ShowAppActivity.kt index 20029022..a289d1e5 100644 --- a/scrcpy_android/app/src/main/java/top/saymzx/scrcpy/android/ShowAppActivity.kt +++ b/scrcpy_android/app/src/main/java/top/saymzx/scrcpy/android/ShowAppActivity.kt @@ -1,10 +1,14 @@ package top.saymzx.scrcpy.android import android.app.Activity +import android.app.AlertDialog import android.content.Intent import android.net.Uri import android.os.Bundle +import android.view.LayoutInflater +import android.widget.Toast import top.saymzx.scrcpy.android.databinding.ActivityShowAppBinding +import top.saymzx.scrcpy.android.databinding.ModeSelectBinding class ShowAppActivity : Activity() { @@ -14,6 +18,14 @@ class ShowAppActivity : Activity() { showAppActivity = ActivityShowAppBinding.inflate(layoutInflater) setContentView(showAppActivity.root) appData.publicTools.setStatusAndNavBar(this) + // 设置隐私用户政策 + setUserPriListener() + // 设置同意按钮 + setAgreeListener() + } + + // 设置隐私用户政策 + private fun setUserPriListener() { // 设置隐私政策链接 showAppActivity.showAppPrivacy.setOnClickListener { try { @@ -36,10 +48,43 @@ class ShowAppActivity : Activity() { } catch (_: Exception) { } } - // 设置下一步按钮 + } + + // 设置同意按钮 + private lateinit var modeSelectDialog: AlertDialog + private fun setAgreeListener() { showAppActivity.showAppAgree.setOnClickListener { - setResult(1) - finish() + // 弹窗选择模式 + val builder: AlertDialog.Builder = AlertDialog.Builder(this) + builder.setCancelable(false) + modeSelectDialog = builder.create() + modeSelectDialog.setCanceledOnTouchOutside(false) + modeSelectDialog.window?.setBackgroundDrawableResource(android.R.color.transparent) + val modeSelectBinding = ModeSelectBinding.inflate(LayoutInflater.from(this)) + modeSelectDialog.setView(modeSelectBinding.root) + modeSelectBinding.modeSelectMaster.setOnClickListener { + saveSet(1) + } + modeSelectBinding.modeSelectSlave.setOnClickListener { + saveSet(0) + } + modeSelectDialog.show() } } + + // 保存设置 + private fun saveSet(mode: Int) { + appData.settings.edit().apply { + putInt("appMode", mode) + putBoolean("FirstUse", false) + apply() + } + modeSelectDialog.cancel() + finish() + } + + // 禁止返回上一级 + override fun onBackPressed() { + Toast.makeText(this, "请先同意用户及隐私协议", Toast.LENGTH_SHORT).show() + } } \ No newline at end of file diff --git a/scrcpy_android/app/src/main/java/top/saymzx/scrcpy/android/entity/FloatVideo.kt b/scrcpy_android/app/src/main/java/top/saymzx/scrcpy/android/entity/FloatVideo.kt index 30440c56..2b7a82b6 100644 --- a/scrcpy_android/app/src/main/java/top/saymzx/scrcpy/android/entity/FloatVideo.kt +++ b/scrcpy_android/app/src/main/java/top/saymzx/scrcpy/android/entity/FloatVideo.kt @@ -16,9 +16,9 @@ import top.saymzx.scrcpy.android.databinding.FloatNavBinding import top.saymzx.scrcpy.android.databinding.FloatVideoBinding import java.nio.ByteBuffer import java.util.* +import kotlin.math.abs import kotlin.math.sqrt - @SuppressLint("ClickableViewAccessibility", "InternalInsetResource", "DiscouragedApi") class FloatVideo( private val device: Device, @@ -488,16 +488,31 @@ class FloatVideo( // 设置悬浮窗大小拖动按钮监听控制 private fun setSetSizeListener() { + var width = 0f + val maxCal = appData.publicTools.dp2px(30f) floatVideo.floatVideoSetSize.setOnTouchListener { _, event -> setFocus(true) - if (event.actionMasked == MotionEvent.ACTION_MOVE) { - // 计算新大小(等比缩放) - val tmpWidth = event.rawX - floatVideoParams.x - val tmpHeight = tmpWidth * remoteVideoHeight / remoteVideoWidth - // 最小300个像素 - if (tmpWidth < 300 || tmpHeight < 300) return@setOnTouchListener true - calculateFloatSize(tmpWidth.toInt(), tmpHeight.toInt()) - update(true) + when (event.actionMasked) { + MotionEvent.ACTION_DOWN -> { + width = event.rawX - floatVideoParams.x + } + + MotionEvent.ACTION_MOVE -> { + // 计算新大小(等比缩放) + val tmpWidth = event.rawX - floatVideoParams.x + val tmpHeight = tmpWidth * remoteVideoHeight / remoteVideoWidth + // 最小300个像素 + if (tmpWidth < 300 || tmpHeight < 300) return@setOnTouchListener true + calculateFloatSize(tmpWidth.toInt(), tmpHeight.toInt()) + if (abs(tmpWidth - width) > maxCal) { + width = tmpWidth + update(true) + } else update(false) + } + + MotionEvent.ACTION_UP -> { + update(true) + } } return@setOnTouchListener true } diff --git a/scrcpy_android/app/src/main/java/top/saymzx/scrcpy/android/entity/Scrcpy.kt b/scrcpy_android/app/src/main/java/top/saymzx/scrcpy/android/entity/Scrcpy.kt index 29a2409c..a8c3f03f 100644 --- a/scrcpy_android/app/src/main/java/top/saymzx/scrcpy/android/entity/Scrcpy.kt +++ b/scrcpy_android/app/src/main/java/top/saymzx/scrcpy/android/entity/Scrcpy.kt @@ -22,6 +22,9 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.delay import kotlinx.coroutines.launch import kotlinx.coroutines.withContext +import okhttp3.internal.notify +import okhttp3.internal.wait +import okio.Buffer import top.saymzx.scrcpy.adb.Adb import top.saymzx.scrcpy.adb.AdbKeyPair import top.saymzx.scrcpy.adb.AdbStream @@ -31,7 +34,6 @@ import top.saymzx.scrcpy.android.appData import java.net.Inet4Address import java.nio.ByteBuffer import java.nio.charset.StandardCharsets -import java.util.concurrent.LinkedBlockingQueue class Scrcpy(private val device: Device) { @@ -132,7 +134,7 @@ class Scrcpy(private val device: Device) { stop("投屏停止", e) } }.start() - // 控制报文 + // 控制 Thread { android.os.Process.setThreadPriority(THREAD_PRIORITY_LOWEST) try { @@ -141,7 +143,6 @@ class Scrcpy(private val device: Device) { stop("投屏停止", e) } }.start() - // 控制报文 Thread { android.os.Process.setThreadPriority(THREAD_PRIORITY_MORE_FAVORABLE) try { @@ -154,10 +155,13 @@ class Scrcpy(private val device: Device) { } // 停止投屏 + private val stopSetStatus = Object() fun stop(scrcpyError: String, e: Exception? = null) { // 防止多次调用 - if (device.status == -1) return - device.status = -1 + synchronized(stopSetStatus) { + if (device.status == -1) return + device.status = -1 + } appData.isFocus = false appData.mainScope.launch { withContext(Dispatchers.Main) { @@ -289,14 +293,14 @@ class Scrcpy(private val device: Device) { if (device.status == -1) return@withContext try { if (connect == 0) { - videoStream = adb.tcpForward(6006, true) + videoStream = adb.localSocketForward("scrcpy_android", true) connect = 1 } if (connect == 1) { - audioStream = adb.tcpForward(6006, true) + audioStream = adb.localSocketForward("scrcpy_android", true) connect = 2 } - controlStream = adb.tcpForward(6006, true) + controlStream = adb.localSocketForward("scrcpy_android", true) break } catch (_: Exception) { Log.i("Scrcpy", "连接失败,再次尝试") @@ -317,8 +321,10 @@ class Scrcpy(private val device: Device) { // 显示悬浮窗 floatVideo = FloatVideo(device, remoteVideoWidth, remoteVideoHeight) { - hasControls = true - controls.offer(it) + controls.write(it) + synchronized(controls) { + controls.notify() + } } } floatVideo.show() @@ -353,8 +359,12 @@ class Scrcpy(private val device: Device) { // 启动解码器 videoDecodec.start() // 解析首帧,解决开始黑屏问题 - pushCodec(videoDecodec, csd0) - pushCodec(videoDecodec, csd1) + var inIndex = videoDecodec.dequeueInputBuffer(-1) + videoDecodec.getInputBuffer(inIndex)!!.put(csd0) + videoDecodec.queueInputBuffer(inIndex, 0, csd0.size, 0, 0) + inIndex = videoDecodec.dequeueInputBuffer(-1) + videoDecodec.getInputBuffer(inIndex)!!.put(csd1) + videoDecodec.queueInputBuffer(inIndex, 0, csd1.size, 0, 0) } // 音频解码器 @@ -397,7 +407,7 @@ class Scrcpy(private val device: Device) { // 初始化音频播放器 private fun setAudioTrack() { val audioDecodecBuild = AudioTrack.Builder() - val sampleRate = 48000 + val sampleRate = 44100 val minBufferSize = AudioTrack.getMinBufferSize( sampleRate, AudioFormat.CHANNEL_OUT_STEREO, AudioFormat.ENCODING_PCM_16BIT ) @@ -430,13 +440,18 @@ class Scrcpy(private val device: Device) { // 开始解码 while (device.status == 1) { val buffer = readFrame(stream) - pushCodec(codec, buffer) - // 连续4个空包检测是否熄屏了 - if (buffer.size < 150) { - zeroFrameNum++ - if (zeroFrameNum > 4) { - zeroFrameNum = 0 - checkScreenOff() + val inIndex = codec.dequeueInputBuffer(-1) + if (inIndex >= 0) { + codec.getInputBuffer(inIndex)!!.put(buffer) + // 提交解码器解码 + codec.queueInputBuffer(inIndex, 0, buffer.size, 0, 0) + // 连续4个空包检测是否熄屏了 + if (buffer.size < 150) { + zeroFrameNum++ + if (zeroFrameNum > 4) { + zeroFrameNum = 0 + checkScreenOff() + } } } } @@ -448,7 +463,7 @@ class Scrcpy(private val device: Device) { val bufferInfo = MediaCodec.BufferInfo() while (device.status == 1) { // 找到已完成的输出缓冲区 - outIndex = videoDecodec.dequeueOutputBuffer(bufferInfo, 0) + outIndex = videoDecodec.dequeueOutputBuffer(bufferInfo, -1) if (outIndex >= 0) { // 是否需要检查旋转(仍需要检查,因为可能是90°和270°的旋转) if (checkRotationNotification) { @@ -462,9 +477,6 @@ class Scrcpy(private val device: Device) { } } videoDecodec.releaseOutputBuffer(outIndex, true) - } else if (outIndex != MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) { - Thread.sleep(4) - continue } } } @@ -473,7 +485,13 @@ class Scrcpy(private val device: Device) { private fun decodeAudioOutput() { var outIndex: Int val bufferInfo = MediaCodec.BufferInfo() + var loopNum = 0 while (device.status == 1) { + loopNum++ + if (loopNum > 200) { + loopNum = 0 + checkClipBoard() + } // 找到已完成的输出缓冲区 outIndex = audioDecodec.dequeueOutputBuffer(bufferInfo, 0) if (outIndex >= 0) { @@ -534,41 +552,16 @@ class Scrcpy(private val device: Device) { } // 控制报文输出 - private val controls = LinkedBlockingQueue() - private var hasControls = false + private val controls = Buffer() private fun setControlOutput() { - var loopNum = 0 while (device.status == 1) { - loopNum++ - if (loopNum > 200) { - loopNum = 0 - checkClipBoard() - } - if (!hasControls) { - Thread.sleep(4) - continue + if (!controls.request(1)) synchronized(controls) { + controls.wait() } - val buffer = controls.poll() - if (buffer == null) { - hasControls = false - continue - } - controlStream.write(buffer) + controlStream.write(controls.readByteArray()) } } - // 向解码器输入 - private fun pushCodec(codec: MediaCodec, buffer: ByteArray) { - var inIndex: Int - // 找到一个空的输入缓冲区 - do { - inIndex = codec.dequeueInputBuffer(0) - } while (inIndex <= 0) - codec.getInputBuffer(inIndex)!!.put(buffer) - // 提交解码器解码 - codec.queueInputBuffer(inIndex, 0, buffer.size, 0, 0) - } - // 防止被控端熄屏 private var isScreenOning = false private fun checkScreenOff() { @@ -579,7 +572,8 @@ class Scrcpy(private val device: Device) { if (!runAdbCmd("dumpsys deviceidle | grep mScreenOn", true).contains("mScreenOn=true")) { isScreenOning = true runAdbCmd("input keyevent 26", false) - delay(500) + delay(1000) + setPowerOff() isScreenOning = false } } catch (_: Exception) { @@ -591,8 +585,10 @@ class Scrcpy(private val device: Device) { // 被控端熄屏 private fun setPowerOff() { - hasControls = true - controls.offer(byteArrayOf(10, 0)) + controls.write(byteArrayOf(10, 0)) + synchronized(controls) { + controls.notify() + } } // 同步本机剪切板至被控端 @@ -617,8 +613,10 @@ class Scrcpy(private val device: Device) { byteBuffer.putInt(textByteArray.size) byteBuffer.put(textByteArray) byteBuffer.flip() - hasControls = true - controls.offer(byteBuffer.array()) + controls.write(byteBuffer) + synchronized(controls) { + controls.notify() + } } // 从socket流中解析数据 diff --git a/scrcpy_android/app/src/main/java/top/saymzx/scrcpy/android/helper/AppData.kt b/scrcpy_android/app/src/main/java/top/saymzx/scrcpy/android/helper/AppData.kt index d09e406c..5de1e50f 100644 --- a/scrcpy_android/app/src/main/java/top/saymzx/scrcpy/android/helper/AppData.kt +++ b/scrcpy_android/app/src/main/java/top/saymzx/scrcpy/android/helper/AppData.kt @@ -15,16 +15,11 @@ import top.saymzx.scrcpy.android.MainActivity import top.saymzx.scrcpy.android.entity.Device import java.io.File -@SuppressLint("Range") class AppData : ViewModel() { // 是否初始化 var isInit = false - // 是否显示默认设备 - var isShowDefultDevice = false - - @SuppressLint("StaticFieldLeak") lateinit var main: MainActivity // 是否处于专注模式 @@ -37,10 +32,10 @@ class AppData : ViewModel() { // 公共工具库 val publicTools = PublicTools() - // 数据库管理 + // 数据库工具 lateinit var dbHelper: DbHelper - // 网络管理 + // 网络工具 val netHelper = NetHelper() // 设备列表管理 @@ -98,6 +93,7 @@ class AppData : ViewModel() { } // 读取数据库设备列表 + @SuppressLint("Range") private fun readDeviceList() { val cursor = dbHelper.readableDatabase.query("DevicesDb", null, null, null, null, null, null) if (cursor.moveToFirst()) { diff --git a/scrcpy_android/app/src/main/java/top/saymzx/scrcpy/android/helper/DeviceListAdapter.kt b/scrcpy_android/app/src/main/java/top/saymzx/scrcpy/android/helper/DeviceListAdapter.kt index dde008bc..76d7aa86 100644 --- a/scrcpy_android/app/src/main/java/top/saymzx/scrcpy/android/helper/DeviceListAdapter.kt +++ b/scrcpy_android/app/src/main/java/top/saymzx/scrcpy/android/helper/DeviceListAdapter.kt @@ -1,6 +1,5 @@ package top.saymzx.scrcpy.android.helper -import android.annotation.SuppressLint import android.app.AlertDialog import android.content.ContentValues import android.view.View @@ -226,7 +225,6 @@ class DeviceListAdapter : BaseAdapter() { } //新建数据 - @SuppressLint("NotifyDataSetChanged") fun newDevice( name: String, address: String, diff --git a/scrcpy_android/app/src/main/java/top/saymzx/scrcpy/android/helper/NetHelper.kt b/scrcpy_android/app/src/main/java/top/saymzx/scrcpy/android/helper/NetHelper.kt index afb64483..8d9f1c34 100644 --- a/scrcpy_android/app/src/main/java/top/saymzx/scrcpy/android/helper/NetHelper.kt +++ b/scrcpy_android/app/src/main/java/top/saymzx/scrcpy/android/helper/NetHelper.kt @@ -12,7 +12,6 @@ import okhttp3.RequestBody.Companion.toRequestBody import org.json.JSONObject import top.saymzx.scrcpy.android.appData - class NetHelper { private val okhttpClient = OkHttpClient() diff --git a/scrcpy_android/app/src/main/java/top/saymzx/scrcpy/android/helper/PublicTools.kt b/scrcpy_android/app/src/main/java/top/saymzx/scrcpy/android/helper/PublicTools.kt index fb3708fa..53c2dc59 100644 --- a/scrcpy_android/app/src/main/java/top/saymzx/scrcpy/android/helper/PublicTools.kt +++ b/scrcpy_android/app/src/main/java/top/saymzx/scrcpy/android/helper/PublicTools.kt @@ -57,7 +57,7 @@ class PublicTools { val builder: AlertDialog.Builder = AlertDialog.Builder(context) builder.setCancelable(false) val loadingDialog = builder.create() - loadingDialog.setCanceledOnTouchOutside(false) + loadingDialog.setCanceledOnTouchOutside(isCanCancel) loadingDialog.window?.setBackgroundDrawableResource(android.R.color.transparent) val loadingBinding = LoadingBinding.inflate(LayoutInflater.from(context)) loadingDialog.setView(loadingBinding.root) diff --git a/scrcpy_android/app/src/main/res/layout/activity_main.xml b/scrcpy_android/app/src/main/res/layout/activity_main.xml index c23ca2c2..70cbdc57 100644 --- a/scrcpy_android/app/src/main/res/layout/activity_main.xml +++ b/scrcpy_android/app/src/main/res/layout/activity_main.xml @@ -13,7 +13,7 @@ android:id="@+id/set" android:layout_width="36dp" android:layout_height="36dp" - android:layout_marginTop="12dp" + android:layout_marginTop="16dp" android:layout_marginEnd="20dp" android:src="@drawable/set" app:layout_constraintEnd_toEndOf="parent" @@ -24,12 +24,12 @@ android:id="@+id/devices_list" android:layout_width="0dp" android:layout_height="match_parent" - android:layout_marginStart="30dp" - android:layout_marginTop="60dp" - android:layout_marginEnd="30dp" + android:layout_marginStart="20dp" + android:layout_marginTop="64dp" + android:layout_marginEnd="20dp" android:layout_marginBottom="20dp" android:divider="#00000000" - android:dividerHeight="10dp" + android:dividerHeight="12dp" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" diff --git a/scrcpy_back/app/src/main/res/layout/edit_port.xml b/scrcpy_android/app/src/main/res/layout/edit_port.xml similarity index 82% rename from scrcpy_back/app/src/main/res/layout/edit_port.xml rename to scrcpy_android/app/src/main/res/layout/edit_port.xml index 648960ca..0c55816c 100644 --- a/scrcpy_back/app/src/main/res/layout/edit_port.xml +++ b/scrcpy_android/app/src/main/res/layout/edit_port.xml @@ -8,7 +8,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@drawable/background" - android:backgroundTint="@color/alertBackground" + android:backgroundTint="@color/cardBackground" android:orientation="vertical"> + android:textColor="@color/onCardBackground" + android:textColorHint="@color/onCardBackgroundSecond" />