<feed xmlns='http://www.w3.org/2005/Atom'>
<title>android/scrcpy-android, branch 0.4</title>
<subtitle>[no description]</subtitle>
<link rel='alternate' type='text/html' href='http://git.0xlena.dev/android/scrcpy-android/'/>
<entry>
<title>release: 0.4</title>
<updated>2026-07-01T00:00:00+00:00</updated>
<author>
<name>Lena</name>
<email>lena@omega</email>
</author>
<published>2026-07-01T00:00:00+00:00</published>
<link rel='alternate' type='text/html' href='http://git.0xlena.dev/android/scrcpy-android/commit/?id=b6c19916afc382875836ee7d13c7cd6e5a5181c1'/>
<id>b6c19916afc382875836ee7d13c7cd6e5a5181c1</id>
<content type='text'>
Address the F-Droid submission review (fdroiddata!41394): the pairing
form takes one device address instead of two loose ports, and both
screens now clear the system bars under Android 15's edge-to-edge.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Address the F-Droid submission review (fdroiddata!41394): the pairing
form takes one device address instead of two loose ports, and both
screens now clear the system bars under Android 15's edge-to-edge.
</pre>
</div>
</content>
</entry>
<entry>
<title>fastlane: regenerate screenshots</title>
<updated>2026-07-01T00:00:00+00:00</updated>
<author>
<name>Lena</name>
<email>lena@omega</email>
</author>
<published>2026-07-01T00:00:00+00:00</published>
<link rel='alternate' type='text/html' href='http://git.0xlena.dev/android/scrcpy-android/commit/?id=b894cca18ea23f3d31ca0c920798cdf07a990ead'/>
<id>b894cca18ea23f3d31ca0c920798cdf07a990ead</id>
<content type='text'>
Captured with ./test screenshots. Both tracked shots were taken before
the inset fix: the main screen has its header under the status bar, and
the settings shot is missing its title and first section header behind
the action bar.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Captured with ./test screenshots. Both tracked shots were taken before
the inset fix: the main screen has its header under the status bar, and
the settings shot is missing its title and first section header behind
the action bar.
</pre>
</div>
</content>
</entry>
<entry>
<title>test: add a screenshot capture tier</title>
<updated>2026-07-01T00:00:00+00:00</updated>
<author>
<name>Lena</name>
<email>lena@omega</email>
</author>
<published>2026-07-01T00:00:00+00:00</published>
<link rel='alternate' type='text/html' href='http://git.0xlena.dev/android/scrcpy-android/commit/?id=f6668454daaa0b5b559723b3bb685c244456247b'/>
<id>f6668454daaa0b5b559723b3bb685c244456247b</id>
<content type='text'>
The store screenshots were made by hand, so nothing kept them in step
with the UI. Add ./test screenshots, which boots a pixel_6 AVD on the
same image the e2e tier uses and overwrites the tracked PNGs.

The AVD is its own so a capture run cannot disturb the device state e2e
asserts against, and the panel comes from the device profile: forcing
geometry with wm size on a booted software-GPU emulator ANRs SystemUI
and the ANR dialog lands in the capture. SystemUI demo mode does the
same, so the status bar is left live. Each shot is rejected unless the
app owns the focused window and the PNG has the expected geometry.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
The store screenshots were made by hand, so nothing kept them in step
with the UI. Add ./test screenshots, which boots a pixel_6 AVD on the
same image the e2e tier uses and overwrites the tracked PNGs.

The AVD is its own so a capture run cannot disturb the device state e2e
asserts against, and the panel comes from the device profile: forcing
geometry with wm size on a booted software-GPU emulator ANRs SystemUI
and the ANR dialog lands in the capture. SystemUI demo mode does the
same, so the status bar is left live. Each shot is rejected unless the
app owns the focused window and the PNG has the expected geometry.
</pre>
</div>
</content>
</entry>
<entry>
<title>app: enter the device address as one host:port field</title>
<updated>2026-07-01T00:00:00+00:00</updated>
<author>
<name>Lena</name>
<email>lena@omega</email>
</author>
<published>2026-07-01T00:00:00+00:00</published>
<link rel='alternate' type='text/html' href='http://git.0xlena.dev/android/scrcpy-android/commit/?id=30ee8be82e44d1a8250d1f6e27e71f7d5f24aec5'/>
<id>30ee8be82e44d1a8250d1f6e27e71f7d5f24aec5</id>
<content type='text'>
The form asked for a host, a pairing port and a connection port as three
separate fields. Nothing on screen says which port is which, and the two
are only distinguishable if the reader already knows how adb pair works
on Android 11+.

Take the connection endpoint the way the target prints it, as a single
"ip:port" string copied off the Wireless debugging screen, and leave the
pairing dialog with just its port and code. Devices.parseAddress() does
the split and rejects anything malformed rather than guessing: an
unbracketed IPv6 literal would otherwise be split at the wrong colon.

