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