Skip to content

Releases - #2

Open
yukinine-dev wants to merge 8 commits into
homefrom
releases
Open

Releases#2
yukinine-dev wants to merge 8 commits into
homefrom
releases

Conversation

@yukinine-dev

Copy link
Copy Markdown
Owner

Релизы

Baseline is v3.13 (windowAnimationStyle fix) — untouched, this only
adds the swipe gesture on top of it.

Root of the "bottom sheet": BottomAlertActivity already configures
its Window as WRAP_CONTENT + gravity=BOTTOM, so the DecorView's first
child IS the visible dialog (icon/title/content/buttons together).
Drag handle: @id/imageView, the existing 48x4dp pin ImageView at the
top of install_content_view(.xml/_kchi.xml), present on all five
screens that extend BottomAlertActivity (InstallStaging,
InstallInstalling, InstallFailed, InstallSuccess,
PackageInstallerActivity) since they all inflate one of those two
layouts.

New class SwipeDismissController (View.OnTouchListener + Runnable,
hand-written smali, no material/library dependency):
- ACTION_DOWN on the handle: snapshot raw Y, current translationY,
  sheet height; cancel any in-flight settle animation.
- ACTION_MOVE: gated by ViewConfiguration's touch slop so a small
  jitter never moves anything; once past slop, sheet.translationY
  follows the finger 1:1, clamped at 0 so it can't be dragged above
  its resting position (this doubles as the swipe-up-to-restore path
  — there's no separate "collapsed" state in a one-shot confirmation
  dialog, so "restore" and "rest position" are the same target).
- ACTION_UP: dismisses only if the gesture was a real drag AND
  (translationY passed 35% of sheet height OR fling velocity exceeds
  ViewConfiguration's scaled minimum) — otherwise animates back to 0.
  Dismiss finish()/overridePendingTransition(0,0) fires via
  postDelayed(this, ...) after the manual drag animation completes,
  so it never fights the swipe motion or replays the (still intact)
  theme animation on top of it.
- ACTION_CANCEL: always settles back to 0, never dismisses.

Touch handling is attached ONLY to the pill via setOnTouchListener,
never to the sheet root or any container, so buttons, ScrollView,
RecyclerView and any other in-content gestures are structurally
unreachable by it — no onInterceptTouchEvent anywhere in this patch.

Single integration point: BottomAlertActivity.setupAlert(), right
after installContent(), calling the new static
SwipeDismissController.attach(Activity). Applies to all three apks
uniformly since their classes.dex were already confirmed identical
in v3.13 and stayed identical after this patch (verified by hash).
Did not touch PackageInstallerActivity's cancellation logic
(setPermissionsResult/abandonSession) or the v3.13 windowAnimationStyle
fix.

Verified statically: apktool build succeeded (valid smali), and the
assembled classes.dex was disassembled with androguard and manually
traced instruction-by-instruction against the intended control flow
(branch targets, register lifetimes, clamp/threshold logic) — no
device/emulator was available in this environment to confirm the
actual on-screen feel, hit-target comfort of the 4dp-tall handle, or
interaction with any OEM overlay. Needs a real swipe test on device
before wider rollout.
Baseline is v3.14, untouched — entrance animation (windowAnimationStyle/
NewUIDialogAnimation/styles.xml), PackageInstaller cancellation logic,
module structure and signing key are all unchanged. This only replaces
the swipe mechanism.

v3.14's pill-only OnTouchListener is gone (SwipeDismissController
removed) — it can't satisfy "drag from anywhere in the sheet," since
OnTouchListener on a single small child never gets first look at
touches landing elsewhere. Replaced with SwipeSheetContainer, a
FrameLayout subclass inserted between the DecorView and its original
child (icon/title/content/buttons together) at the same hook point as
before (BottomAlertActivity.setupAlert(), right after installContent()).
Being an ancestor of everything, it gets real ViewGroup arbitration via
onInterceptTouchEvent — the only correct way to let an outer drag and
inner taps/scrolls/clicks coexist. It doesn't intercept ACTION_DOWN, so
every child (buttons, and any ScrollView/RecyclerView — none exist in
our own layouts today, but the mechanism is general) sees it and behaves
exactly as before. It only starts stealing a gesture once movement
crosses touch slop AND is predominantly vertical AND downward; a child
already mid-scroll can still call requestDisallowInterceptTouchEvent
(standard ViewGroup behavior, inherited free) to keep it. Once stolen,
the sheet's translationY tracks the finger 1:1 every MOVE, clamped at 0
(recomputed from the down point each time, not incremental — no drift).