Reported on the F-Droid submission (fdroiddata!41394).
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
The form asked for a host, a pairing port and a connection port as three
separate fields. Nothing on screen says which port is which, and the two
are only distinguishable if the reader already knows how adb pair works
on Android 11+.

Take the connection endpoint the way the target prints it, as a single
"ip:port" string copied off the Wireless debugging screen, and leave the
pairing dialog with just its port and code. Devices.parseAddress() does
the split and rejects anything malformed rather than guessing: an
unbracketed IPv6 literal would otherwise be split at the wrong colon.

Reported on the F-Droid submission (fdroiddata!41394).
</pre>
</div>
</content>
</entry>
<entry>
<title>app: pad Main and Settings for system bar insets</title>
<updated>2026-07-01T00:00:00+00:00</updated>
<author>
<name>Lena</name>
<email>lena@omega</email>
</author>
<published>2026-07-01T00:00:00+00:00</published>
<link rel='alternate' type='text/html' href='http://git.0xlena.dev/android/scrcpy-android/commit/?id=c03f0464c1f834c2f4d8642cbfad322033d368b7'/>
<id>c03f0464c1f834c2f4d8642cbfad322033d368b7</id>
<content type='text'>
targetSdk 35 makes every window edge-to-edge on Android 15. Neither
activity handled insets, so Main drew its header under the status bar
and the Settings ScrollView started at window y=0: the framework action
bar covered its first 80dp and the navigation bar covered the last rows.

Pad both roots by the system bar insets. Main adds the IME inset as
well, since an edge-to-edge window is not resized when the keyboard
opens. Settings drops the framework action bar and draws its own title
like Main already does, which removes the action-bar-versus-inset
interaction entirely.

Reported on the F-Droid submission (fdroiddata!41394).
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
targetSdk 35 makes every window edge-to-edge on Android 15. Neither
activity handled insets, so Main drew its header under the status bar
and the Settings ScrollView started at window y=0: the framework action
bar covered its first 80dp and the navigation bar covered the last rows.

Pad both roots by the system bar insets. Main adds the IME inset as
well, since an edge-to-edge window is not resized when the keyboard
opens. Settings drops the framework action bar and draws its own title
like Main already does, which removes the action-bar-versus-inset
interaction entirely.

Reported on the F-Droid submission (fdroiddata!41394).
</pre>
</div>
</content>
</entry>
<entry>
<title>release: 0.3</title>
<updated>2026-07-01T00:00:00+00:00</updated>
<author>
<name>Lena</name>
<email>lena@omega</email>
</author>
<published>2026-07-01T00:00:00+00:00</published>
<link rel='alternate' type='text/html' href='http://git.0xlena.dev/android/scrcpy-android/commit/?id=be7a012517905f0a36b2e68f0df7a311ca191fff'/>
<id>be7a012517905f0a36b2e68f0df7a311ca191fff</id>
<content type='text'>
Migrate hosting from Codeberg to GitLab. Update the LGPL
source-availability notices in THIRD_PARTY_NOTICES to
gitlab.com/0xlena/scrcpy-android.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Migrate hosting from Codeberg to GitLab. Update the LGPL
source-availability notices in THIRD_PARTY_NOTICES to
gitlab.com/0xlena/scrcpy-android.
</pre>
</div>
</content>
</entry>
<entry>
<title>release: 0.2</title>
<updated>2026-07-01T00:00:00+00:00</updated>
<author>
<name>Lena</name>
<email>lena@omega</email>
</author>
<published>2026-07-01T00:00:00+00:00</published>
<link rel='alternate' type='text/html' href='http://git.0xlena.dev/android/scrcpy-android/commit/?id=0678b16dc31802a069bd3ee76c12abccbe484dd7'/>
<id>0678b16dc31802a069bd3ee76c12abccbe484dd7</id>
<content type='text'>
Cut 0.2 for the F-Droid submission: it carries the opus playback fix,
transactional session bring-up and teardown, the activity hardening,
and the release-input verification. versionCode 2 corresponds to the
already-written changelog for the store listing.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Cut 0.2 for the F-Droid submission: it carries the opus playback fix,
transactional session bring-up and teardown, the activity hardening,
and the release-input verification. versionCode 2 corresponds to the
already-written changelog for the store listing.
</pre>
</div>
</content>
</entry>
<entry>
<title>readme: document security and release policy</title>
<updated>2026-07-01T00:00:00+00:00</updated>
<author>
<name>Lena</name>
<email>lena@omega</email>
</author>
<published>2026-07-01T00:00:00+00:00</published>
<link rel='alternate' type='text/html' href='http://git.0xlena.dev/android/scrcpy-android/commit/?id=701788299cd1b37dfdfc22b36e83ffd85e73a5ff'/>
<id>701788299cd1b37dfdfc22b36e83ffd85e73a5ff</id>
<content type='text'>
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
</pre>
</div>
</content>
</entry>
<entry>
<title>build: verify release inputs</title>
<updated>2026-07-01T00:00:00+00:00</updated>
<author>
<name>Lena</name>
<email>lena@omega</email>
</author>
<published>2026-07-01T00:00:00+00:00</published>
<link rel='alternate' type='text/html' href='http://git.0xlena.dev/android/scrcpy-android/commit/?id=0f88f2c1e5e108021ccddeee24f1216107115791'/>
<id>0f88f2c1e5e108021ccddeee24f1216107115791</id>
<content type='text'>
Pin and verify what goes into a release: JitPack confined to the
SPAKE2 module via exclusiveContent, the vendored subtree pulled by
commit SHA instead of a mutable tag, a pinned Docker base digest with
a checksummed cmdline-tools download, and a verifyScrcpyServer task
wired into every assets merge. The expected server checksum can be
overridden with -PscrcpyServerSha256 when the jar is built from
source.

