aboutsummaryrefslogtreecommitdiff
path: root/app/src/main/java/invalid/lena/scrcpy/Mirror.java
diff options
context:
space:
mode:
Diffstat (limited to 'app/src/main/java/invalid/lena/scrcpy/Mirror.java')
-rw-r--r--app/src/main/java/invalid/lena/scrcpy/Mirror.java61
1 files changed, 33 insertions, 28 deletions
diff --git a/app/src/main/java/invalid/lena/scrcpy/Mirror.java b/app/src/main/java/invalid/lena/scrcpy/Mirror.java
index bc9db34..51e861a 100644
--- a/app/src/main/java/invalid/lena/scrcpy/Mirror.java
+++ b/app/src/main/java/invalid/lena/scrcpy/Mirror.java
@@ -11,13 +11,13 @@ import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.SystemClock;
+import android.view.Gravity;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
-import android.view.ViewGroup;
import android.view.WindowInsets;
import android.view.WindowInsetsController;
import android.view.WindowManager;
@@ -65,6 +65,7 @@ public final class Mirror extends Activity {
private State state = State.CONNECTING;
private int connectedW, connectedH;
private long connectedGeometryVersion;
+ private int gestureBottomInset;
private SurfaceView surfaceView;
@@ -114,26 +115,25 @@ public final class Mirror extends Activity {
// video surface, so re-fit from here as well.
root.addOnLayoutChangeListener(
(view, l, t, r, b, ol, ot, or, ob) -> applyLetterbox());
+ // Keep the target's bottom edge above the source's mandatory Home
+ // gesture area. A target gesture can then start on the mirrored
+ // handle instead of being claimed by the source system.
+ root.setOnApplyWindowInsetsListener((view, insets) -> {
+ int bottom = insets.getInsetsIgnoringVisibility(
+ WindowInsets.Type.mandatorySystemGestures()).bottom;
+ if (gestureBottomInset != bottom) {
+ gestureBottomInset = bottom;
+ applyLetterbox();
+ }
+ return insets;
+ });
+ root.requestApplyInsets();
statusBar = findViewById(R.id.status_bar);
statusText = findViewById(R.id.status_text);
reconnectBtn = findViewById(R.id.reconnect);
insetStatusBar();
reconnectBtn.setOnClickListener(view -> reconnect());
- // Back, Home and Recents as explicit controls. On a
- // gesture-navigation source the target's own navigation cannot be
- // reached by forwarding touches: the source claims the bottom
- // edge swipe for itself and, unlike the side edges, that region
- // cannot be released with setSystemGestureExclusionRects.
- findViewById(R.id.nav_back).setOnClickListener(view -> {
- if (session != null) session.onBack();
- });
- findViewById(R.id.nav_home).setOnClickListener(view -> {
- if (session != null) session.onHome();
- });
- findViewById(R.id.nav_recents).setOnClickListener(view -> {
- if (session != null) session.onRecents();
- });
updateStatusBar();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
@@ -220,22 +220,29 @@ public final class Mirror extends Activity {
View v = surfaceView;
if (v == null || root == null || session == null) return;
int cw = root.getWidth(), ch = root.getHeight();
+ int availableH = ch - gestureBottomInset;
int tw = connectedW, th = connectedH;
- if (cw <= 0 || ch <= 0 || tw <= 0 || th <= 0) return;
+ if (cw <= 0 || availableH <= 0 || tw <= 0 || th <= 0) return;
- float scale = Math.min(cw / (float) tw, ch / (float) th);
+ float scale = Math.min(cw / (float) tw, availableH / (float) th);
int w = Math.min(cw, Math.max(1, Math.round(tw * scale)));
- int h = Math.min(ch, Math.max(1, Math.round(th * scale)));
+ int h = Math.min(availableH, Math.max(1, Math.round(th * scale)));
+ int x = (cw - w) / 2;
+ int y = (availableH - h) / 2;
- ViewGroup.LayoutParams lp = v.getLayoutParams();
- if (lp.width != w || lp.height != h) {
+ FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) v.getLayoutParams();
+ if (lp.width != w || lp.height != h || lp.leftMargin != x
+ || lp.topMargin != y || lp.gravity != (Gravity.TOP | Gravity.START)) {
lp.width = w;
lp.height = h;
+ lp.leftMargin = x;
+ lp.topMargin = y;
+ lp.gravity = Gravity.TOP | Gravity.START;
v.setLayoutParams(lp); // re-layout re-enters here, then converges
- Log.i("mirror: letterbox %dx%d -> %dx%d in %dx%d", tw, th, w, h, cw, ch);
+ Log.i("mirror: letterbox %dx%d -> %dx%d in %dx%d gesture_bottom=%d",
+ tw, th, w, h, cw, ch, gestureBottomInset);
}
- session.setViewport(connectedGeometryVersion,
- (cw - w) / 2, (ch - h) / 2, w, h);
+ session.setViewport(connectedGeometryVersion, x, y, w, h);
}
private void detachSurface() {
@@ -377,12 +384,10 @@ public final class Mirror extends Activity {
statusText.setText(s);
reconnectBtn.setVisibility(state == State.DISCONNECTED ? View.VISIBLE : View.GONE);
- // Hide the whole bar while actively mirroring if the user opted
- // out; keep it up whenever not CONNECTED so the status and the
- // Reconnect button stay reachable.
+ // Status is only needed during bring-up and after a terminal error.
+ // Target navigation remains inside the mirrored frame.
if (statusBar != null) {
- boolean show = Settings.showStatusBar(this) || state != State.CONNECTED;
- statusBar.setVisibility(show ? View.VISIBLE : View.GONE);
+ statusBar.setVisibility(state == State.CONNECTED ? View.GONE : View.VISIBLE);
}
}