From fbab6dac6ac9044fdbed5f81a1555dfe908688c3 Mon Sep 17 00:00:00 2001 From: ajp_anton Date: Thu, 11 Jun 2026 14:57:36 +0000 Subject: [PATCH] Refine clock and unlock statusbar transitions --- .../layout/StockLayoutCanvasController.java | 8 +++-- .../mode/SystemUiStatusBarStateFeature.java | 29 +++++++++++++++++++ .../runtime/render/ClockLayout.java | 16 +++++++--- .../UnlockedIconSnapshotRenderController.java | 14 ++++++++- 4 files changed, 60 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/se/ajpanton/statusbartweak/runtime/layout/StockLayoutCanvasController.java b/app/src/main/java/se/ajpanton/statusbartweak/runtime/layout/StockLayoutCanvasController.java index 0861aba..d109179 100644 --- a/app/src/main/java/se/ajpanton/statusbartweak/runtime/layout/StockLayoutCanvasController.java +++ b/app/src/main/java/se/ajpanton/statusbartweak/runtime/layout/StockLayoutCanvasController.java @@ -1959,8 +1959,12 @@ final class StockLayoutCanvasController { } unlockedIconRenderController.clearRoot(root); dirtyUnlockedLayoutRoots.add(root); - root.requestLayout(); - root.invalidate(); + if (isViewThread(root)) { + applyToRoot(root); + } else { + root.requestLayout(); + root.invalidate(); + } } private boolean isLockscreenScene() { diff --git a/app/src/main/java/se/ajpanton/statusbartweak/runtime/mode/SystemUiStatusBarStateFeature.java b/app/src/main/java/se/ajpanton/statusbartweak/runtime/mode/SystemUiStatusBarStateFeature.java index 46e90b2..01fcd55 100644 --- a/app/src/main/java/se/ajpanton/statusbartweak/runtime/mode/SystemUiStatusBarStateFeature.java +++ b/app/src/main/java/se/ajpanton/statusbartweak/runtime/mode/SystemUiStatusBarStateFeature.java @@ -2,6 +2,8 @@ package se.ajpanton.statusbartweak.runtime.mode; import android.content.Context; +import java.util.List; + import io.github.libxposed.api.XposedModuleInterface; import se.ajpanton.statusbartweak.runtime.SystemContextProvider; import se.ajpanton.statusbartweak.runtime.features.RuntimeContext; @@ -19,6 +21,8 @@ public final class SystemUiStatusBarStateFeature implements RuntimeFeature { private static final String CLASS_STATUS_BAR_STATE_CONTROLLER = "com.android.systemui.statusbar.StatusBarStateControllerImpl"; + private static final String CLASS_KEYGUARD_STATE_CONTROLLER = + "com.android.systemui.statusbar.policy.KeyguardStateControllerImpl"; private boolean installed; @@ -57,9 +61,30 @@ public final class SystemUiStatusBarStateFeature implements RuntimeFeature { updateScene(context, chain.getThisObject()); return result; }); + installKeyguardGoingAwayHook(context, param.getClassLoader()); installed = true; } + private void installKeyguardGoingAwayHook(RuntimeContext context, ClassLoader classLoader) { + Class keyguardClass = ReflectionSupport.findClassIfExists( + CLASS_KEYGUARD_STATE_CONTROLLER, + classLoader); + if (keyguardClass == null) { + return; + } + XposedHookSupport.hookAllMethodsIfExists( + context.getFramework(), + keyguardClass, + "notifyKeyguardGoingAway", + chain -> { + Object result = chain.proceed(); + if (firstBooleanArg(chain.getArgs())) { + context.getModeStateRepository().setUnlocked(); + } + return result; + }); + } + private void updateScene(RuntimeContext context, Object controller) { if (context == null || controller == null) { return; @@ -73,6 +98,10 @@ public final class SystemUiStatusBarStateFeature implements RuntimeFeature { SystemNotificationDisplayStyleDetector.read(systemContext(controller))); } + private boolean firstBooleanArg(List args) { + return args != null && !args.isEmpty() && Boolean.TRUE.equals(args.get(0)); + } + private Context systemContext(Object controller) { Object context = ReflectionSupport.getFieldValue(controller, "mContext"); if (context instanceof Context androidContext) { diff --git a/app/src/main/java/se/ajpanton/statusbartweak/runtime/render/ClockLayout.java b/app/src/main/java/se/ajpanton/statusbartweak/runtime/render/ClockLayout.java index 2147f3e..e4569e8 100644 --- a/app/src/main/java/se/ajpanton/statusbartweak/runtime/render/ClockLayout.java +++ b/app/src/main/java/se/ajpanton/statusbartweak/runtime/render/ClockLayout.java @@ -63,7 +63,8 @@ final class ClockLayout { int baseHeightSteps, int autoGapSteps, int statusbarHeight, - int verticalOffsetSteps + int verticalOffsetSteps, + int bottomRowBaselineAnchorY ) { if (source == null || model == null || model.rows.isEmpty()) { return null; @@ -103,7 +104,8 @@ final class ClockLayout { measuredRows, Math.max(1, autoGapSteps), Math.max(1, statusbarHeight), - verticalOffsetSteps); + verticalOffsetSteps, + bottomRowBaselineAnchorY); RowAlignment alignment = alignRows(measuredRows, position); ArrayList rows = alignment.rows; @@ -215,7 +217,8 @@ final class ClockLayout { ArrayList measuredRows, int autoGapSteps, int statusbarHeight, - int verticalOffsetSteps + int verticalOffsetSteps, + int bottomRowBaselineAnchorY ) { ArrayList positionedRows = new ArrayList<>(measuredRows); int nextBottomSteps = 0; @@ -227,7 +230,12 @@ final class ClockLayout { if (rowIndex == measuredRows.size() - 1) { topSteps = 100 - Math.max(1, row.logicalHeightSteps) - verticalOffsetSteps; int heightPx = Math.max(1, stepsToPx(Math.max(1, row.logicalHeightSteps), statusbarHeight)); - bottomPx = Math.max(1, statusbarHeight) - stepsToPx(verticalOffsetSteps, statusbarHeight); + int offsetPx = stepsToPx(verticalOffsetSteps, statusbarHeight); + if (bottomRowBaselineAnchorY > 0 && row.baseline > 0) { + bottomPx = bottomRowBaselineAnchorY - row.baseline + heightPx - offsetPx; + } else { + bottomPx = Math.max(1, statusbarHeight) - offsetPx; + } } else { MeasuredClockRow nextRow = measuredRows.get(rowIndex + 1); int gapSteps = resolveGapSteps(nextRow.source.gapBeforePx, autoGapSteps); diff --git a/app/src/main/java/se/ajpanton/statusbartweak/runtime/render/UnlockedIconSnapshotRenderController.java b/app/src/main/java/se/ajpanton/statusbartweak/runtime/render/UnlockedIconSnapshotRenderController.java index 25d480f..914327f 100644 --- a/app/src/main/java/se/ajpanton/statusbartweak/runtime/render/UnlockedIconSnapshotRenderController.java +++ b/app/src/main/java/se/ajpanton/statusbartweak/runtime/render/UnlockedIconSnapshotRenderController.java @@ -763,10 +763,22 @@ public final class UnlockedIconSnapshotRenderController { textSizeSteps, autoGapSteps, statusbarHeight, - settings.clockVerticalOffsetPx); + settings.clockVerticalOffsetPx, + stockClockBaselineY(sourceBounds, source)); return layout; } + private int stockClockBaselineY(Bounds sourceBounds, TextView source) { + if (sourceBounds == null || source == null) { + return 0; + } + int baseline = source.getBaseline(); + if (baseline <= 0) { + baseline = ClockLayout.centeredTextBaseline(source, sourceBounds.height); + } + return baseline > 0 ? sourceBounds.top + baseline : 0; + } + private int clockAutoGapSteps(TextView source, int statusbarHeight, int fallbackSteps) { int lineHeight = source != null ? source.getLineHeight() : 0; if (lineHeight <= 0 || statusbarHeight <= 0) {