build-apk now requires apksigner and fails unless independent
signature verification succeeds. Split the test image into unit and
e2e targets so JVM-only test runs do not download an emulator. Ship
THIRD_PARTY_NOTICES and the LGPL text for SPAKE2 in the APK. Add
scripts/check as the host quality gate.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Pin and verify what goes into a release: JitPack confined to the
SPAKE2 module via exclusiveContent, the vendored subtree pulled by
commit SHA instead of a mutable tag, a pinned Docker base digest with
a checksummed cmdline-tools download, and a verifyScrcpyServer task
wired into every assets merge. The expected server checksum can be
overridden with -PscrcpyServerSha256 when the jar is built from
source.

build-apk now requires apksigner and fails unless independent
signature verification succeeds. Split the test image into unit and
e2e targets so JVM-only test runs do not download an emulator. Ship
THIRD_PARTY_NOTICES and the LGPL text for SPAKE2 in the APK. Add
scripts/check as the host quality gate.
</pre>
</div>
</content>
</entry>
<entry>
<title>app: fix session lifecycle, teardown, and opus playback</title>
<updated>2026-07-01T00:00:00+00:00</updated>
<author>
<name>Lena</name>
<email>lena@omega</email>
</author>
<published>2026-07-01T00:00:00+00:00</published>
<link rel='alternate' type='text/html' href='http://git.0xlena.dev/android/scrcpy-android/commit/?id=ff7acf898b48359275a5b09b82ed926a945233f8'/>
<id>ff7acf898b48359275a5b09b82ed926a945233f8</id>
<content type='text'>
Opus playback never worked: feed() called dequeueInputBuffer() on a
codec in async-callback mode, which always throws, so every packet
was silently dropped. Feed input through the async callback with a
bounded pending queue instead.

Make bring-up transactional: roll back partially opened streams and
the server shell on failure, join reader threads on stop, and close
the owning ADB streams before releasing sinks. Replace the
openAbstract watchdog thread with a real timeout in the vendored
AdbConnection.open(), which also removes the half-open stream from
the lookup table on failure.

Harden the activity: release owned Surfaces, gate callbacks on a
destroyed flag and a session generation, serialize reconnect, and
handle target replacement via singleTask + onNewIntent. Propagate
device-list write failures instead of swallowing them, bound the
clipboard payload and the video pending queue against hostile
peers, and discard incomplete recordings instead of keeping corrupt
files.

Use the mediaPlayback foreground-service type; Android 15 stops
dataSync services after six hours. Drop the unused
ACCESS_NETWORK_STATE permission.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Opus playback never worked: feed() called dequeueInputBuffer() on a
codec in async-callback mode, which always throws, so every packet
was silently dropped. Feed input through the async callback with a
bounded pending queue instead.

Make bring-up transactional: roll back partially opened streams and
the server shell on failure, join reader threads on stop, and close
the owning ADB streams before releasing sinks. Replace the
openAbstract watchdog thread with a real timeout in the vendored
AdbConnection.open(), which also removes the half-open stream from
the lookup table on failure.

Harden the activity: release owned Surfaces, gate callbacks on a
destroyed flag and a session generation, serialize reconnect, and
handle target replacement via singleTask + onNewIntent. Propagate
device-list write failures instead of swallowing them, bound the
clipboard payload and the video pending queue against hostile
peers, and discard incomplete recordings instead of keeping corrupt
files.

Use the mediaPlayback foreground-service type; Android 15 stops
dataSync services after six hours. Drop the unused
ACCESS_NETWORK_STATE permission.
</pre>
</div>
</content>
</entry>
</feed>
