203 lines
7.6 KiB
Java
203 lines
7.6 KiB
Java
package com.ttstd.controlled;
|
|
|
|
import android.Manifest;
|
|
import android.content.ComponentName;
|
|
import android.content.Context;
|
|
import android.content.Intent;
|
|
import android.content.ServiceConnection;
|
|
import android.content.pm.PackageManager;
|
|
import android.media.projection.MediaProjectionManager;
|
|
import android.os.Build;
|
|
import android.os.Bundle;
|
|
import android.os.IBinder;
|
|
import android.util.Log;
|
|
import android.widget.Button;
|
|
import android.widget.EditText;
|
|
import android.widget.TextView;
|
|
import android.widget.Toast;
|
|
|
|
import androidx.annotation.NonNull;
|
|
import androidx.annotation.Nullable;
|
|
import androidx.appcompat.app.AppCompatActivity;
|
|
import androidx.core.app.ActivityCompat;
|
|
import androidx.core.content.ContextCompat;
|
|
|
|
import com.ttstd.controlled.service.ScreenCaptureService;
|
|
import com.ttstd.controlled.webrtc.WebRtcClient;
|
|
|
|
import org.webrtc.RendererCommon;
|
|
import org.webrtc.SurfaceViewRenderer;
|
|
|
|
public class MainActivity extends AppCompatActivity {
|
|
|
|
private static final String TAG = "ControlledMain";
|
|
private static final int REQUEST_MEDIA_PROJECTION = 1001;
|
|
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 ScreenCaptureService screenCaptureService;
|
|
private boolean isBound = false;
|
|
private boolean isLocalViewInitialized = false;
|
|
|
|
private final ServiceConnection serviceConnection = new ServiceConnection() {
|
|
@Override
|
|
public void onServiceConnected(ComponentName name, IBinder service) {
|
|
ScreenCaptureService.LocalBinder binder = (ScreenCaptureService.LocalBinder) service;
|
|
screenCaptureService = binder.getService();
|
|
isBound = true;
|
|
setupLocalPreview();
|
|
}
|
|
|
|
@Override
|
|
public void onServiceDisconnected(ComponentName name) {
|
|
isBound = false;
|
|
screenCaptureService = null;
|
|
}
|
|
};
|
|
|
|
@Override
|
|
protected void onCreate(Bundle savedInstanceState) {
|
|
super.onCreate(savedInstanceState);
|
|
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);
|
|
|
|
// 默认服务器地址
|
|
etServerUrl.setText("ws://192.168.100.222:8080/ws/signal");
|
|
// 生成设备ID
|
|
// etDeviceId.setText("controlled_" + UUID.randomUUID().toString().substring(0, 8));
|
|
|
|
btnStart.setOnClickListener(v -> startScreenSharing());
|
|
btnStop.setOnClickListener(v -> stopScreenSharing());
|
|
|
|
updateUI(false);
|
|
}
|
|
|
|
private void startScreenSharing() {
|
|
// 检查通知权限 (Android 13+)
|
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
|
if (ContextCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS)
|
|
!= PackageManager.PERMISSION_GRANTED) {
|
|
ActivityCompat.requestPermissions(this,
|
|
new String[]{Manifest.permission.POST_NOTIFICATIONS},
|
|
REQUEST_NOTIFICATION_PERMISSION);
|
|
return;
|
|
}
|
|
}
|
|
|
|
// 请求屏幕录制权限
|
|
MediaProjectionManager projectionManager =
|
|
(MediaProjectionManager) getSystemService(Context.MEDIA_PROJECTION_SERVICE);
|
|
startActivityForResult(projectionManager.createScreenCaptureIntent(), REQUEST_MEDIA_PROJECTION);
|
|
}
|
|
|
|
@Override
|
|
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
|
|
super.onActivityResult(requestCode, resultCode, data);
|
|
|
|
if (requestCode == REQUEST_MEDIA_PROJECTION) {
|
|
if (resultCode == RESULT_OK && data != null) {
|
|
Intent serviceIntent = new Intent(this, ScreenCaptureService.class);
|
|
serviceIntent.putExtra(ScreenCaptureService.EXTRA_RESULT_CODE, resultCode);
|
|
serviceIntent.putExtra(ScreenCaptureService.EXTRA_RESULT_DATA, data);
|
|
serviceIntent.putExtra(ScreenCaptureService.EXTRA_SERVER_URL, etServerUrl.getText().toString());
|
|
serviceIntent.putExtra(ScreenCaptureService.EXTRA_DEVICE_ID, etDeviceId.getText().toString());
|
|
|
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
startForegroundService(serviceIntent);
|
|
} else {
|
|
startService(serviceIntent);
|
|
}
|
|
|
|
bindService(serviceIntent, serviceConnection, BIND_AUTO_CREATE);
|
|
|
|
updateUI(true);
|
|
Toast.makeText(this, "屏幕共享已启动", Toast.LENGTH_SHORT).show();
|
|
} else {
|
|
Toast.makeText(this, "屏幕录制权限被拒绝", Toast.LENGTH_SHORT).show();
|
|
}
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
|
|
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
|
|
if (requestCode == REQUEST_NOTIFICATION_PERMISSION) {
|
|
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
|
startScreenSharing();
|
|
} else {
|
|
Toast.makeText(this, "需要通知权限才能运行", Toast.LENGTH_SHORT).show();
|
|
}
|
|
}
|
|
}
|
|
|
|
private void stopScreenSharing() {
|
|
if (isBound) {
|
|
unbindService(serviceConnection);
|
|
isBound = false;
|
|
}
|
|
Intent serviceIntent = new Intent(this, ScreenCaptureService.class);
|
|
stopService(serviceIntent);
|
|
if (localView != null) {
|
|
localView.release();
|
|
isLocalViewInitialized = false;
|
|
}
|
|
updateUI(false);
|
|
Toast.makeText(this, "屏幕共享已停止", Toast.LENGTH_SHORT).show();
|
|
}
|
|
|
|
private void setupLocalPreview() {
|
|
if (isBound && screenCaptureService != null && !isLocalViewInitialized) {
|
|
WebRtcClient webRtcClient = screenCaptureService.getWebRtcClient();
|
|
if (webRtcClient != null && webRtcClient.getEglContext() != null) {
|
|
try {
|
|
localView.init(webRtcClient.getEglContext(), null);
|
|
localView.setScalingType(RendererCommon.ScalingType.SCALE_ASPECT_FIT);
|
|
localView.setMirror(false);
|
|
webRtcClient.setLocalSink(localView);
|
|
isLocalViewInitialized = true;
|
|
} catch (Exception e) {
|
|
Log.e(TAG, "Error initializing local view", e);
|
|
}
|
|
} else {
|
|
// 如果 webRtcClient 还没准备好,稍后重试
|
|
localView.postDelayed(this::setupLocalPreview, 500);
|
|
}
|
|
}
|
|
}
|
|
|
|
@Override
|
|
protected void onDestroy() {
|
|
super.onDestroy();
|
|
if (isBound) {
|
|
unbindService(serviceConnection);
|
|
isBound = false;
|
|
}
|
|
if (localView != null) {
|
|
localView.release();
|
|
isLocalViewInitialized = false;
|
|
}
|
|
}
|
|
|
|
private void updateUI(boolean running) {
|
|
isServiceRunning = running;
|
|
btnStart.setEnabled(!running);
|
|
btnStop.setEnabled(running);
|
|
etServerUrl.setEnabled(!running);
|
|
etDeviceId.setEnabled(!running);
|
|
tvStatus.setText(running ? "状态: 运行中" : "状态: 已停止");
|
|
}
|
|
}
|