Threshold is exactly what was asked: 25% visible height / 75% of the
sheet's own opened height, snapshotted once when the drag begins and
never recomputed against a shrinking "current" height mid-drag. No
velocity anywhere in this file — a fast short flick that doesn't cross
75% animates back to 0, full stop. ACTION_UP and ACTION_CANCEL share
one code path: if the threshold was already passed, cancel still
completes the dismiss instead of snapping an almost-closed sheet back
open. Dismiss finish()/overridePendingTransition(0,0) fires through
postDelayed(this, 220) after the manual animation ends, so it never
fights the drag or double-animates against the (untouched) entrance
theme. No hidden collapsed state: settle always lands exactly at 0,
dismiss always ends in finish().

Install-mode lock (the "критически важно" part) needed no new gating
logic at all: SwipeSheetContainer.attach() checks
`instanceof InstallInstalling` before touching the view tree and
returns immediately if so — that screen is never wrapped, so swipe/
drag/tap-there literally cannot do anything, by construction, without
this patch going anywhere near the existing cancellation code. Back
and outside-tap on InstallInstalling were already correctly gated by
existing code found during this pass: onBackPressed() already checks
mCancelButton.isEnabled(), and InstallingAsyncTask.onPostExecute()
already calls setFinishOnTouchOutside(false) the moment session.commit()
returns — both untouched. The real Cancel button's click handler
(AlertController's negative button, wired in onCreate) is untouched.
Swipe code calls abandonSession() nowhere — it doesn't even exist on
this screen.

All three apks patched identically; classes.dex hash-verified equal
after the rebuild, same as after every prior patch. Same debug keystore
as v3.13/v3.14 (SHA-1 cfd32bf8...), so the upgrade chain isn't broken.

Verified statically only (no device in this environment): apktool
build succeeded, and every branch of onInterceptTouchEvent/onTouchEvent/
attach/beginDrag was disassembled from the built classes.dex with
androguard and traced instruction-by-instruction against the intended
control flow — branch targets, the 0.75f threshold constant's bit
pattern, clamp logic, and the UP/CANCEL convergence all confirmed
against the actual assembled bytecode. What's not verified: on-screen
feel (whether tracking feels 1:1 without jank), real interaction with
a genuinely scrollable child (none exist in this app's own layouts to
test against), and any OEM touch-handling quirks. Needs a real device
pass before wider rollout.
…agnosed

Built on v3.14/v3.15 (both untouched). Three device-reported issues,
each investigated to root cause before any change.

PROBLEM A — background/shape stayed put while content dragged.
Root cause: the rounded sheet is the WINDOW background drawable
(Window.setBackgroundDrawable(dialog_background_inset), set in
BottomAlertActivity.onCreate) — it lives on the DecorView, not on any
child. v3.15 translated an inner child (the AlertController alert
layout that holds icon/text/buttons), so content moved but the window
background never did. Verified by reading onCreate + resolving the
drawable id.
Fix: translate the DecorView itself, which carries BOTH its background
(the rounded shape) and all content, so the whole sheet moves as one
unit. No inner-child translation, no separate targets.

PROBLEM C — blur looked worse ("soapy") on v3.15.
Root cause: decompiled v3.14 and v3.15 and diffed every file — the ONLY
differences were smali (the gesture classes + one hook line). Zero
resource/style/drawable/dimen/window changes. So the blur regression
was caused purely by v3.15 inserting a wrapping FrameLayout
(SwipeSheetContainer) between the DecorView and its child, which
restructured the exact view tree the ROM's window blur/composition
depends on.
Fix: stop restructuring the tree entirely. v3.16 inserts NO view. The
DecorView → alert-layout hierarchy is now identical to stock/v3.14, so
the window background + FLAG_BLUR_BEHIND/setBlurBehindRadius composite
exactly as before. Blur is not "tuned" — the cause was removed.

New gesture architecture (fixes A and C together, satisfies all v3.15
drag requirements):
SwipeSheetController is a plain controller object (no View, nothing
added to the tree). BottomAlertActivity overrides dispatchTouchEvent
and delegates to it:
- ACTION_DOWN is always passed through to super, so children (buttons)
  press and taps work exactly as before.
- A gesture is only stolen once movement crosses ViewConfiguration
  touch slop AND is predominantly vertical AND downward. On steal, one
  ACTION_CANCEL is dispatched to the children (so a half-pressed button
  resets) and the controller consumes from then on. This is real
  tap/scroll/drag arbitration, not a blanket root OnTouchListener.
- While dragging, DecorView.translationY tracks the finger 1:1 via
  getRawY (screen coords, drift-free), clamped >= 0 so the sheet can
  never go above its resting position; dragging down then back up
  returns it toward 0 with the finger.
- Threshold is 75% of the sheet's opened height, snapshotted once at
  drag start (getHeight at the moment the drag begins), never
  recomputed mid-drag. No velocity is used anywhere — a fast short
  flick under 75% settles back.
- ACTION_UP and ACTION_CANCEL share one decision path: past 75% ->
  animate down and finish(); otherwise animate back to 0. So CANCEL
  after the threshold still completes the dismiss instead of snapping
  an almost-closed sheet back open.
- Dismiss finish()/overridePendingTransition(0,0) fires via
  postDelayed(this, 200) after the manual slide, so it never fights the
  drag or the (untouched) entrance animation.

Install mode is locked exactly as required and by construction:
SwipeSheetController.attach() returns null for InstallInstalling, so
mSwipe is null there and dispatchTouchEvent falls straight through to
super — swipe/drag/tap-outside do nothing on the installing screen,
and Back/outside remain governed by the existing (untouched) code
(onBackPressed checks mCancelButton.isEnabled(); onPostExecute sets
setFinishOnTouchOutside(false) at commit).

PROBLEM B — Cancel button doesn't cancel (device: button is grey).
Traced the full path, did not assume: the negative-button listener
(lambda$onCreate$0) is correctly wired via AlertController.setButton(-2)
and calls AsyncTask.cancel(true) + PackageInstaller.abandonSession(
mSessionId) + setResult(CANCELED) + finish(). doInBackground polls
isCancelled() each 1MB chunk (cooperative pre-commit cancel).
session.commit() runs in onPostExecute (UI thread) AFTER the whole APK
is written, and the button is disabled (setEnabled(false)) right after
that commit. The reported symptom — a GREY button — means the install
has already passed commit by the time the screen is interactive: for a
local APK on a privileged system installer the write+commit is
near-instant, so the button is correctly disabled post-commit.
abandonSession() after commit cannot un-install (Android limitation).
This is NOT a wiring bug and is NOT caused by the swipe work
(InstallInstalling is never wrapped/handled by the gesture code). No
change made to the cancellation path — the only way to make Cancel
usable would be to deliberately add a pre-commit confirmation/hold,
which is a flow change the spec said not to make; left for a separate
decision.

All three apks (MIUI/Google/AOSP) patched identically; classes.dex
hash-verified equal after rebuild. Same debug keystore as v3.13-v3.15
(SHA-1 cfd32bf8...). Module structure and signing unchanged.

Static verification only (no device here): apktool build clean, and
dispatchTouchEvent + onDispatch + apply + settle/dismiss disassembled
from the built classes.dex with androguard and traced branch-by-branch
against the intended flow (slop/direction gate, clamp, 0.75f threshold
bit pattern, UP/CANCEL convergence, InstallInstalling null-gate). What
still needs a real device: that translating the DecorView slides the
whole sheet cleanly on the target ROM, drag feel, and that removing the
wrapper restores blur as expected.
Built on v3.14/v3.15/v3.16 (all untouched). Two targeted changes;
blur deliberately left alone.

PILL (resource-only, all 3 apks):
Investigation: @id/imageView is 48dp x 4dp, no padding, default
scaleType (fitCenter); @drawable/pin is a shape with intrinsic size
48dp x 2dp. Under fitCenter the pin already spans the full 48dp view
width (scale=min(48/48,4/2)=1.0 -> 48x2 centered), so there is NO
internal letterbox — the perceived side space was the short 48dp
handle sitting in the full-width sheet. Per decision, widen the handle
to 64dp WITHOUT fitXY (so height is never stretched):
- res/drawable/pin.xml <size> width 48dp -> 64dp (height stays 2dp,
  corners 2dp).
- install_content_view.xml + install_content_view_kchi.xml imageView
  layout_width 48dp -> 64dp (height stays 4dp).
fitCenter then renders the pin at 64x2 centered vertically in the
64x4 view: full 64dp width, unchanged 2dp visual height. Sheet size
untouched.

CANCEL — real 3s pre-commit window (flow change, authorized):
Root cause confirmed by full lifecycle trace: mCancelButton is created
enabled in onCreate; it is only meaningfully enabled during the async
APK write; InstallingAsyncTask.onPostExecute called session.commit()
the instant the write finished and disabled the button on the very
next lines, so on a fast/privileged local install the button was grey
before the user could act.
Change (does NOT delay the APK write, only defers commit):
- New state field mCommitState (0 idle, 1 PENDING, 2 CANCELLED,
  3 COMMITTED) + mPendingCommit runnable.
- onPostExecute no longer commits inline. After the write completes it
  builds the IntentSender as before and calls the new host method
  scheduleCommit(session, sender).
- scheduleCommit(): state=PENDING, creates PendingCommit(host, session,
  sender), and mCancelButton.postDelayed(it, 3000). The button stays
  ENABLED for this whole window; it is NOT disabled here.
- After 3s PendingCommit.run() -> host.commitNow(session, sender):
  proceeds only if state==PENDING and !isFinishing(); then state=
  COMMITTED, session.commit(sender), mCancelButton.setEnabled(false),
  setFinishOnTouchOutside(false). Post-commit behaviour is exactly the
  original.
- Cancel (existing lambda$onCreate$0) now first sets state=CANCELLED
  and mCancelButton.removeCallbacks(mPendingCommit), THEN runs the
  existing AsyncTask.cancel + abandonSession + setResult + finish path.
Race safety (two independent barriers): Cancel both removes the queued
callback AND flips state to CANCELLED; commitNow refuses to commit
unless state is still PENDING, so even a callback that already
dequeued cannot commit after Cancel. State is one-way into COMMITTED /
CANCELLED, so commit runs at most once and never after Cancel.
No visible countdown (per decision) — the button simply stays active
for 3s. No new cancellation mechanism: the real cancel is still the
existing abandonSession path, now reachable because the point of no
return (commit) is deferred behind the window.

Swipe controller (v3.16) is unchanged and still skips InstallInstalling
(mSwipe null there), so the gesture layer never interferes with this
screen. Blur untouched: investigation showed all resources AND
BottomAlertActivity.onCreate (window bg / setBlurBehindRadius / flags)
are byte-identical across v3.14/v3.15/v3.16, so there is no proven
version-to-version cause to fix — not changing it blindly.

All three apks (MIUI/Google/AOSP) patched identically; classes.dex
hash-verified equal after rebuild. Same debug keystore (SHA-1
cfd32bf8...). Module structure and signing unchanged.

Static verification only (no device here): apktool build clean;
scheduleCommit / commitNow / PendingCommit.run / the modified
onPostExecute / the modified Cancel lambda were disassembled from the
built classes.dex with androguard and traced branch-by-branch (state
transitions, PENDING/CANCELLED/COMMITTED guards, removeCallbacks,
3000ms delay, isFinishing guard). Pill width 64dp confirmed in the
rebuilt resources. What still needs a device: that the 3s window feels
right and that Cancel within it actually aborts on the target ROM, and
the pill's on-screen width.
…lletin

Built on v3.14-v3.17 (all untouched). Two minimal, local fixes; the 3s
pre-commit cancel logic, swipe, pill (64dp) and blur are unchanged.

1) Outside-tap no longer closes InstallInstalling.
Cause: setFinishOnTouchOutside(false) was only called after commit()
(and in an onResume side-path), so during onCreate + the whole 3s
pre-commit window the theme default windowCloseOnTouchOutside=true was
in effect and a tap outside the sheet finished the activity.
Fix: one call to setFinishOnTouchOutside(false) in
InstallInstalling.onCreate, right after super.onCreate, so it holds for
the entire lifecycle. Standard window mechanism (no touch interception);
governs only taps outside the window, so Cancel, in-sheet buttons and
swipe are unaffected. Scoped to InstallInstalling only — the confirm
screen (PackageInstallerActivity) keeps its normal outside-tap-to-close.

