aboutsummaryrefslogtreecommitdiff
path: root/app/src/main/res/layout
diff options
context:
space:
mode:
authorLena <lena@omega>2026-08-01 00:00:00 +0000
committerLena <lena@omega>2026-08-01 00:00:00 +0000
commit852a8a00273c9128efeed0217a8e5d3fcd8bf780 (patch)
treec72f959731fa3c7c809cf1a0222363b6c9c9b03b /app/src/main/res/layout
parentf379b93d52bf0dbd3816ec3f64d165314771d2a6 (diff)
downloadscrcpy-android-852a8a00273c9128efeed0217a8e5d3fcd8bf780.tar.gz
app: harden mirroring lifecycle and state
Diffstat (limited to 'app/src/main/res/layout')
-rw-r--r--app/src/main/res/layout/device_row.xml28
-rw-r--r--app/src/main/res/layout/licenses.xml20
-rw-r--r--app/src/main/res/layout/main.xml264
-rw-r--r--app/src/main/res/layout/mirror.xml46
-rw-r--r--app/src/main/res/layout/settings.xml60
5 files changed, 242 insertions, 176 deletions
diff --git a/app/src/main/res/layout/device_row.xml b/app/src/main/res/layout/device_row.xml
index f06ab20..0471639 100644
--- a/app/src/main/res/layout/device_row.xml
+++ b/app/src/main/res/layout/device_row.xml
@@ -1,28 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Saved-device row: phone glyph + "host:port" label, with the platform
- touch ripple. Bound by an ArrayAdapter via R.id.device_label. -->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<!-- Saved-device row with a platform touch ripple. -->
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/device_label"
+ style="@style/DeviceLabel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:orientation="horizontal"
android:gravity="center_vertical"
android:minHeight="56dp"
android:paddingHorizontal="@dimen/space_sm"
android:paddingVertical="@dimen/space_md"
- android:background="?android:attr/selectableItemBackground">
-
- <ImageView
- android:layout_width="24dp"
- android:layout_height="24dp"
- android:src="@drawable/ic_device"
- android:contentDescription="@null"/>
-
- <TextView
- android:id="@+id/device_label"
- style="@style/DeviceLabel"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:layout_marginStart="@dimen/space_md"/>
-
-</LinearLayout>
+ android:drawableStart="@drawable/ic_device"
+ android:drawablePadding="@dimen/space_md"
+ android:foreground="?android:attr/selectableItemBackground"/>
diff --git a/app/src/main/res/layout/licenses.xml b/app/src/main/res/layout/licenses.xml
new file mode 100644
index 0000000..6ca02ab
--- /dev/null
+++ b/app/src/main/res/layout/licenses.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Plain scrolling text. The notices are wrapped at 78 columns in the
+ asset, so they are shown in a monospace face at a size that does not
+ re-wrap them into nonsense. -->
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/root"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:padding="@dimen/space_lg">
+
+ <TextView
+ android:id="@+id/notices"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:textColor="@color/on_surface"
+ android:textSize="12sp"
+ android:fontFamily="monospace"
+ android:textIsSelectable="true"/>
+
+</ScrollView>
diff --git a/app/src/main/res/layout/main.xml b/app/src/main/res/layout/main.xml
index 0b1273b..15b1c90 100644
--- a/app/src/main/res/layout/main.xml
+++ b/app/src/main/res/layout/main.xml
@@ -1,161 +1,177 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Root padding is the base; Ui.padForInsets() adds the system bar and
+<!-- One scroll for the whole page. The saved-device rows are built into
+ the LinearLayout below rather than a ListView, because a ListView
+ inside a ScrollView cannot measure itself and splitting the screen
+ into two independently scrolling halves left one of them unusable at
+ some sizes. The list is a handful of rows; it does not need
+ recycling.
+
+ Root padding is the base; Ui.padForInsets() adds the system bar and
IME insets to it at runtime (the window is edge-to-edge). -->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/root"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:orientation="vertical"
+ android:fillViewport="true"
android:padding="@dimen/space_lg">
- <!-- Header: app glyph + name, Settings on the right. -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:orientation="horizontal"
- android:gravity="center_vertical"
- android:layout_marginBottom="@dimen/space_lg">
+ android:orientation="vertical">
- <ImageView
- android:layout_width="40dp"
- android:layout_height="40dp"
- android:src="@drawable/ic_launcher_foreground"
- android:scaleType="fitCenter"
- android:contentDescription="@null"/>
-
- <TextView
- android:layout_width="0dp"
+ <!-- Header: app glyph + name, Settings on the right. -->
+ <LinearLayout
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_weight="1"
- android:layout_marginStart="@dimen/space_sm"
- android:text="@string/app_name"
- android:textColor="@color/on_surface"
- android:textSize="22sp"
- android:textStyle="bold"/>
-
- <ImageButton
- android:id="@+id/settings"
- android:layout_width="48dp"
- android:layout_height="48dp"
- android:src="@drawable/ic_settings"
- android:scaleType="centerInside"
- android:background="?android:attr/selectableItemBackgroundBorderless"
- android:contentDescription="@string/settings"/>
-
- </LinearLayout>
-
- <!-- Pairing form. Each field is one value the target already prints,
- copied verbatim: the Wireless debugging screen shows the device
- address as a single "ip:port" string, and the pairing dialog adds
- its own port plus the code. -->
- <LinearLayout
- style="@style/Card"
- android:layout_width="match_parent"
- android:layout_height="wrap_content">
+ android:orientation="horizontal"
+ android:gravity="center_vertical"
+ android:layout_marginBottom="@dimen/space_lg">
- <TextView
- style="@style/SectionHeader"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/pair_a_device"/>
+ <ImageView
+ android:layout_width="40dp"
+ android:layout_height="40dp"
+ android:src="@drawable/ic_launcher_foreground"
+ android:scaleType="fitCenter"
+ android:contentDescription="@null"/>
- <TextView
- style="@style/Caption"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="@string/pair_help"/>
+ <TextView
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:layout_marginStart="@dimen/space_sm"
+ android:text="@string/app_name"
+ android:textColor="@color/on_surface"
+ android:textSize="22sp"
+ android:textStyle="bold"/>
+
+ <ImageButton
+ android:id="@+id/settings"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:src="@drawable/ic_settings"
+ android:scaleType="centerInside"
+ android:background="?android:attr/selectableItemBackgroundBorderless"
+ android:contentDescription="@string/settings"/>
- <TextView
- style="@style/FieldLabel"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/label_address"/>
+ </LinearLayout>
- <TextView
- style="@style/Caption"
+ <!-- Pairing form. Each field is one value the target already
+ prints, copied verbatim: the Wireless debugging screen shows
+ the device address as a single "ip:port" string, and the
+ pairing dialog adds its own port plus the code. -->
+ <LinearLayout
+ style="@style/Card"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="@string/sub_address"/>
+ android:layout_height="wrap_content">
- <EditText
- android:id="@+id/device_address"
- style="@style/Field"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginTop="@dimen/space_xs"
- android:hint="@string/address_hint"
- android:inputType="textUri"
- android:autofillHints="postalAddress"/>
+ <TextView
+ style="@style/SectionHeader"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/pair_a_device"/>
- <TextView
- style="@style/FieldLabel"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/label_pairing"/>
+ <TextView
+ style="@style/Caption"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/pair_help"/>
- <TextView
- style="@style/Caption"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="@string/sub_pairing"/>
+ <TextView
+ style="@style/FieldLabel"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/label_address"/>
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="horizontal"
- android:layout_marginTop="@dimen/space_xs">
+ <TextView
+ style="@style/Caption"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/sub_address"/>
<EditText
- android:id="@+id/pair_port"
+ android:id="@+id/device_address"
style="@style/Field"
- android:layout_width="0dp"
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_weight="1"
- android:layout_marginEnd="@dimen/space_sm"
- android:hint="@string/pair_port_hint"
- android:inputType="number"
- android:autofillHints="off"/>
+ android:layout_marginTop="@dimen/space_xs"
+ android:hint="@string/address_hint"
+ android:inputType="textUri"
+ android:importantForAutofill="no"/>
+
+ <TextView
+ style="@style/FieldLabel"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/label_pairing"/>
- <EditText
- android:id="@+id/pair_code"
- style="@style/Field"
- android:layout_width="0dp"
+ <TextView
+ style="@style/Caption"
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_weight="1"
- android:hint="@string/pair_code_hint"
- android:inputType="numberPassword"
- android:maxLength="6"
- android:autofillHints="off"/>
+ android:text="@string/sub_pairing"/>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:layout_marginTop="@dimen/space_xs">
+
+ <EditText
+ android:id="@+id/pair_port"
+ style="@style/Field"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:layout_marginEnd="@dimen/space_sm"
+ android:hint="@string/pair_port_hint"
+ android:inputType="number"
+ android:importantForAutofill="no"/>
+
+ <EditText
+ android:id="@+id/pair_code"
+ style="@style/Field"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:hint="@string/pair_code_hint"
+ android:inputType="numberPassword"
+ android:maxLength="6"
+ android:importantForAutofill="no"/>
+
+ </LinearLayout>
+
+ <TextView
+ style="@style/Caption"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/space_md"
+ android:text="@string/network_trust"/>
+
+ <Button
+ android:id="@+id/pair"
+ style="@style/Button.Primary"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/space_lg"
+ android:text="@string/pair_and_save"/>
</LinearLayout>
- <Button
- android:id="@+id/pair"
- style="@style/Button.Primary"
+ <TextView
+ style="@style/SectionHeader"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginTop="@dimen/space_lg"
- android:text="@string/pair_and_save"/>
-
- </LinearLayout>
+ android:text="@string/saved_devices"/>
- <TextView
- style="@style/SectionHeader"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="@string/saved_devices"/>
-
- <FrameLayout
- android:layout_width="match_parent"
- android:layout_height="0dp"
- android:layout_weight="1">
-
- <ListView
+ <LinearLayout
android:id="@+id/devices"
android:layout_width="match_parent"
- android:layout_height="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
android:divider="@color/stroke"
- android:dividerHeight="1dp"/>
+ android:showDividers="middle"
+ android:dividerPadding="0dp"/>
<TextView
android:id="@+id/devices_empty"
@@ -166,6 +182,6 @@
android:paddingTop="@dimen/space_xl"
android:text="@string/no_devices_yet"/>
- </FrameLayout>
+ </LinearLayout>
-</LinearLayout>
+</ScrollView>
diff --git a/app/src/main/res/layout/mirror.xml b/app/src/main/res/layout/mirror.xml
index cf24e11..d2355a8 100644
--- a/app/src/main/res/layout/mirror.xml
+++ b/app/src/main/res/layout/mirror.xml
@@ -1,14 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Release Mirror layout: SurfaceView for the video pipeline plus a
- floating top status pill with Record and a Reconnect button (visible
- only when the session is in DISCONNECTED state). The debug layout
- under src/debug/res/layout/mirror.xml shadows this with a TextureView
- and extra stats overlay used by the e2e screen capture. -->
+<!-- Video surface with optional target navigation and reconnect controls. -->
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:id="@+id/root"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:background="#000000">
+ tools:ignore="MergeRootFrame">
+ <!-- Sized at runtime to the target's aspect ratio and centred, so the
+ black FrameLayout behind it shows as letterbox bars. -->
<SurfaceView
android:id="@+id/surface"
android:layout_width="match_parent"
@@ -39,16 +39,42 @@
android:ellipsize="end"
android:text="@string/connecting"/>
+
+ <Button
+ android:id="@+id/nav_back"
+ style="@style/Button.Secondary"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/space_sm"
+ android:minWidth="0dp"
+ android:minHeight="@dimen/touch_min"
+ android:paddingHorizontal="@dimen/space_md"
+ android:paddingVertical="@dimen/space_xs"
+ android:text="@string/nav_back"/>
+
+ <Button
+ android:id="@+id/nav_home"
+ style="@style/Button.Secondary"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/space_sm"
+ android:minWidth="0dp"
+ android:minHeight="@dimen/touch_min"
+ android:paddingHorizontal="@dimen/space_md"
+ android:paddingVertical="@dimen/space_xs"
+ android:text="@string/nav_home"/>
+
<Button
- android:id="@+id/record"
+ android:id="@+id/nav_recents"
style="@style/Button.Secondary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/space_sm"
- android:minHeight="0dp"
+ android:minWidth="0dp"
+ android:minHeight="@dimen/touch_min"
android:paddingHorizontal="@dimen/space_md"
android:paddingVertical="@dimen/space_xs"
- android:text="@string/record"/>
+ android:text="@string/nav_recents"/>
<Button
android:id="@+id/reconnect"
@@ -56,7 +82,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/space_sm"
- android:minHeight="0dp"
+ android:minHeight="@dimen/touch_min"
android:paddingHorizontal="@dimen/space_md"
android:paddingVertical="@dimen/space_xs"
android:text="@string/reconnect"
diff --git a/app/src/main/res/layout/settings.xml b/app/src/main/res/layout/settings.xml
index 76f706b..aa2f117 100644
--- a/app/src/main/res/layout/settings.xml
+++ b/app/src/main/res/layout/settings.xml
@@ -51,21 +51,21 @@
style="@style/RadioOption"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:text="H.264 (default)"/>
+ android:text="@string/video_h264"/>
<RadioButton
android:id="@+id/video_h265"
style="@style/RadioOption"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:text="H.265"/>
+ android:text="@string/video_h265"/>
<RadioButton
android:id="@+id/video_av1"
style="@style/RadioOption"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:text="AV1 (requires target Android 14+)"/>
+ android:text="@string/video_av1"/>
</RadioGroup>
@@ -93,14 +93,14 @@
style="@style/RadioOption"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:text="Raw PCM (1.5 Mbps, default)"/>
+ android:text="@string/audio_raw"/>
<RadioButton
android:id="@+id/audio_opus"
style="@style/RadioOption"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:text="Opus (~128 kbps)"/>
+ android:text="@string/audio_opus"/>
</RadioGroup>
@@ -128,42 +128,42 @@
style="@style/RadioOption"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:text="Original (default)"/>
+ android:text="@string/max_size_original"/>
<RadioButton
android:id="@+id/max_size_480"
style="@style/RadioOption"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:text="480"/>
+ android:text="@string/max_size_480"/>
<RadioButton
android:id="@+id/max_size_720"
style="@style/RadioOption"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:text="720"/>
+ android:text="@string/max_size_720"/>
<RadioButton
android:id="@+id/max_size_1080"
style="@style/RadioOption"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:text="1080"/>
+ android:text="@string/max_size_1080"/>
<RadioButton
android:id="@+id/max_size_1440"
style="@style/RadioOption"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:text="1440"/>
+ android:text="@string/max_size_1440"/>
<RadioButton
android:id="@+id/max_size_2160"
style="@style/RadioOption"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:text="2160"/>
+ android:text="@string/max_size_2160"/>
</RadioGroup>
@@ -191,35 +191,35 @@
style="@style/RadioOption"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:text="1 Mbps"/>
+ android:text="@string/bit_rate_1m"/>
<RadioButton
android:id="@+id/bit_rate_2m"
style="@style/RadioOption"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:text="2 Mbps"/>
+ android:text="@string/bit_rate_2m"/>
<RadioButton
android:id="@+id/bit_rate_4m"
style="@style/RadioOption"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:text="4 Mbps"/>
+ android:text="@string/bit_rate_4m"/>
<RadioButton
android:id="@+id/bit_rate_8m"
style="@style/RadioOption"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:text="8 Mbps (default)"/>
+ android:text="@string/bit_rate_8m"/>
<RadioButton
android:id="@+id/bit_rate_16m"
style="@style/RadioOption"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:text="16 Mbps"/>
+ android:text="@string/bit_rate_16m"/>
</RadioGroup>
@@ -247,35 +247,35 @@
style="@style/RadioOption"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:text="Unlimited (default)"/>
+ android:text="@string/max_fps_unlimited"/>
<RadioButton
android:id="@+id/max_fps_30"
style="@style/RadioOption"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:text="30"/>
+ android:text="@string/max_fps_30"/>
<RadioButton
android:id="@+id/max_fps_60"
style="@style/RadioOption"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:text="60"/>
+ android:text="@string/max_fps_60"/>
<RadioButton
android:id="@+id/max_fps_90"
style="@style/RadioOption"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:text="90"/>
+ android:text="@string/max_fps_90"/>
<RadioButton
android:id="@+id/max_fps_120"
style="@style/RadioOption"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:text="120"/>
+ android:text="@string/max_fps_120"/>
</RadioGroup>
@@ -294,6 +294,13 @@
android:text="@string/display"/>
<CheckBox
+ android:id="@+id/clipboard_sync"
+ style="@style/RadioOption"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/clipboard_sync"/>
+
+ <CheckBox
android:id="@+id/show_status_bar"
style="@style/RadioOption"
android:layout_width="match_parent"
@@ -302,6 +309,17 @@
</LinearLayout>
+ <!-- Required, not decorative: the bundled SPAKE2 library is
+ LGPL-3.0 and the combined work has to give the user prominent
+ notice of that and of where to get the source. -->
+ <Button
+ android:id="@+id/licenses"
+ style="@style/Button.Secondary"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/space_lg"
+ android:text="@string/licenses"/>
+
</LinearLayout>
</ScrollView>