feat: 改为MVVM
This commit is contained in:
@@ -17,7 +17,7 @@
|
|||||||
android:theme="@style/Theme.MaterialComponents.DayNight">
|
android:theme="@style/Theme.MaterialComponents.DayNight">
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".MainActivity"
|
android:name=".activity.main.MainActivity"
|
||||||
android:exported="true">
|
android:exported="true">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.ttstd.controlled;
|
package com.ttstd.controlled.activity.main;
|
||||||
|
|
||||||
import android.Manifest;
|
import android.Manifest;
|
||||||
import android.content.ComponentName;
|
import android.content.ComponentName;
|
||||||
@@ -8,39 +8,29 @@ import android.content.ServiceConnection;
|
|||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.media.projection.MediaProjectionManager;
|
import android.media.projection.MediaProjectionManager;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.widget.Button;
|
|
||||||
import android.widget.EditText;
|
|
||||||
import android.widget.TextView;
|
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.appcompat.app.AppCompatActivity;
|
|
||||||
import androidx.core.app.ActivityCompat;
|
import androidx.core.app.ActivityCompat;
|
||||||
import androidx.core.content.ContextCompat;
|
import androidx.core.content.ContextCompat;
|
||||||
|
|
||||||
|
import com.ttstd.controlled.R;
|
||||||
|
import com.ttstd.controlled.base.BaseMvvmActivity;
|
||||||
|
import com.ttstd.controlled.databinding.ActivityMainBinding;
|
||||||
import com.ttstd.controlled.service.ScreenCaptureService;
|
import com.ttstd.controlled.service.ScreenCaptureService;
|
||||||
import com.ttstd.controlled.webrtc.WebRtcClient;
|
import com.ttstd.controlled.webrtc.WebRtcClient;
|
||||||
|
|
||||||
import org.webrtc.RendererCommon;
|
import org.webrtc.RendererCommon;
|
||||||
import org.webrtc.SurfaceViewRenderer;
|
|
||||||
|
|
||||||
public class MainActivity extends AppCompatActivity {
|
public class MainActivity extends BaseMvvmActivity<MainViewModel, ActivityMainBinding> {
|
||||||
|
|
||||||
private static final String TAG = "ControlledMain";
|
private static final String TAG = "ControlledMain";
|
||||||
private static final int REQUEST_MEDIA_PROJECTION = 1001;
|
private static final int REQUEST_MEDIA_PROJECTION = 1001;
|
||||||
private static final int REQUEST_NOTIFICATION_PERMISSION = 1002;
|
private static final int REQUEST_NOTIFICATION_PERMISSION = 1002;
|
||||||
|
|
||||||
private EditText etServerUrl;
|
|
||||||
private EditText etDeviceId;
|
|
||||||
private Button btnStart;
|
|
||||||
private Button btnStop;
|
|
||||||
private TextView tvStatus;
|
|
||||||
private SurfaceViewRenderer localView;
|
|
||||||
|
|
||||||
private boolean isServiceRunning = false;
|
private boolean isServiceRunning = false;
|
||||||
private ScreenCaptureService screenCaptureService;
|
private ScreenCaptureService screenCaptureService;
|
||||||
private boolean isBound = false;
|
private boolean isBound = false;
|
||||||
@@ -63,28 +53,28 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
};
|
};
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected int getLayoutId() {
|
||||||
super.onCreate(savedInstanceState);
|
return R.layout.activity_main;
|
||||||
setContentView(R.layout.activity_main);
|
}
|
||||||
|
|
||||||
etServerUrl = findViewById(R.id.et_server_url);
|
|
||||||
etDeviceId = findViewById(R.id.et_device_id);
|
|
||||||
btnStart = findViewById(R.id.btn_start);
|
|
||||||
btnStop = findViewById(R.id.btn_stop);
|
|
||||||
tvStatus = findViewById(R.id.tv_status);
|
|
||||||
localView = findViewById(R.id.local_view);
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void initView() {
|
||||||
// 默认服务器地址
|
// 默认服务器地址
|
||||||
etServerUrl.setText("ws://175.178.213.60:8088/ws/signal");
|
binding.etServerUrl.setText("ws://175.178.213.60:8088/ws/signal");
|
||||||
// 生成设备ID
|
// 生成设备ID
|
||||||
// etDeviceId.setText("controlled_" + UUID.randomUUID().toString().substring(0, 8));
|
// binding.etDeviceId.setText("controlled_" + UUID.randomUUID().toString().substring(0, 8));
|
||||||
|
|
||||||
btnStart.setOnClickListener(v -> startScreenSharing());
|
binding.btnStart.setOnClickListener(v -> startScreenSharing());
|
||||||
btnStop.setOnClickListener(v -> stopScreenSharing());
|
binding.btnStop.setOnClickListener(v -> stopScreenSharing());
|
||||||
|
|
||||||
updateUI(false);
|
updateUI(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void initData() {
|
||||||
|
// Initialization logic if any
|
||||||
|
}
|
||||||
|
|
||||||
private void startScreenSharing() {
|
private void startScreenSharing() {
|
||||||
// 检查通知权限 (Android 13+)
|
// 检查通知权限 (Android 13+)
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||||
@@ -112,8 +102,8 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
Intent serviceIntent = new Intent(this, ScreenCaptureService.class);
|
Intent serviceIntent = new Intent(this, ScreenCaptureService.class);
|
||||||
serviceIntent.putExtra(ScreenCaptureService.EXTRA_RESULT_CODE, resultCode);
|
serviceIntent.putExtra(ScreenCaptureService.EXTRA_RESULT_CODE, resultCode);
|
||||||
serviceIntent.putExtra(ScreenCaptureService.EXTRA_RESULT_DATA, data);
|
serviceIntent.putExtra(ScreenCaptureService.EXTRA_RESULT_DATA, data);
|
||||||
serviceIntent.putExtra(ScreenCaptureService.EXTRA_SERVER_URL, etServerUrl.getText().toString());
|
serviceIntent.putExtra(ScreenCaptureService.EXTRA_SERVER_URL, binding.etServerUrl.getText().toString());
|
||||||
serviceIntent.putExtra(ScreenCaptureService.EXTRA_DEVICE_ID, etDeviceId.getText().toString());
|
serviceIntent.putExtra(ScreenCaptureService.EXTRA_DEVICE_ID, binding.etDeviceId.getText().toString());
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
startForegroundService(serviceIntent);
|
startForegroundService(serviceIntent);
|
||||||
@@ -150,8 +140,8 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
}
|
}
|
||||||
Intent serviceIntent = new Intent(this, ScreenCaptureService.class);
|
Intent serviceIntent = new Intent(this, ScreenCaptureService.class);
|
||||||
stopService(serviceIntent);
|
stopService(serviceIntent);
|
||||||
if (localView != null) {
|
if (binding.localView != null) {
|
||||||
localView.release();
|
binding.localView.release();
|
||||||
isLocalViewInitialized = false;
|
isLocalViewInitialized = false;
|
||||||
}
|
}
|
||||||
updateUI(false);
|
updateUI(false);
|
||||||
@@ -163,17 +153,17 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
WebRtcClient webRtcClient = screenCaptureService.getWebRtcClient();
|
WebRtcClient webRtcClient = screenCaptureService.getWebRtcClient();
|
||||||
if (webRtcClient != null && webRtcClient.getEglContext() != null) {
|
if (webRtcClient != null && webRtcClient.getEglContext() != null) {
|
||||||
try {
|
try {
|
||||||
localView.init(webRtcClient.getEglContext(), null);
|
binding.localView.init(webRtcClient.getEglContext(), null);
|
||||||
localView.setScalingType(RendererCommon.ScalingType.SCALE_ASPECT_FIT);
|
binding.localView.setScalingType(RendererCommon.ScalingType.SCALE_ASPECT_FIT);
|
||||||
localView.setMirror(false);
|
binding.localView.setMirror(false);
|
||||||
webRtcClient.setLocalSink(localView);
|
webRtcClient.setLocalSink(binding.localView);
|
||||||
isLocalViewInitialized = true;
|
isLocalViewInitialized = true;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Log.e(TAG, "Error initializing local view", e);
|
Log.e(TAG, "Error initializing local view", e);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// 如果 webRtcClient 还没准备好,稍后重试
|
// 如果 webRtcClient 还没准备好,稍后重试
|
||||||
localView.postDelayed(this::setupLocalPreview, 500);
|
binding.localView.postDelayed(this::setupLocalPreview, 500);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -185,18 +175,18 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
unbindService(serviceConnection);
|
unbindService(serviceConnection);
|
||||||
isBound = false;
|
isBound = false;
|
||||||
}
|
}
|
||||||
if (localView != null) {
|
if (binding != null && binding.localView != null) {
|
||||||
localView.release();
|
binding.localView.release();
|
||||||
isLocalViewInitialized = false;
|
isLocalViewInitialized = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateUI(boolean running) {
|
private void updateUI(boolean running) {
|
||||||
isServiceRunning = running;
|
isServiceRunning = running;
|
||||||
btnStart.setEnabled(!running);
|
binding.btnStart.setEnabled(!running);
|
||||||
btnStop.setEnabled(running);
|
binding.btnStop.setEnabled(running);
|
||||||
etServerUrl.setEnabled(!running);
|
binding.etServerUrl.setEnabled(!running);
|
||||||
etDeviceId.setEnabled(!running);
|
binding.etDeviceId.setEnabled(!running);
|
||||||
tvStatus.setText(running ? "状态: 运行中" : "状态: 已停止");
|
binding.tvStatus.setText(running ? "状态: 运行中" : "状态: 已停止");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
package com.ttstd.controlled.activity.main;
|
||||||
|
|
||||||
|
import com.ttstd.controlled.base.BaseViewModel;
|
||||||
|
|
||||||
|
public class MainViewModel extends BaseViewModel {
|
||||||
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
package com.ttstd.controlled.base;
|
||||||
|
|
||||||
|
import android.os.Bundle;
|
||||||
|
|
||||||
|
import androidx.annotation.LayoutRes;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
|
import androidx.databinding.DataBindingUtil;
|
||||||
|
import androidx.databinding.ViewDataBinding;
|
||||||
|
import androidx.lifecycle.ViewModelProvider;
|
||||||
|
|
||||||
|
import java.lang.reflect.ParameterizedType;
|
||||||
|
|
||||||
|
public abstract class BaseMvvmActivity<VM extends BaseViewModel, DB extends ViewDataBinding> extends AppCompatActivity {
|
||||||
|
|
||||||
|
protected VM viewModel;
|
||||||
|
protected DB binding;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
binding = DataBindingUtil.setContentView(this, getLayoutId());
|
||||||
|
binding.setLifecycleOwner(this);
|
||||||
|
|
||||||
|
initViewModel();
|
||||||
|
initView();
|
||||||
|
initData();
|
||||||
|
}
|
||||||
|
|
||||||
|
@LayoutRes
|
||||||
|
protected abstract int getLayoutId();
|
||||||
|
|
||||||
|
protected abstract void initView();
|
||||||
|
|
||||||
|
protected abstract void initData();
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private void initViewModel() {
|
||||||
|
ParameterizedType type = (ParameterizedType) getClass().getGenericSuperclass();
|
||||||
|
if (type != null) {
|
||||||
|
Class<VM> viewModelClass = (Class<VM>) type.getActualTypeArguments()[0];
|
||||||
|
viewModel = new ViewModelProvider(this).get(viewModelClass);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
package com.ttstd.controlled.base;
|
||||||
|
|
||||||
|
import androidx.lifecycle.ViewModel;
|
||||||
|
|
||||||
|
public class BaseViewModel extends ViewModel {
|
||||||
|
@Override
|
||||||
|
protected void onCleared() {
|
||||||
|
super.onCleared();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -21,7 +21,7 @@ import android.view.WindowManager;
|
|||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.core.app.NotificationCompat;
|
import androidx.core.app.NotificationCompat;
|
||||||
|
|
||||||
import com.ttstd.controlled.MainActivity;
|
import com.ttstd.controlled.activity.main.MainActivity;
|
||||||
import com.ttstd.controlled.input.InputCommandHandler;
|
import com.ttstd.controlled.input.InputCommandHandler;
|
||||||
import com.ttstd.controlled.signaling.SignalMessage;
|
import com.ttstd.controlled.signaling.SignalMessage;
|
||||||
import com.ttstd.controlled.signaling.WebSocketClient;
|
import com.ttstd.controlled.signaling.WebSocketClient;
|
||||||
|
|||||||
@@ -1,75 +1,81 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<layout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:layout_width="match_parent"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
android:layout_height="match_parent"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:orientation="vertical"
|
tools:context=".activity.main.MainActivity">
|
||||||
android:padding="24dp">
|
|
||||||
|
|
||||||
<TextView
|
<LinearLayout
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginBottom="24dp"
|
|
||||||
android:text="WebRTC 被控端"
|
|
||||||
android:textSize="24sp"
|
|
||||||
android:textStyle="bold" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="信令服务器地址:"
|
|
||||||
android:textSize="14sp" />
|
|
||||||
|
|
||||||
<EditText
|
|
||||||
android:id="@+id/et_server_url"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="match_parent"
|
||||||
android:layout_marginBottom="16dp"
|
android:orientation="vertical"
|
||||||
android:hint="ws://175.178.213.60:8088/ws/signal"
|
android:padding="24dp">
|
||||||
android:inputType="textUri" />
|
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="设备ID:"
|
android:layout_marginBottom="24dp"
|
||||||
android:textSize="14sp" />
|
android:text="WebRTC 被控端"
|
||||||
|
android:textSize="24sp"
|
||||||
|
android:textStyle="bold" />
|
||||||
|
|
||||||
<EditText
|
<TextView
|
||||||
android:id="@+id/et_device_id"
|
android:layout_width="wrap_content"
|
||||||
android:layout_width="match_parent"
|
android:layout_height="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:text="信令服务器地址:"
|
||||||
android:layout_marginBottom="24dp"
|
android:textSize="14sp" />
|
||||||
android:hint="设备ID"
|
|
||||||
android:inputType="text"
|
|
||||||
android:text="981964879" />
|
|
||||||
|
|
||||||
<TextView
|
<EditText
|
||||||
android:id="@+id/tv_status"
|
android:id="@+id/et_server_url"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginBottom="24dp"
|
android:layout_marginBottom="16dp"
|
||||||
android:text="状态: 已停止"
|
android:hint="ws://175.178.213.60:8088/ws/signal"
|
||||||
android:textSize="16sp"
|
android:inputType="textUri" />
|
||||||
android:textStyle="bold" />
|
|
||||||
|
|
||||||
<Button
|
<TextView
|
||||||
android:id="@+id/btn_start"
|
android:layout_width="wrap_content"
|
||||||
android:layout_width="match_parent"
|
android:layout_height="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:text="设备ID:"
|
||||||
android:layout_marginBottom="8dp"
|
android:textSize="14sp" />
|
||||||
android:text="开始屏幕共享" />
|
|
||||||
|
|
||||||
<Button
|
<EditText
|
||||||
android:id="@+id/btn_stop"
|
android:id="@+id/et_device_id"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginBottom="16dp"
|
android:layout_marginBottom="24dp"
|
||||||
android:enabled="false"
|
android:hint="设备ID"
|
||||||
android:text="停止屏幕共享" />
|
android:inputType="text"
|
||||||
|
android:text="981964879" />
|
||||||
|
|
||||||
<org.webrtc.SurfaceViewRenderer
|
<TextView
|
||||||
android:id="@+id/local_view"
|
android:id="@+id/tv_status"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="0dp"
|
android:layout_height="wrap_content"
|
||||||
android:layout_weight="1" />
|
android:layout_marginBottom="24dp"
|
||||||
|
android:text="状态: 已停止"
|
||||||
|
android:textSize="16sp"
|
||||||
|
android:textStyle="bold" />
|
||||||
|
|
||||||
</LinearLayout>
|
<Button
|
||||||
|
android:id="@+id/btn_start"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="8dp"
|
||||||
|
android:text="开始屏幕共享" />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/btn_stop"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="16dp"
|
||||||
|
android:enabled="false"
|
||||||
|
android:text="停止屏幕共享" />
|
||||||
|
|
||||||
|
<org.webrtc.SurfaceViewRenderer
|
||||||
|
android:id="@+id/local_view"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:layout_weight="1" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
</layout>
|
||||||
|
|||||||
Reference in New Issue
Block a user