2) Version bulletin ("old -> new version") no longer stretches.
Cause: version_view in install_content_view_kchi.xml used
layout_height="0dp" + layout_weight="1.0" inside a fill_parent height
chain, so it expanded to absorb all leftover vertical space and the
short version info was centered in the surplus.
Fix: version_view -> layout_height="wrap_content" and weight removed, so
the block wraps its content. Text sizes, backgrounds, chips and the
inner rows are untouched; the residual inner weights become inert in a
wrap_content parent.

Cancel 3s logic verified unchanged: scheduleCommit, commitNow,
PendingCommit and the modified onPostExecute/onCreate cancel lambda are
byte-identical between the v3.17 and v3.18 builds (apples-to-apples
apktool decompile). Only new bytecode in InstallInstalling is the two
onCreate instructions; method set otherwise identical.

All three apks (MIUI/Google/AOSP) patched identically; classes.dex
hash-verified equal after rebuild. Same debug keystore (SHA-1
cfd32bf8...). Module structure unchanged.

Static verification only (no device): apktool build clean; onCreate now
runs super.onCreate -> setFinishOnTouchOutside(false) -> getIntent
(confirmed in the built dex); version_view is wrap_content with no
weight in the rebuilt resource. Needs a device to confirm the
outside-tap is dead during the 3s window and the bulletin height looks
right.
Built on v3.14-v3.18 (all untouched). Layout-only change; classes.dex is
byte-identical to v3.18 (md5 5e0e5723...) across all three apks.

