From 852a8a00273c9128efeed0217a8e5d3fcd8bf780 Mon Sep 17 00:00:00 2001 From: Lena Date: Sat, 1 Aug 2026 00:00:00 +0000 Subject: app: harden mirroring lifecycle and state --- app/src/debug/AndroidManifest.xml | 9 + .../debug/java/invalid/lena/scrcpy/Pattern.java | 115 +++++++ app/src/debug/res/layout/mirror.xml | 93 ----- app/src/main/AndroidManifest.xml | 8 +- .../main/java/invalid/lena/scrcpy/AtomicFiles.java | 30 +- .../main/java/invalid/lena/scrcpy/AudioSink.java | 55 ++- .../main/java/invalid/lena/scrcpy/AudioStream.java | 45 ++- .../java/invalid/lena/scrcpy/ControlMessages.java | 37 +- .../java/invalid/lena/scrcpy/ControlStream.java | 11 +- .../main/java/invalid/lena/scrcpy/Controller.java | 141 +++++--- .../main/java/invalid/lena/scrcpy/Crashlog.java | 29 +- app/src/main/java/invalid/lena/scrcpy/Devices.java | 86 ++++- .../main/java/invalid/lena/scrcpy/Licenses.java | 48 +++ app/src/main/java/invalid/lena/scrcpy/Main.java | 117 ++++--- app/src/main/java/invalid/lena/scrcpy/Mirror.java | 371 ++++++++++++-------- .../main/java/invalid/lena/scrcpy/MuxRecorder.java | 226 ------------ app/src/main/java/invalid/lena/scrcpy/Server.java | 96 ++++-- app/src/main/java/invalid/lena/scrcpy/Session.java | 377 +++++++++++++++------ .../main/java/invalid/lena/scrcpy/Sessions.java | 24 +- .../main/java/invalid/lena/scrcpy/Settings.java | 119 ++++++- .../java/invalid/lena/scrcpy/SettingsActivity.java | 22 +- app/src/main/java/invalid/lena/scrcpy/Sync.java | 54 ++- .../java/invalid/lena/scrcpy/TouchGeometry.java | 46 +++ .../main/java/invalid/lena/scrcpy/TouchMap.java | 34 ++ app/src/main/java/invalid/lena/scrcpy/Ui.java | 2 +- .../main/java/invalid/lena/scrcpy/VideoFrames.java | 2 +- .../main/java/invalid/lena/scrcpy/VideoQueue.java | 94 +++++ .../java/invalid/lena/scrcpy/VideoRecorder.java | 19 -- .../main/java/invalid/lena/scrcpy/VideoSink.java | 277 +++++++++------ .../main/java/invalid/lena/scrcpy/VideoStream.java | 26 +- app/src/main/java/invalid/lena/scrcpy/Wire.java | 71 +++- .../main/res/drawable/ic_launcher_foreground.xml | 13 +- app/src/main/res/drawable/ic_settings.xml | 10 +- app/src/main/res/layout/device_row.xml | 28 +- app/src/main/res/layout/licenses.xml | 20 ++ app/src/main/res/layout/main.xml | 264 ++++++++------- app/src/main/res/layout/mirror.xml | 46 ++- app/src/main/res/layout/settings.xml | 60 ++-- app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml | 5 +- app/src/main/res/values/ids.xml | 10 - app/src/main/res/values/strings.xml | 40 ++- app/src/main/res/values/styles.xml | 2 +- app/src/main/res/xml/data_extraction_rules.xml | 14 + .../java/invalid/lena/scrcpy/AtomicFilesTest.java | 12 + .../java/invalid/lena/scrcpy/AudioStreamTest.java | 13 +- .../invalid/lena/scrcpy/ControlMessagesTest.java | 29 +- .../invalid/lena/scrcpy/ControlStreamTest.java | 10 +- .../java/invalid/lena/scrcpy/CrashlogTest.java | 36 ++ .../test/java/invalid/lena/scrcpy/DevicesTest.java | 16 +- .../invalid/lena/scrcpy/TouchGeometryTest.java | 48 +++ .../java/invalid/lena/scrcpy/TouchMapTest.java | 85 +++++ .../java/invalid/lena/scrcpy/VideoQueueTest.java | 53 +++ .../java/invalid/lena/scrcpy/VideoStreamTest.java | 61 +--- .../test/java/invalid/lena/scrcpy/WireTest.java | 58 +++- 54 files changed, 2400 insertions(+), 1217 deletions(-) create mode 100644 app/src/debug/AndroidManifest.xml create mode 100644 app/src/debug/java/invalid/lena/scrcpy/Pattern.java delete mode 100644 app/src/debug/res/layout/mirror.xml create mode 100644 app/src/main/java/invalid/lena/scrcpy/Licenses.java delete mode 100644 app/src/main/java/invalid/lena/scrcpy/MuxRecorder.java create mode 100644 app/src/main/java/invalid/lena/scrcpy/TouchGeometry.java create mode 100644 app/src/main/java/invalid/lena/scrcpy/TouchMap.java create mode 100644 app/src/main/java/invalid/lena/scrcpy/VideoQueue.java delete mode 100644 app/src/main/java/invalid/lena/scrcpy/VideoRecorder.java create mode 100644 app/src/main/res/layout/licenses.xml delete mode 100644 app/src/main/res/values/ids.xml create mode 100644 app/src/main/res/xml/data_extraction_rules.xml create mode 100644 app/src/test/java/invalid/lena/scrcpy/CrashlogTest.java create mode 100644 app/src/test/java/invalid/lena/scrcpy/TouchGeometryTest.java create mode 100644 app/src/test/java/invalid/lena/scrcpy/TouchMapTest.java create mode 100644 app/src/test/java/invalid/lena/scrcpy/VideoQueueTest.java (limited to 'app') diff --git a/app/src/debug/AndroidManifest.xml b/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..8e04c86 --- /dev/null +++ b/app/src/debug/AndroidManifest.xml @@ -0,0 +1,9 @@ + + + + + + diff --git a/app/src/debug/java/invalid/lena/scrcpy/Pattern.java b/app/src/debug/java/invalid/lena/scrcpy/Pattern.java new file mode 100644 index 0000000..39a5d42 --- /dev/null +++ b/app/src/debug/java/invalid/lena/scrcpy/Pattern.java @@ -0,0 +1,115 @@ +package invalid.lena.scrcpy; + +import android.app.Activity; +import android.content.ClipData; +import android.content.ClipboardManager; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.os.Bundle; +import android.view.KeyEvent; +import android.view.MotionEvent; +import android.view.View; +import android.view.WindowInsets; +import android.view.WindowInsetsController; + +// Deterministic moving target for the two-emulator E2E test. Debug-only, +// exported only in the debug manifest, and absent from release artifacts. +public final class Pattern extends Activity { + + private static final String TARGET_CLIPBOARD_TEXT = "scrcpy-e2e"; + private static final String SOURCE_CLIPBOARD_TEXT = "source-e2e"; + private static final String EXTRA_CLIPBOARD_TEXT = "clipboard_text"; + + private ClipboardManager clipboard; + private String clipboardText; + private final ClipboardManager.OnPrimaryClipChangedListener clipboardListener = + this::onClipboardChanged; + + @Override + @SuppressWarnings("deprecation") + protected void onCreate(Bundle state) { + super.onCreate(state); + String requested = getIntent().getStringExtra(EXTRA_CLIPBOARD_TEXT); + clipboardText = SOURCE_CLIPBOARD_TEXT.equals(requested) + ? SOURCE_CLIPBOARD_TEXT : TARGET_CLIPBOARD_TEXT; + setContentView(new PatternView()); + clipboard = getSystemService(ClipboardManager.class); + if (clipboard != null) clipboard.addPrimaryClipChangedListener(clipboardListener); + getWindow().setDecorFitsSystemWindows(false); + WindowInsetsController insets = getWindow().getInsetsController(); + if (insets != null) insets.hide(WindowInsets.Type.systemBars()); + } + + @Override + protected void onDestroy() { + if (clipboard != null) clipboard.removePrimaryClipChangedListener(clipboardListener); + super.onDestroy(); + } + + private void onClipboardChanged() { + ClipData data = clipboard.getPrimaryClip(); + if (data == null || data.getItemCount() == 0) return; + CharSequence text = data.getItemAt(0).getText(); + if (SOURCE_CLIPBOARD_TEXT.contentEquals(text)) { + Log.i("pattern: clipboard from source"); + } + } + + @Override + public boolean dispatchKeyEvent(KeyEvent event) { + if (event.getAction() == KeyEvent.ACTION_UP) { + Log.i("pattern: key up code=%d", event.getKeyCode()); + } + return super.dispatchKeyEvent(event); + } + + private final class PatternView extends View { + private final Paint paint = new Paint(); + private int step; + + PatternView() { + super(Pattern.this); + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + if (event.getActionMasked() == MotionEvent.ACTION_UP) { + Log.i("pattern: touch up x=%d y=%d", (int) event.getX(), (int) event.getY()); + performClick(); + } + return true; + } + + @Override + public boolean performClick() { + super.performClick(); + if (clipboard != null) { + clipboard.setPrimaryClip(ClipData.newPlainText("e2e", clipboardText)); + Log.i("pattern: clipboard set"); + } + return true; + } + + @Override + protected void onDraw(Canvas canvas) { + int w = getWidth(); + int h = getHeight(); + int mx = w / 2; + int my = h / 2; + paint.setColor(Color.rgb(224, 32, 32)); + canvas.drawRect(0, 0, mx, my, paint); + paint.setColor(Color.rgb(32, 192, 48)); + canvas.drawRect(mx, 0, w, my, paint); + paint.setColor(Color.rgb(32, 64, 224)); + canvas.drawRect(0, my, mx, h, paint); + paint.setColor(Color.rgb(224, 192, 32)); + canvas.drawRect(mx, my, w, h, paint); + + paint.setColor(Color.WHITE); + int x = step++ % Math.max(1, w); + canvas.drawRect(x, 0, Math.min(w, x + 12), h, paint); + postInvalidateDelayed(33); + } + } +} diff --git a/app/src/debug/res/layout/mirror.xml b/app/src/debug/res/layout/mirror.xml deleted file mode 100644 index 5d0e845..0000000 --- a/app/src/debug/res/layout/mirror.xml +++ /dev/null @@ -1,93 +0,0 @@ - - - - - - - - - - -