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