Problem (device): big empty horizontal space to the LEFT of the version
value ("<app> (<versionCode>)") inside the version bulletin.
Root cause: the value chips (version_old_layout / version_new_layout,
wrap_content) sit inside their columns (installed_info_header and the
new-version column), which are layout_width=fill_parent + layout_weight=1
(each half the row) and carried android:gravity="center". Since the
column is much wider than the short version text, center gravity placed
the narrow chip in the middle -> large empty space beside it. Not
padding/margin/inset/translationX: dialog_sub_background has no inset,
RunningTextView (marquee) is wrap_content and doesn't force width, the
chips are wrap_content.

Fix (exactly 3 attributes in install_content_view_kchi.xml):
- installed_info_header: gravity "center" -> "center_vertical|start"
- new-version column:     gravity "center" -> "center_vertical|start"
- version_old_layout:     layout_gravity "center|top" -> "start|top"
version_new_layout has no layout_gravity, so it follows its now
start-aligned parent column. Vertical centering preserved; plate size,
pill, swipe, Cancel/3s window, outside-tap, blur all untouched. The
"Old Version"/"New version" labels are intentionally left centered.

Verified statically: diff against v3.18 shows exactly these 3 attribute
changes and nothing else in the layout; classes.dex unchanged vs v3.18;
same debug keystore (SHA-1 cfd32bf8...); module structure unchanged;
v3.14-v3.18 release zips untouched. Needs a device to confirm the value
now starts at the left in both fresh-install and update scenarios.
…d, cmp & verifyres dumps, apktool build output; keep latest release zip
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant