Fix call chip rendering and placement stability
This commit is contained in:
@@ -0,0 +1,27 @@
|
|||||||
|
package se.ajpanton.statusbartweak.runtime;
|
||||||
|
|
||||||
|
public final class RuntimeMutationGuard {
|
||||||
|
private static final ThreadLocal<Integer> SNAPSHOT_RENDER_DEPTH =
|
||||||
|
ThreadLocal.withInitial(() -> 0);
|
||||||
|
|
||||||
|
private RuntimeMutationGuard() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void enterSnapshotRenderMutation() {
|
||||||
|
SNAPSHOT_RENDER_DEPTH.set(SNAPSHOT_RENDER_DEPTH.get() + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void exitSnapshotRenderMutation() {
|
||||||
|
int depth = SNAPSHOT_RENDER_DEPTH.get() - 1;
|
||||||
|
if (depth <= 0) {
|
||||||
|
SNAPSHOT_RENDER_DEPTH.remove();
|
||||||
|
} else {
|
||||||
|
SNAPSHOT_RENDER_DEPTH.set(depth);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isSnapshotRenderMutation() {
|
||||||
|
Integer depth = SNAPSHOT_RENDER_DEPTH.get();
|
||||||
|
return depth != null && depth > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
+6
@@ -34,6 +34,7 @@ import java.util.WeakHashMap;
|
|||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
import se.ajpanton.statusbartweak.runtime.NotificationKeyReflection;
|
import se.ajpanton.statusbartweak.runtime.NotificationKeyReflection;
|
||||||
|
import se.ajpanton.statusbartweak.runtime.RuntimeMutationGuard;
|
||||||
import se.ajpanton.statusbartweak.runtime.ViewIdNames;
|
import se.ajpanton.statusbartweak.runtime.ViewIdNames;
|
||||||
import se.ajpanton.statusbartweak.runtime.features.RuntimeContext;
|
import se.ajpanton.statusbartweak.runtime.features.RuntimeContext;
|
||||||
import se.ajpanton.statusbartweak.runtime.hooks.ReflectionSupport;
|
import se.ajpanton.statusbartweak.runtime.hooks.ReflectionSupport;
|
||||||
@@ -1491,6 +1492,9 @@ final class StockLayoutCanvasController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void markStatusChipLifecycleDirtyIfNeeded(View view, View fallbackRoot) {
|
private void markStatusChipLifecycleDirtyIfNeeded(View view, View fallbackRoot) {
|
||||||
|
if (RuntimeMutationGuard.isSnapshotRenderMutation()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (view == null || !isStatusChipCandidate(view)) {
|
if (view == null || !isStatusChipCandidate(view)) {
|
||||||
View root = view != null ? unlockedStatusBarRootFor(view) : fallbackRoot;
|
View root = view != null ? unlockedStatusBarRootFor(view) : fallbackRoot;
|
||||||
if (deferDrawerStatusChipRefresh(root)) {
|
if (deferDrawerStatusChipRefresh(root)) {
|
||||||
@@ -2989,6 +2993,7 @@ final class StockLayoutCanvasController {
|
|||||||
private boolean isTrackedStatusChipWriteTarget(View view) {
|
private boolean isTrackedStatusChipWriteTarget(View view) {
|
||||||
if (view == null
|
if (view == null
|
||||||
|| ownHiddenViewAlphaWriteDepth > 0
|
|| ownHiddenViewAlphaWriteDepth > 0
|
||||||
|
|| RuntimeMutationGuard.isSnapshotRenderMutation()
|
||||||
|| !trackedStatusChipSources.contains(view)
|
|| !trackedStatusChipSources.contains(view)
|
||||||
|| !hiddenViewStates.containsKey(view)
|
|| !hiddenViewStates.containsKey(view)
|
||||||
|| !view.isAttachedToWindow()
|
|| !view.isAttachedToWindow()
|
||||||
@@ -3008,6 +3013,7 @@ final class StockLayoutCanvasController {
|
|||||||
private boolean isStatusChipShellWriteTarget(View view) {
|
private boolean isStatusChipShellWriteTarget(View view) {
|
||||||
if (view == null
|
if (view == null
|
||||||
|| ownHiddenViewAlphaWriteDepth > 0
|
|| ownHiddenViewAlphaWriteDepth > 0
|
||||||
|
|| RuntimeMutationGuard.isSnapshotRenderMutation()
|
||||||
|| !view.isAttachedToWindow()
|
|| !view.isAttachedToWindow()
|
||||||
|| !isLayoutEnabled(view.getContext())
|
|| !isLayoutEnabled(view.getContext())
|
||||||
|| !isStatusChipShell(view)) {
|
|| !isStatusChipShell(view)) {
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ import java.util.Objects;
|
|||||||
import java.util.WeakHashMap;
|
import java.util.WeakHashMap;
|
||||||
|
|
||||||
import se.ajpanton.statusbartweak.runtime.NotificationKeyReflection;
|
import se.ajpanton.statusbartweak.runtime.NotificationKeyReflection;
|
||||||
|
import se.ajpanton.statusbartweak.runtime.RuntimeMutationGuard;
|
||||||
import se.ajpanton.statusbartweak.runtime.ViewIdNames;
|
import se.ajpanton.statusbartweak.runtime.ViewIdNames;
|
||||||
import se.ajpanton.statusbartweak.runtime.hooks.ReflectionSupport;
|
import se.ajpanton.statusbartweak.runtime.hooks.ReflectionSupport;
|
||||||
import se.ajpanton.statusbartweak.runtime.layoutsolver.StatusBarLayoutSolver.Bounds;
|
import se.ajpanton.statusbartweak.runtime.layoutsolver.StatusBarLayoutSolver.Bounds;
|
||||||
@@ -748,16 +749,26 @@ final class SnapshotRenderer {
|
|||||||
bitmap.getHeight())) {
|
bitmap.getHeight())) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
sourceView.setVisibility(View.VISIBLE);
|
RuntimeMutationGuard.enterSnapshotRenderMutation();
|
||||||
sourceView.setAlpha(1f);
|
try {
|
||||||
if (source.mode() == SnapshotMode.STATUS_CHIP) {
|
sourceView.setVisibility(View.VISIBLE);
|
||||||
drawTemporarilySizedView(sourceView, canvas, bitmap.getWidth(), bitmap.getHeight());
|
sourceView.setAlpha(1f);
|
||||||
} else {
|
if (source.mode() == SnapshotMode.STATUS_CHIP) {
|
||||||
sourceView.draw(canvas);
|
drawTemporarilySizedView(sourceView, canvas, bitmap.getWidth(), bitmap.getHeight());
|
||||||
|
} else {
|
||||||
|
sourceView.draw(canvas);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
RuntimeMutationGuard.exitSnapshotRenderMutation();
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
sourceView.setAlpha(oldAlpha);
|
RuntimeMutationGuard.enterSnapshotRenderMutation();
|
||||||
sourceView.setVisibility(oldVisibility);
|
try {
|
||||||
|
sourceView.setAlpha(oldAlpha);
|
||||||
|
sourceView.setVisibility(oldVisibility);
|
||||||
|
} finally {
|
||||||
|
RuntimeMutationGuard.exitSnapshotRenderMutation();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1183,7 +1194,9 @@ final class SnapshotRenderer {
|
|||||||
view.getRight(),
|
view.getRight(),
|
||||||
view.getBottom(),
|
view.getBottom(),
|
||||||
view.getMeasuredWidth(),
|
view.getMeasuredWidth(),
|
||||||
view.getMeasuredHeight()));
|
view.getMeasuredHeight(),
|
||||||
|
view.getVisibility(),
|
||||||
|
view.getAlpha()));
|
||||||
if (view instanceof ViewGroup group) {
|
if (view instanceof ViewGroup group) {
|
||||||
for (int i = 0; i < group.getChildCount(); i++) {
|
for (int i = 0; i < group.getChildCount(); i++) {
|
||||||
captureFrameState(group.getChildAt(i), state);
|
captureFrameState(group.getChildAt(i), state);
|
||||||
@@ -1207,6 +1220,12 @@ final class SnapshotRenderer {
|
|||||||
View.MeasureSpec.makeMeasureSpec(frame.measuredHeight, View.MeasureSpec.EXACTLY));
|
View.MeasureSpec.makeMeasureSpec(frame.measuredHeight, View.MeasureSpec.EXACTLY));
|
||||||
}
|
}
|
||||||
view.layout(frame.left, frame.top, frame.right, frame.bottom);
|
view.layout(frame.left, frame.top, frame.right, frame.bottom);
|
||||||
|
if (view.getAlpha() != frame.alpha) {
|
||||||
|
view.setAlpha(frame.alpha);
|
||||||
|
}
|
||||||
|
if (view.getVisibility() != frame.visibility) {
|
||||||
|
view.setVisibility(frame.visibility);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1221,7 +1240,9 @@ final class SnapshotRenderer {
|
|||||||
int right,
|
int right,
|
||||||
int bottom,
|
int bottom,
|
||||||
int measuredWidth,
|
int measuredWidth,
|
||||||
int measuredHeight
|
int measuredHeight,
|
||||||
|
int visibility,
|
||||||
|
float alpha
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+7
-2
@@ -21,6 +21,10 @@ final class UnlockedChipPlacementController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void clear() {
|
void clear() {
|
||||||
|
resetMissingChipFallback();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void resetMissingChipFallback() {
|
||||||
heldPlacements = null;
|
heldPlacements = null;
|
||||||
lastCollisionBounds = null;
|
lastCollisionBounds = null;
|
||||||
lastRootWidth = 0;
|
lastRootWidth = 0;
|
||||||
@@ -47,10 +51,11 @@ final class UnlockedChipPlacementController {
|
|||||||
return rawPlacements;
|
return rawPlacements;
|
||||||
}
|
}
|
||||||
|
|
||||||
ArrayList<SnapshotPlacement> placements = isAnyChipHidingEnabled(settings)
|
boolean hasMetricSources = metricSources != null && !metricSources.isEmpty();
|
||||||
|
ArrayList<SnapshotPlacement> placements = isAnyChipHidingEnabled(settings) || !hasMetricSources
|
||||||
? new ArrayList<>()
|
? new ArrayList<>()
|
||||||
: heldPlacements(root);
|
: heldPlacements(root);
|
||||||
if (placements.isEmpty()) {
|
if (placements.isEmpty() && hasMetricSources) {
|
||||||
placements = emptyPlacement(root, metricSources);
|
placements = emptyPlacement(root, metricSources);
|
||||||
}
|
}
|
||||||
return placements;
|
return placements;
|
||||||
|
|||||||
+26
-1
@@ -88,7 +88,13 @@ final class UnlockedLayoutPlanner {
|
|||||||
Bounds aodStatusbarBounds = scene != null && scene.isAod()
|
Bounds aodStatusbarBounds = scene != null && scene.isAod()
|
||||||
? aodStatusbarBounds(root, settings, aodNotificationBounds, aodStatusAnchorBounds)
|
? aodStatusbarBounds(root, settings, aodNotificationBounds, aodStatusAnchorBounds)
|
||||||
: null;
|
: null;
|
||||||
LayoutEdges edges = layoutEdges(root, settings, anchors, scene, aodStatusAnchorBounds);
|
LayoutEdges edges = layoutEdges(
|
||||||
|
root,
|
||||||
|
settings,
|
||||||
|
anchors,
|
||||||
|
collectedIcons,
|
||||||
|
scene,
|
||||||
|
aodStatusAnchorBounds);
|
||||||
int statusbarHeight = statusbarHeight(root, anchors, scene, aodStatusContentBounds);
|
int statusbarHeight = statusbarHeight(root, anchors, scene, aodStatusContentBounds);
|
||||||
if (clockEnabledForScene(settings, scene) && clockLayout != null && clockLayout.width() > 0) {
|
if (clockEnabledForScene(settings, scene) && clockLayout != null && clockLayout.width() > 0) {
|
||||||
bands.add(UnlockedLayoutBand.clock(
|
bands.add(UnlockedLayoutBand.clock(
|
||||||
@@ -1393,6 +1399,7 @@ final class UnlockedLayoutPlanner {
|
|||||||
View root,
|
View root,
|
||||||
SbtSettings settings,
|
SbtSettings settings,
|
||||||
RootAnchors anchors,
|
RootAnchors anchors,
|
||||||
|
CollectedIcons collectedIcons,
|
||||||
SceneKey scene,
|
SceneKey scene,
|
||||||
Bounds aodStatusAnchorBounds
|
Bounds aodStatusAnchorBounds
|
||||||
) {
|
) {
|
||||||
@@ -1419,11 +1426,29 @@ final class UnlockedLayoutPlanner {
|
|||||||
if (settings.layoutPaddingRightAddStock) {
|
if (settings.layoutPaddingRightAddStock) {
|
||||||
right -= stockInsets.right;
|
right -= stockInsets.right;
|
||||||
}
|
}
|
||||||
|
if (scene != null && scene.isUnlocked() && hasStatusChipSources(collectedIcons)) {
|
||||||
|
LayoutEdges recentEdges = recentNonAodEdgesByRootWidth.get(rootWidth);
|
||||||
|
if (isReusableUnlockedEdge(left, recentEdges)) {
|
||||||
|
left = recentEdges.left();
|
||||||
|
}
|
||||||
|
}
|
||||||
LayoutEdges edges = new LayoutEdges(left, right);
|
LayoutEdges edges = new LayoutEdges(left, right);
|
||||||
rememberNonAodEdges(rootWidth, scene, edges);
|
rememberNonAodEdges(rootWidth, scene, edges);
|
||||||
return edges;
|
return edges;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean hasStatusChipSources(CollectedIcons icons) {
|
||||||
|
return icons != null
|
||||||
|
&& ((icons.statusChips != null && !icons.statusChips.isEmpty())
|
||||||
|
|| (icons.statusChipMetrics != null && !icons.statusChipMetrics.isEmpty()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isReusableUnlockedEdge(int currentLeft, LayoutEdges recentEdges) {
|
||||||
|
return recentEdges != null
|
||||||
|
&& recentEdges.right() > recentEdges.left()
|
||||||
|
&& Math.abs(currentLeft - recentEdges.left()) <= 8;
|
||||||
|
}
|
||||||
|
|
||||||
private LayoutEdges stableAodEdges(int rootWidth, LayoutEdges aodEdges) {
|
private LayoutEdges stableAodEdges(int rootWidth, LayoutEdges aodEdges) {
|
||||||
if (rootWidth <= 0) {
|
if (rootWidth <= 0) {
|
||||||
return aodEdges;
|
return aodEdges;
|
||||||
|
|||||||
Reference in New Issue
Block a user