Skip to content

Commit

Permalink
大版本更新
Browse files Browse the repository at this point in the history
大:
支持小窗模式
支持多设备同时连接
不在使用额外端口,仅使用ADB端口
小:
支持自定义是否修改分辨率
缩减应用体积
减少性能占用
可能修复了无法触控的bug
可能修复了端口转发失败的bug
修复一系列bug,减少崩溃
  • Loading branch information
mingzhixian committed May 29, 2023
1 parent 5737751 commit 074b309
Show file tree
Hide file tree
Showing 26 changed files with 1,139 additions and 521 deletions.
37 changes: 25 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,11 @@
- 得益于Scrcpy2.0集成了Sndcpy,支持了音频的传输(经测试游戏和音乐可以传输,通话不会流转)
- 在连接之初会自动根据主控端分辨率修改被控端分辨率,最大化利用主控端屏幕
- 良好的旋转支持
- 自动检测被控端屏幕状态,熄屏后自动亮屏,主控端在连接成功后永不熄屏
- 自动检测被控端屏幕状态,熄屏后自动亮屏
- 使用导航悬浮球提供导航,减少主被控端手势冲突
- 超快启动
- 较低的延迟
- 支持小窗显示

## 使用步骤

Expand All @@ -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)
## 截图

<img src="https://github.com/mingzhixian/scrcpy/blob/master/pic/演示.gif" width="200px">
<img src="https://github.com/mingzhixian/scrcpy/blob/master/pic/软件界面.png" width="200px">
<img src="https://github.com/mingzhixian/scrcpy/blob/master/pic/添加设备.png" width="200px">
<img src="https://github.com/mingzhixian/scrcpy/blob/master/pic/小窗.png" width="200px">

## 鼓励
如果您觉得我的软件对您有帮助,可以赏俺一个硬币,万分感谢!
Expand Down
17 changes: 17 additions & 0 deletions scrcpy_android/.idea/deploymentTargetDropDown.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 2 additions & 4 deletions scrcpy_android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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")
Expand Down
5 changes: 2 additions & 3 deletions scrcpy_android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,17 @@
<uses-permission android:name="android.permission.EXPAND_STATUS_BAR" />

<application
android:icon="@mipmap/icon"
android:icon="@drawable/icon"
android:label="投屏"
android:screenOrientation="portrait"
android:supportsRtl="true"
android:theme="@style/Theme.AppCompat.Light.NoActionBar"
tools:targetApi="31" >
<activity
android:name=".MainActivity"
android:exported="true" >
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
Expand Down
Original file line number Diff line number Diff line change
@@ -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<Device>()

// 密钥文件
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()) {
Expand All @@ -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<TextView>(R.id.loading_text).text = text
if (isCanCancel) {
loading.findViewById<Button>(R.id.loading_cancel).visibility = View.VISIBLE
loading.findViewById<Button>(R.id.loading_cancel).setOnClickListener { cancelFun?.let { it1 -> it1() } }
} else loading.findViewById<Button>(R.id.loading_cancel).visibility = View.GONE
loadingDialog.show()
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ class DbHelper(
"\t maxSize integer,\n" +
"\t fps integer,\n" +
"\t videoBit integer," +
"\t setResolution integer" +
"\t setResolution integer,"+
"\t defaultFull integer"+
")"
)
}
Expand Down Expand Up @@ -80,7 +81,7 @@ class DbHelper(
// 删除旧表
db.execSQL("drop table DevicesDbOld")
}
// 修改列名,增加端口列
// 修改列名,增加默认全屏列、是否修改分辨率列
if (oldVersion < 4) {
// 修改表名
db!!.execSQL("alter table DevicesDb rename to DevicesDbOld")
Expand All @@ -94,7 +95,8 @@ class DbHelper(
"\t maxSize integer,\n" +
"\t fps integer,\n" +
"\t videoBit integer," +
"\t setResolution integer"+
"\t setResolution integer,"+
"\t defaultFull integer"+
")"
)
// 将数据搬移至新表
Expand All @@ -107,10 +109,13 @@ class DbHelper(
put("address", cursor.getString(cursor.getColumnIndex("address")))
put("port", cursor.getInt(cursor.getColumnIndex("port")))
put("videoCodec", cursor.getString(cursor.getColumnIndex("videoCodec")))
put("maxSize", cursor.getString(cursor.getColumnIndex("resolution")))
// 修改为默认值
put("maxSize", "1600")
put("fps", cursor.getString(cursor.getColumnIndex("fps")))
put("videoBit", cursor.getString(cursor.getColumnIndex("videoBit")))
// 修改为默认值
put("videoBit", "8000000")
put("setResolution", 1)
put("defaultFull", 1)
}
db.insert("DevicesDb", null, values)
} while (cursor.moveToNext())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@ class Device(
val maxSize: Int,
val fps: Int,
val videoBit: Int,
val setResolution:Boolean
val setResolution:Boolean,
val defaultFull:Boolean
){
var isFull=true
var status=-1
var isFull=defaultFull
// -10为停止状态,-1~-9为停止中,0为准备中,1为已连接ADB,2为已连接音视频,3为投屏中
var status=-10
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ class DeviceAdapter(private val main: MainActivity) :
holder.textViewAddress.text = address
// 单击打开投屏
holder.linearLayout.setOnClickListener {
Scrcpy(device, main).start()
if (device.status != -10) Toast.makeText(main, "此设备正在投屏或未完全关闭", Toast.LENGTH_SHORT).show()
else Scrcpy(device, main).start()
}
// 长按删除
holder.linearLayout.setOnLongClickListener {
Expand Down Expand Up @@ -71,6 +72,7 @@ class DeviceAdapter(private val main: MainActivity) :
fps: Int,
videoBit: Int,
setResolution: Boolean,
defaultFull: Boolean
) {
val values = ContentValues().apply {
put("name", name)
Expand All @@ -81,10 +83,23 @@ class DeviceAdapter(private val main: MainActivity) :
put("fps", fps)
put("videoBit", videoBit)
put("setResolution", if (setResolution) 1 else 0)
put("defaultFull", if (defaultFull) 1 else 0)
}
// 名称重复
if (main.appData.dbHelper.writableDatabase.insert("DevicesDb", null, values).toInt() != -1) {
main.appData.devices.add(Device(name, address, port, videoCodec, maxSize, fps, videoBit, setResolution))
main.appData.devices.add(
Device(
name,
address,
port,
videoCodec,
maxSize,
fps,
videoBit,
setResolution,
defaultFull
)
)
notifyDataSetChanged()
}
}
Expand Down
Loading

0 comments on commit 074b309

Please sign in to comment.