diff --git a/README.md b/README.md
index 4e655859..984b03a8 100644
--- a/README.md
+++ b/README.md
@@ -19,10 +19,11 @@
- 得益于Scrcpy2.0集成了Sndcpy,支持了音频的传输(经测试游戏和音乐可以传输,通话不会流转)
- 在连接之初会自动根据主控端分辨率修改被控端分辨率,最大化利用主控端屏幕
- 良好的旋转支持
-- 自动检测被控端屏幕状态,熄屏后自动亮屏,主控端在连接成功后永不熄屏
+- 自动检测被控端屏幕状态,熄屏后自动亮屏
- 使用导航悬浮球提供导航,减少主被控端手势冲突
- 超快启动
- 较低的延迟
+- 支持小窗显示
## 使用步骤
@@ -43,21 +44,33 @@ adb tcpip 5555
## 使用说明
-- 全屏悬浮窗显示投屏后的界面,主控端导航键不在起作用(类似于专注模式),如需退出投屏需按主控端电源键熄屏,也可以点按主控端通知栏消息
-- 分辨率在退出后会自动恢复,如果非正常退出导致被控端未恢复,可使用scrcpy_back
-- 投屏后声音会自动流转至主控端,音量大小受控于主控端,不需要调整被控端(除非被控端静音)
-- 因主控端手势先于本软件识别触摸,若系统判定为手势导航,会导致本软件捕捉不到触摸,本软件提供了悬浮导航球,帮助用户控制被控端,悬浮球单击为返回、双击为桌面、长按为最近任务,悬浮球可拖动
+### 默认选项
+
+- 默认全屏显示,可以在添加设备时修改高级选项使用小窗模式
+- 默认修改被控端分辨率,可以在添加设备时修改高级选项设置不修改
+- 默认分辨率为720p,帧率为60帧,码率为8M,编解码器为H264
+
+### 全屏模式
+
+- 请注意设备全屏控制后无法不中断恢复为小窗
+- 设备全屏控制后进入专注模式,如需退出投屏需按主控端电源键熄屏,也可以点按主控端通知栏消息
+- 设备全屏控制后使用悬浮导航球导航,单击为返回、双击为桌面、长按为最近任务,悬浮球可拖动
-## 未来?
+### 小窗模式
-本软件的出现是我写给我妈妈使用,目前已经满足需求,不会考虑大的更新,小bug会修复
-- 软件最低安卓6.0,应该不会降低最低版本,适配工作量大
-- 有线控制,没想法,我认为有线并不舒服,减少的那点延迟不明显,我妈妈现在手机放家里随便一个地方,平板拿起来点击投屏就行,出门才用手机,在家平板大屏幕才爽
+- 小窗模式可以通过横条拖动,双机横条全屏控制
+- 小窗模式点击右上角红点为关闭投屏,拖动右下角白点为更改小窗大小
+
+### 其他
+
+- 分辨率在退出后会自动恢复,如果非正常退出导致被控端未恢复,可使用scrcpy_back
+- 投屏后声音会自动流转至主控端,音量大小受控于主控端,不需要调整被控端(除非被控端静音)
-## 演示
-4.4MB大小,可能加载较慢,可直接前往[此处查看](https://github.com/mingzhixian/scrcpy/blob/master/pic/演示.gif)
+## 截图
-
+
+
+
## 鼓励
如果您觉得我的软件对您有帮助,可以赏俺一个硬币,万分感谢!
diff --git a/scrcpy_android/.idea/deploymentTargetDropDown.xml b/scrcpy_android/.idea/deploymentTargetDropDown.xml
new file mode 100644
index 00000000..f2ec85b1
--- /dev/null
+++ b/scrcpy_android/.idea/deploymentTargetDropDown.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/scrcpy_android/app/build.gradle b/scrcpy_android/app/build.gradle
index ada85bc0..63bdbf1c 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 80
- versionName "8.0"
+ versionCode 82
+ versionName "8.2"
resConfigs "zh"
resConfigs "xhdpi"
ndk {
@@ -47,8 +47,6 @@ dependencies {
implementation 'androidx.recyclerview:recyclerview:1.3.0'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.1'
- implementation 'com.malinskiy.adam:adam:0.5.1'
-
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
implementation("dev.mobile:dadb:1.2.6")
diff --git a/scrcpy_android/app/src/main/AndroidManifest.xml b/scrcpy_android/app/src/main/AndroidManifest.xml
index 51b57216..3d02ef23 100644
--- a/scrcpy_android/app/src/main/AndroidManifest.xml
+++ b/scrcpy_android/app/src/main/AndroidManifest.xml
@@ -11,7 +11,7 @@
+ android:exported="true">
-
diff --git a/scrcpy_android/app/src/main/java/top/saymzx/scrcpy_android/AppData.kt b/scrcpy_android/app/src/main/java/top/saymzx/scrcpy_android/AppData.kt
index 5e5a07f4..1eb08581 100644
--- a/scrcpy_android/app/src/main/java/top/saymzx/scrcpy_android/AppData.kt
+++ b/scrcpy_android/app/src/main/java/top/saymzx/scrcpy_android/AppData.kt
@@ -1,25 +1,56 @@
package top.saymzx.scrcpy_android
import android.annotation.SuppressLint
+import android.app.AlertDialog
+import android.util.DisplayMetrics
+import android.view.LayoutInflater
+import android.view.View
+import android.widget.Button
+import android.widget.TextView
import androidx.lifecycle.ViewModel
-import com.malinskiy.adam.AndroidDebugBridgeClient
-import com.malinskiy.adam.AndroidDebugBridgeClientFactory
-import com.malinskiy.adam.interactor.StartAdbInteractor
-import kotlinx.coroutines.GlobalScope
-import kotlinx.coroutines.launch
+import dadb.AdbKeyPair
+import java.io.File
@SuppressLint("Range")
-class AppData(): ViewModel() {
+class AppData : ViewModel() {
+
+ // 是否初始化
+ var isInit=false
- // ADB客户端
- lateinit var adb: AndroidDebugBridgeClient
// 数据库管理
- lateinit var dbHelper:DbHelper
+ lateinit var dbHelper: DbHelper
+ lateinit var deviceAdapter: DeviceAdapter
+
// 设备列表
val devices = ArrayList()
+ // 密钥文件
+ lateinit var privateKey: File
+ lateinit var publicKey: File
+
+ // 系统分辨率
+ var deviceWidth = 0
+ var deviceHeight = 0
+
+ // 加载框(全局通用)
+ @SuppressLint("StaticFieldLeak")
+ lateinit var loadingDialog: AlertDialog
+ @SuppressLint("StaticFieldLeak")
+ lateinit var loading: View
+
// 初始化数据
- fun init() {
+ fun init(main: MainActivity) {
+ isInit=true
+ // 获取系统分辨率
+ val metric = DisplayMetrics()
+ main.windowManager.defaultDisplay.getRealMetrics(metric)
+ deviceWidth = metric.widthPixels
+ deviceHeight = metric.heightPixels
+ if (deviceWidth > deviceHeight) deviceWidth =
+ deviceWidth xor deviceHeight xor deviceWidth.also { deviceHeight = it }
+ // 数据库管理
+ dbHelper = DbHelper(main, "scrcpy_android.db", 4)
+ deviceAdapter = DeviceAdapter(main)
// 从数据库获取设备列表
val cursor = dbHelper.readableDatabase.query("DevicesDb", null, null, null, null, null, null)
if (cursor.moveToFirst()) {
@@ -33,11 +64,37 @@ class AppData(): ViewModel() {
cursor.getInt(cursor.getColumnIndex("maxSize")),
cursor.getInt(cursor.getColumnIndex("fps")),
cursor.getInt(cursor.getColumnIndex("videoBit")),
- cursor.getInt(cursor.getColumnIndex("isFull")) == 1
+ cursor.getInt(cursor.getColumnIndex("setResolution")) == 1,
+ cursor.getInt(cursor.getColumnIndex("defaultFull")) == 1
)
)
} while (cursor.moveToNext())
}
cursor.close()
+ // 密钥文件
+ privateKey = File(main.applicationContext.filesDir, "private.key")
+ publicKey = File(main.applicationContext.filesDir, "public.key")
+ if (!privateKey.isFile || !publicKey.isFile) {
+ AdbKeyPair.generate(privateKey, publicKey)
+ }
+ // 加载框
+ val builder: AlertDialog.Builder = AlertDialog.Builder(main)
+ builder.setCancelable(false)
+ loadingDialog = builder.create()
+ loadingDialog.setCanceledOnTouchOutside(false)
+ loadingDialog.window?.setBackgroundDrawableResource(android.R.color.transparent)
+ loading = LayoutInflater.from(main).inflate(R.layout.loading, null, false)
+ main.appData.loadingDialog.setView(loading)
+ }
+
+ // 显示加载框
+ fun showLoading(text: String, isCanCancel: Boolean, cancelFun: (() -> Unit)?) {
+ loading.findViewById(R.id.loading_text).text = text
+ if (isCanCancel) {
+ loading.findViewById