refactor: 优化注释格式并修复WebSocket错误处理

This commit is contained in:
TongTongStudio
2026-07-26 21:40:51 +08:00
parent 63adb7f9f6
commit 11173eb04c

View File

@@ -10,43 +10,40 @@ import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.pm.ServiceInfo; import android.content.pm.ServiceInfo;
import android.media.projection.MediaProjection; import android.media.projection.MediaProjection;
import android.media.projection.MediaProjectionManager;
import android.os.Binder; import android.os.Binder;
import android.os.Build; import android.os.Build;
import android.os.Handler; import android.os.Handler;
import android.os.IBinder; import android.os.IBinder;
import android.os.Looper; import android.os.Looper;
import android.text.TextUtils;
import android.widget.Toast;
import android.util.DisplayMetrics; import android.util.DisplayMetrics;
import android.util.Log; import android.util.Log;
import android.view.WindowManager; import android.view.WindowManager;
import android.widget.Toast;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.core.app.NotificationCompat; import androidx.core.app.NotificationCompat;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.ttstd.control.Action;
import com.ttstd.control.ControlMessage;
import com.ttstd.controlled.R; import com.ttstd.controlled.R;
import com.ttstd.controlled.accessibility.KeyboardAccessibilityService;
import com.ttstd.controlled.activity.connection.ConnectionRequestActivity; import com.ttstd.controlled.activity.connection.ConnectionRequestActivity;
import com.ttstd.controlled.activity.main.MainActivity; import com.ttstd.controlled.activity.main.MainActivity;
import com.ttstd.controlled.accessibility.KeyboardAccessibilityService;
import com.ttstd.controlled.input.AccessibilityInputUtils; import com.ttstd.controlled.input.AccessibilityInputUtils;
import com.ttstd.controlled.input.InputCommandHandler; import com.ttstd.controlled.input.InputCommandHandler;
import com.ttstd.controlled.input.InputExecutor; import com.ttstd.controlled.input.InputExecutor;
import com.ttstd.controlled.input.RootShellInputUtils; import com.ttstd.controlled.input.RootShellInputUtils;
import com.ttstd.controlled.input.ShellInputUtils; import com.ttstd.controlled.input.ShellInputUtils;
import com.ttstd.controlled.input.SystemInputUtils; import com.ttstd.controlled.input.SystemInputUtils;
import com.ttstd.controlled.utils.SignatureUtils;
import com.ttstd.controlled.utils.InputSettings;
import com.ttstd.controlled.signaling.SignalMessage; import com.ttstd.controlled.signaling.SignalMessage;
import com.ttstd.controlled.utils.AuthSettings;
import com.ttstd.controlled.signaling.WebSocketClient; import com.ttstd.controlled.signaling.WebSocketClient;
import com.ttstd.controlled.webrtc.WebRtcClient; import com.ttstd.controlled.utils.AuthSettings;
import com.ttstd.controlled.utils.InputSettings;
import com.ttstd.controlled.utils.SignatureUtils;
import com.ttstd.controlled.webrtc.SelfCodecEncoder; import com.ttstd.controlled.webrtc.SelfCodecEncoder;
import com.ttstd.control.Action; import com.ttstd.controlled.webrtc.WebRtcClient;
import com.ttstd.control.ControlMessage;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import org.webrtc.EglBase; import org.webrtc.EglBase;
import org.webrtc.IceCandidate; import org.webrtc.IceCandidate;
@@ -63,7 +60,9 @@ public class ScreenCaptureService extends Service {
public static final String EXTRA_SERVER_URL = "server_url"; public static final String EXTRA_SERVER_URL = "server_url";
public static final String EXTRA_DEVICE_ID = "device_id"; public static final String EXTRA_DEVICE_ID = "device_id";
/** 静态授权结果,解决部分 Android 10 设备跨进程/Intent 传递 Intent 时 Token 失效的问题 */ /**
* 静态授权结果,解决部分 Android 10 设备跨进程/Intent 传递 Intent 时 Token 失效的问题
*/
public static int sResultCode = Activity.RESULT_CANCELED; public static int sResultCode = Activity.RESULT_CANCELED;
public static Intent sResultData = null; public static Intent sResultData = null;
@@ -74,34 +73,52 @@ public class ScreenCaptureService extends Service {
private EglBase eglBase; private EglBase eglBase;
private final Gson gson = new Gson(); private final Gson gson = new Gson();
/** 标记服务是否已经初始化,避免 onStartCommand 多次调用导致重复创建 */ /**
* 标记服务是否已经初始化,避免 onStartCommand 多次调用导致重复创建
*/
private boolean isInitialized = false; private boolean isInitialized = false;
/** 静态实例引用,供弹窗 Activity 在无需绑定的情况下回调本服务。 */ /**
* 静态实例引用,供弹窗 Activity 在无需绑定的情况下回调本服务。
*/
private static ScreenCaptureService instance; private static ScreenCaptureService instance;
public static ScreenCaptureService getInstance() { public static ScreenCaptureService getInstance() {
return instance; return instance;
} }
/** 本设备 ID注册到信令服务器用保存为字段以便弹窗回调使用。 */ /**
* 本设备 ID注册到信令服务器用保存为字段以便弹窗回调使用。
*/
private String deviceId; private String deviceId;
/** 当前待处理的连接请求OFFER信息供用户在弹窗中确认或拒绝。 */ /**
* 当前待处理的连接请求OFFER信息供用户在弹窗中确认或拒绝。
*/
private String pendingControllerId; private String pendingControllerId;
private String pendingControllerName; private String pendingControllerName;
private String pendingOfferSdp; private String pendingOfferSdp;
/** 当前正在控制本设备的控制端名称(用户名或设备 ID用于断开提示。 */ /**
* 当前正在控制本设备的控制端名称(用户名或设备 ID用于断开提示。
*/
private String controllingName; private String controllingName;
/** 设备真实屏幕分辨率,用于分辨率切换时按宽高比计算采集尺寸。 */ /**
* 设备真实屏幕分辨率,用于分辨率切换时按宽高比计算采集尺寸。
*/
private int realScreenWidth; private int realScreenWidth;
private int realScreenHeight; private int realScreenHeight;
/** 当前实际采集分辨率与帧率(运行时可被本地/远端请求切换)。 */ /**
* 当前实际采集分辨率与帧率(运行时可被本地/远端请求切换)。
*/
private int currentCaptureWidth; private int currentCaptureWidth;
private int currentCaptureHeight; private int currentCaptureHeight;
private int currentCaptureFps; private int currentCaptureFps;
/** 主线程 Handler用于从 WebRTC 回调线程切回主线程执行 UI 提示。 */ /**
* 主线程 Handler用于从 WebRTC 回调线程切回主线程执行 UI 提示。
*/
private final Handler mainHandler = new Handler(Looper.getMainLooper()); private final Handler mainHandler = new Handler(Looper.getMainLooper());
/** 标记服务是否正在关闭,避免重复停止/重复弹窗。 */ /**
* 标记服务是否正在关闭,避免重复停止/重复弹窗。
*/
private boolean isShuttingDown = false; private boolean isShuttingDown = false;
// ---- 屏幕串流"自编码"模式 ---- // ---- 屏幕串流"自编码"模式 ----
@@ -190,7 +207,8 @@ public class ScreenCaptureService extends Service {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
try { try {
refreshRate = wm.getDefaultDisplay().getRefreshRate(); refreshRate = wm.getDefaultDisplay().getRefreshRate();
} catch (Exception ignored) {} } catch (Exception ignored) {
}
} }
int fps = Math.round(refreshRate); int fps = Math.round(refreshRate);
// 屏幕控制 30fps 已足够跟手,并显著降低 H264 硬编延迟(影响“跟手”体验)。 // 屏幕控制 30fps 已足够跟手,并显著降低 H264 硬编延迟(影响“跟手”体验)。
@@ -301,23 +319,30 @@ public class ScreenCaptureService extends Service {
/** /**
* 切换屏幕采集分辨率(本地 UI 调用)。 * 切换屏幕采集分辨率(本地 UI 调用)。
*
* @param longEdge 目标长边像素;<=0 表示使用设备原生分辨率(按屏幕宽高比缩放)。 * @param longEdge 目标长边像素;<=0 表示使用设备原生分辨率(按屏幕宽高比缩放)。
*/ */
public void changeResolutionByLongEdge(int longEdge) { public void changeResolutionByLongEdge(int longEdge) {
requestResolutionChange(longEdge, 0, 0, false); requestResolutionChange(longEdge, 0, 0, false);
} }
/** 返回当前采集分辨率(宽/高/帧率)。 */ /**
* 返回当前采集分辨率(宽/高/帧率)。
*/
public int[] getCurrentCaptureResolution() { public int[] getCurrentCaptureResolution() {
return new int[]{ currentCaptureWidth, currentCaptureHeight, currentCaptureFps }; return new int[]{currentCaptureWidth, currentCaptureHeight, currentCaptureFps};
} }
/** 返回设备原生分辨率的长边(像素),供 UI 生成“原始画质”选项。 */ /**
* 返回设备原生分辨率的长边(像素),供 UI 生成“原始画质”选项。
*/
public int getNativeLongEdge() { public int getNativeLongEdge() {
return Math.max(realScreenWidth, realScreenHeight); return Math.max(realScreenWidth, realScreenHeight);
} }
/** 控制端经 DataChannel 发来的 SET_RESOLUTION 指令入口。 */ /**
* 控制端经 DataChannel 发来的 SET_RESOLUTION 指令入口。
*/
private void onRemoteResolutionRequested(int width, int height, int fps) { private void onRemoteResolutionRequested(int width, int height, int fps) {
requestResolutionChange(width, height, fps, true); requestResolutionChange(width, height, fps, true);
} }
@@ -368,7 +393,9 @@ public class ScreenCaptureService extends Service {
} }
} }
/** 根据指令参数解析出最终采集尺寸(保留屏幕宽高比、偶数对齐)。 */ /**
* 根据指令参数解析出最终采集尺寸(保留屏幕宽高比、偶数对齐)。
*/
private int[] resolveCaptureSize(int width, int height) { private int[] resolveCaptureSize(int width, int height) {
int w, h; int w, h;
if (width <= 0) { if (width <= 0) {
@@ -388,12 +415,14 @@ public class ScreenCaptureService extends Service {
if (h % 2 != 0) h--; if (h % 2 != 0) h--;
if (w <= 0) w = 2; if (w <= 0) w = 2;
if (h <= 0) h = 2; if (h <= 0) h = 2;
return new int[]{ w, h }; return new int[]{w, h};
} }
// ---- 屏幕串流"自编码"模式 ---- // ---- 屏幕串流"自编码"模式 ----
/** 控制端经 SET_STREAM_MODE 请求切换串流模式。 */ /**
* 控制端经 SET_STREAM_MODE 请求切换串流模式。
*/
private void onStreamModeRequested(int mode) { private void onStreamModeRequested(int mode) {
setStreamMode(mode); setStreamMode(mode);
} }
@@ -429,12 +458,16 @@ public class ScreenCaptureService extends Service {
reportStreamMode(mode); reportStreamMode(mode);
} }
/** 返回当前串流模式。 */ /**
* 返回当前串流模式。
*/
public int getCurrentStreamMode() { public int getCurrentStreamMode() {
return currentStreamMode; return currentStreamMode;
} }
/** 启动自编码通道。返回 false 表示启动失败(调用方应回退 WebRTC 模式)。 */ /**
* 启动自编码通道。返回 false 表示启动失败(调用方应回退 WebRTC 模式)。
*/
private boolean startSelfCodecEncoder() { private boolean startSelfCodecEncoder() {
if (selfEncoder != null) { if (selfEncoder != null) {
Log.w(TAG, "self codec encoder already running"); Log.w(TAG, "self codec encoder already running");
@@ -490,7 +523,9 @@ public class ScreenCaptureService extends Service {
} }
} }
/** 经 control DataChannel 向控制端回报当前生效的串流模式。 */ /**
* 经 control DataChannel 向控制端回报当前生效的串流模式。
*/
private void reportStreamMode(int mode) { private void reportStreamMode(int mode) {
if (webRtcClient == null) return; if (webRtcClient == null) return;
try { try {
@@ -508,9 +543,14 @@ public class ScreenCaptureService extends Service {
* 状态回调。由已 bind 的 MainActivity 注册,用于把连接状态同步到界面。 * 状态回调。由已 bind 的 MainActivity 注册,用于把连接状态同步到界面。
*/ */
public interface ServiceStateListener { public interface ServiceStateListener {
/** 信令服务器断开WebSocket 断开)。 */ /**
* 信令服务器断开WebSocket 断开)。
*/
void onSignalDisconnected(); void onSignalDisconnected();
/** 远程控制端断开,参数为控制端名称(用户名或设备 ID。 */
/**
* 远程控制端断开,参数为控制端名称(用户名或设备 ID
*/
void onControllerDisconnected(String name); void onControllerDisconnected(String name);
} }
@@ -586,11 +626,9 @@ public class ScreenCaptureService extends Service {
@Override @Override
public void onError(String error) { public void onError(String error) {
Log.e(TAG, "WebSocket error: " + error); Log.e(TAG, "WebSocket onError: " + error);
if(TextUtils.isEmpty(error)){
mainHandler.post(() -> onSignalServerDisconnected()); mainHandler.post(() -> onSignalServerDisconnected());
} }
}
@Override @Override
public void onMessage(SignalMessage message) { public void onMessage(SignalMessage message) {
@@ -730,7 +768,9 @@ public class ScreenCaptureService extends Service {
return "未知的鉴权类型: " + authType; return "未知的鉴权类型: " + authType;
} }
/** 鉴权失败时,向控制端回送带原因的拒绝消息并清理待处理状态。 */ /**
* 鉴权失败时,向控制端回送带原因的拒绝消息并清理待处理状态。
*/
private void sendAuthRejected(String reason) { private void sendAuthRejected(String reason) {
if (pendingControllerId == null || wsClient == null) { if (pendingControllerId == null || wsClient == null) {
return; return;
@@ -860,6 +900,7 @@ public class ScreenCaptureService extends Service {
}; };
private int heartbeatCount = 0; private int heartbeatCount = 0;
private void updateNotificationHeartbeat() { private void updateNotificationHeartbeat() {
String dots = ""; String dots = "";
for (int i = 0; i < (heartbeatCount % 3) + 1; i++) dots += "."; for (int i = 0; i < (heartbeatCount % 3) + 1; i++) dots += ".";