Improve chip rendering and debug overlays
This commit is contained in:
+56
-10
@@ -140,6 +140,8 @@ final class StockLayoutCanvasController {
|
||||
Collections.newSetFromMap(new WeakHashMap<>());
|
||||
private final Set<View> dirtyUnlockedLayoutRoots =
|
||||
Collections.newSetFromMap(new WeakHashMap<>());
|
||||
private final Set<View> pendingDrawerStatusChipRefreshRoots =
|
||||
Collections.newSetFromMap(new WeakHashMap<>());
|
||||
private final Set<ClassLoader> hookedPluginClassLoaders =
|
||||
Collections.newSetFromMap(new IdentityHashMap<>());
|
||||
private final Set<ClassLoader> pendingPluginClassLoaders =
|
||||
@@ -288,6 +290,7 @@ final class StockLayoutCanvasController {
|
||||
}
|
||||
if (expansion <= 0.01f) {
|
||||
notificationDrawerWasOpen = false;
|
||||
flushDeferredDrawerStatusChipRefreshes();
|
||||
return;
|
||||
}
|
||||
if (expansion <= 0.05f) {
|
||||
@@ -337,6 +340,7 @@ final class StockLayoutCanvasController {
|
||||
} else if (previousState == STATUS_BAR_STATE_SHADE_LOCKED
|
||||
&& currentState != STATUS_BAR_STATE_SHADE_LOCKED) {
|
||||
notificationDrawerWasOpen = false;
|
||||
flushDeferredDrawerStatusChipRefreshes();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1153,9 +1157,6 @@ final class StockLayoutCanvasController {
|
||||
if (activeScene == null) {
|
||||
return;
|
||||
}
|
||||
if (!runtimeContext.getModeStateRepository().isSystemUiShadeLocked() && !activeScene.isAod()) {
|
||||
notificationDrawerWasOpen = false;
|
||||
}
|
||||
if (isNotificationShadeWindowRoot(root)) {
|
||||
if (shouldPrepareCarrierlessAodNotificationTransition(settings, activeScene)) {
|
||||
prepareCarrierlessAodNotificationTransition(root);
|
||||
@@ -1331,8 +1332,8 @@ final class StockLayoutCanvasController {
|
||||
if (activeScene != null && activeScene.isUnlocked()) {
|
||||
if (isKnownRootGeometryChanged(root)) {
|
||||
ownedIconHostManager.setUnlockedHostsVisible(root, false);
|
||||
removeDebugOverlay(root);
|
||||
}
|
||||
removeDebugOverlay(root);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1385,13 +1386,19 @@ final class StockLayoutCanvasController {
|
||||
private void markStatusChipLifecycleDirtyIfNeeded(View view, View fallbackRoot) {
|
||||
if (view == null || !isStatusChipCandidate(view)) {
|
||||
View root = view != null ? unlockedStatusBarRootFor(view) : fallbackRoot;
|
||||
if (deferDrawerStatusChipRefresh(root)) {
|
||||
return;
|
||||
}
|
||||
requestUnlockedLayoutRefresh(root);
|
||||
return;
|
||||
}
|
||||
View root = unlockedStatusBarRootFor(view);
|
||||
if (deferDrawerStatusChipRefresh(root != null ? root : fallbackRoot)) {
|
||||
return;
|
||||
}
|
||||
int signature = statusChipLayoutSignature(view);
|
||||
Integer previous = statusChipLifecycleLayoutSignatureByView.put(view, signature);
|
||||
if (previous == null || previous != signature) {
|
||||
View root = unlockedStatusBarRootFor(view);
|
||||
requestUnlockedLayoutRefresh(root != null ? root : fallbackRoot);
|
||||
}
|
||||
}
|
||||
@@ -1408,6 +1415,9 @@ final class StockLayoutCanvasController {
|
||||
if (root == null || !root.isAttachedToWindow()) {
|
||||
return;
|
||||
}
|
||||
if (deferDrawerStatusChipRefresh(root)) {
|
||||
return;
|
||||
}
|
||||
int signature = statusChipContentSignature(chipSource);
|
||||
Integer previous = statusChipContentSignatureByRoot.put(root, signature);
|
||||
if (previous != null && previous == signature) {
|
||||
@@ -1434,10 +1444,39 @@ final class StockLayoutCanvasController {
|
||||
requestUnlockedLayoutRefresh(root);
|
||||
}
|
||||
|
||||
private boolean deferDrawerStatusChipRefresh(View root) {
|
||||
if (!notificationDrawerWasOpen || root == null || !root.isAttachedToWindow()) {
|
||||
return false;
|
||||
}
|
||||
SceneKey activeScene = runtimeContext.getModeStateRepository().getActiveScene();
|
||||
if (activeScene == null || !activeScene.isUnlocked()) {
|
||||
return false;
|
||||
}
|
||||
pendingDrawerStatusChipRefreshRoots.add(root);
|
||||
return true;
|
||||
}
|
||||
|
||||
private void flushDeferredDrawerStatusChipRefreshes() {
|
||||
if (pendingDrawerStatusChipRefreshRoots.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
ArrayDeque<View> roots = new ArrayDeque<>(pendingDrawerStatusChipRefreshRoots);
|
||||
pendingDrawerStatusChipRefreshRoots.clear();
|
||||
while (!roots.isEmpty()) {
|
||||
View root = roots.removeFirst();
|
||||
if (root != null && root.isAttachedToWindow()) {
|
||||
requestStatusChipRefresh(root);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void requestStatusChipRefresh(View root) {
|
||||
if (root == null || !root.isAttachedToWindow()) {
|
||||
return;
|
||||
}
|
||||
if (deferDrawerStatusChipRefresh(root)) {
|
||||
return;
|
||||
}
|
||||
unlockedIconRenderController.forceChipRefresh(root);
|
||||
requestUnlockedLayoutRefresh(root);
|
||||
}
|
||||
@@ -1517,7 +1556,8 @@ final class StockLayoutCanvasController {
|
||||
return 0;
|
||||
}
|
||||
int result = 17;
|
||||
result = 31 * result + System.identityHashCode(view);
|
||||
result = 31 * result + view.getClass().getName().hashCode();
|
||||
result = 31 * result + view.getId();
|
||||
result = 31 * result + view.getVisibility();
|
||||
result = 31 * result + view.getWidth();
|
||||
result = 31 * result + view.getHeight();
|
||||
@@ -1528,8 +1568,10 @@ final class StockLayoutCanvasController {
|
||||
}
|
||||
if (view instanceof ImageView imageView) {
|
||||
Drawable drawable = imageView.getDrawable();
|
||||
result = 31 * result + System.identityHashCode(drawable);
|
||||
if (drawable != null) {
|
||||
result = 31 * result + drawable.getClass().getName().hashCode();
|
||||
result = 31 * result + drawable.getIntrinsicWidth();
|
||||
result = 31 * result + drawable.getIntrinsicHeight();
|
||||
result = 31 * result + drawable.getBounds().hashCode();
|
||||
}
|
||||
}
|
||||
@@ -1559,8 +1601,10 @@ final class StockLayoutCanvasController {
|
||||
}
|
||||
if (view instanceof ImageView imageView) {
|
||||
Drawable drawable = imageView.getDrawable();
|
||||
result = 31 * result + System.identityHashCode(drawable);
|
||||
if (drawable != null) {
|
||||
result = 31 * result + drawable.getClass().getName().hashCode();
|
||||
result = 31 * result + drawable.getIntrinsicWidth();
|
||||
result = 31 * result + drawable.getIntrinsicHeight();
|
||||
result = 31 * result + drawable.getAlpha();
|
||||
result = 31 * result + drawable.getLevel();
|
||||
result = 31 * result + drawable.getBounds().hashCode();
|
||||
@@ -1936,13 +1980,13 @@ final class StockLayoutCanvasController {
|
||||
if (!aodScene && renderResult.shouldOwnLockscreen()) {
|
||||
hideOrDiscoverLockedStatusBarIconSurfaces(root);
|
||||
}
|
||||
if (aodScene) {
|
||||
if (aodScene || renderResult.shouldOwnLockscreen()) {
|
||||
applyDebugOverlayIfNeeded(
|
||||
root,
|
||||
true,
|
||||
settings,
|
||||
renderResult.layoutChanged(),
|
||||
true,
|
||||
aodScene,
|
||||
activeScene);
|
||||
} else {
|
||||
removeDebugOverlay(root);
|
||||
@@ -2069,6 +2113,7 @@ final class StockLayoutCanvasController {
|
||||
) {
|
||||
int result = 17;
|
||||
result = 31 * result + (layoutEnabled ? 1 : 0);
|
||||
result = 31 * result + (scene != null ? scene.hashCode() : 0);
|
||||
result = 31 * result + (root != null ? root.getWidth() : 0);
|
||||
result = 31 * result + (root != null ? root.getHeight() : 0);
|
||||
if (settings != null) {
|
||||
@@ -3874,6 +3919,7 @@ final class StockLayoutCanvasController {
|
||||
statusChipContentSignatureByRoot.clear();
|
||||
statusChipLayoutSignatureByRoot.clear();
|
||||
statusChipLifecycleLayoutSignatureByView.clear();
|
||||
pendingDrawerStatusChipRefreshRoots.clear();
|
||||
}
|
||||
|
||||
private static boolean containsAny(String value, Set<String> tokens) {
|
||||
|
||||
+41
-59
@@ -107,9 +107,8 @@ public final class DebugBoundsOverlayController {
|
||||
removeOverlays(parent);
|
||||
return;
|
||||
}
|
||||
ViewGroup overlayParent = overlayParent(root, parent, layoutEnabled, aodStockVisualizersEnabled, settings);
|
||||
removeOverlayFromOtherParent(parent, overlayParent);
|
||||
OverlayView host = ensureOverlay(overlayParent);
|
||||
removeOverlaysFromOwnedHosts(parent);
|
||||
OverlayView host = ensureOverlay(parent);
|
||||
if (host == null) {
|
||||
return;
|
||||
}
|
||||
@@ -122,7 +121,7 @@ public final class DebugBoundsOverlayController {
|
||||
host.layout(0, 0, width, height);
|
||||
}
|
||||
host.setSpecs(specs);
|
||||
if (overlayParent.getChildAt(overlayParent.getChildCount() - 1) != host) {
|
||||
if (parent.getChildAt(parent.getChildCount() - 1) != host) {
|
||||
host.bringToFront();
|
||||
}
|
||||
}
|
||||
@@ -134,18 +133,22 @@ public final class DebugBoundsOverlayController {
|
||||
boolean aodStockVisualizersEnabled,
|
||||
SceneKey scene
|
||||
) {
|
||||
if (!layoutEnabled || root == null || settings == null
|
||||
|| !aodStockVisualizersEnabled
|
||||
|| !settings.debugVisualizeAodStockContainers) {
|
||||
if (!layoutEnabled || root == null || settings == null) {
|
||||
return 0;
|
||||
}
|
||||
int result = 17;
|
||||
ViewGroup notificationContainer = aodNotificationContainer(root, scene);
|
||||
result = 31 * result + signature(
|
||||
aodNotificationBounds(root, scene));
|
||||
result = 31 * result + signature(liveAodStatusIconsBounds(root));
|
||||
result = 31 * result + signature(
|
||||
derivedAodStatusbarBounds(root, notificationContainer, settings, scene));
|
||||
if (aodStockVisualizersEnabled && settings.debugVisualizeAodStockContainers) {
|
||||
ViewGroup notificationContainer = aodNotificationContainer(root, scene);
|
||||
result = 31 * result + signature(
|
||||
aodNotificationBounds(root, scene));
|
||||
result = 31 * result + signature(liveAodStatusIconsBounds(root));
|
||||
result = 31 * result + signature(
|
||||
derivedAodStatusbarBounds(root, notificationContainer, settings, scene));
|
||||
}
|
||||
result = 31 * result + hostSignature(root, OwnedIconHostManager.TAG_UNLOCKED_NOTIFICATION_HOST);
|
||||
result = 31 * result + hostSignature(root, OwnedIconHostManager.TAG_UNLOCKED_STATUS_HOST);
|
||||
result = 31 * result + hostSignature(root, OwnedIconHostManager.TAG_UNLOCKED_CLOCK_HOST);
|
||||
result = 31 * result + hostSignature(root, OwnedIconHostManager.TAG_UNLOCKED_CHIP_HOST);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -255,6 +258,12 @@ public final class DebugBoundsOverlayController {
|
||||
}
|
||||
int right = bounds.left + bounds.width;
|
||||
int bottom = bounds.top + bounds.height;
|
||||
if (bounds.left == 0
|
||||
&& bounds.top == 0
|
||||
&& bounds.width >= root.getWidth()
|
||||
&& bounds.height >= root.getHeight()) {
|
||||
return false;
|
||||
}
|
||||
return bounds.left >= 0
|
||||
&& bounds.top >= 0
|
||||
&& right <= root.getWidth()
|
||||
@@ -410,49 +419,15 @@ public final class DebugBoundsOverlayController {
|
||||
return host;
|
||||
}
|
||||
|
||||
private ViewGroup overlayParent(
|
||||
View root,
|
||||
ViewGroup rootParent,
|
||||
boolean layoutEnabled,
|
||||
boolean aodStockVisualizersEnabled,
|
||||
SbtSettings settings
|
||||
) {
|
||||
if (layoutEnabled
|
||||
&& aodStockVisualizersEnabled
|
||||
&& settings != null
|
||||
&& settings.debugVisualizeAodStockContainers) {
|
||||
View chipHost = findDirectTaggedChild(rootParent, OwnedIconHostManager.TAG_UNLOCKED_CHIP_HOST);
|
||||
if (chipHost instanceof ViewGroup chipHostGroup) {
|
||||
return chipHostGroup;
|
||||
}
|
||||
View statusHost = findDirectTaggedChild(rootParent, OwnedIconHostManager.TAG_UNLOCKED_STATUS_HOST);
|
||||
if (statusHost instanceof ViewGroup statusHostGroup) {
|
||||
return statusHostGroup;
|
||||
}
|
||||
}
|
||||
return rootParent;
|
||||
}
|
||||
|
||||
private void removeOverlayFromOtherParent(ViewGroup rootParent, ViewGroup overlayParent) {
|
||||
private void removeOverlaysFromOwnedHosts(ViewGroup rootParent) {
|
||||
if (rootParent == null) {
|
||||
return;
|
||||
}
|
||||
removeOverlayIfParentDiffers(rootParent, overlayParent);
|
||||
removeOverlayIfParentDiffers(
|
||||
directTaggedViewGroup(rootParent, OwnedIconHostManager.TAG_UNLOCKED_STATUS_HOST),
|
||||
overlayParent);
|
||||
removeOverlayIfParentDiffers(
|
||||
directTaggedViewGroup(rootParent, OwnedIconHostManager.TAG_UNLOCKED_NOTIFICATION_HOST),
|
||||
overlayParent);
|
||||
removeOverlayIfParentDiffers(
|
||||
directTaggedViewGroup(rootParent, OwnedIconHostManager.TAG_UNLOCKED_CLOCK_HOST),
|
||||
overlayParent);
|
||||
removeOverlayIfParentDiffers(
|
||||
directTaggedViewGroup(rootParent, OwnedIconHostManager.TAG_UNLOCKED_CARRIER_HOST),
|
||||
overlayParent);
|
||||
removeOverlayIfParentDiffers(
|
||||
directTaggedViewGroup(rootParent, OwnedIconHostManager.TAG_UNLOCKED_CHIP_HOST),
|
||||
overlayParent);
|
||||
removeOverlay(directTaggedViewGroup(rootParent, OwnedIconHostManager.TAG_UNLOCKED_STATUS_HOST));
|
||||
removeOverlay(directTaggedViewGroup(rootParent, OwnedIconHostManager.TAG_UNLOCKED_NOTIFICATION_HOST));
|
||||
removeOverlay(directTaggedViewGroup(rootParent, OwnedIconHostManager.TAG_UNLOCKED_CLOCK_HOST));
|
||||
removeOverlay(directTaggedViewGroup(rootParent, OwnedIconHostManager.TAG_UNLOCKED_CARRIER_HOST));
|
||||
removeOverlay(directTaggedViewGroup(rootParent, OwnedIconHostManager.TAG_UNLOCKED_CHIP_HOST));
|
||||
}
|
||||
|
||||
private void removeOverlays(ViewGroup rootParent) {
|
||||
@@ -467,12 +442,6 @@ public final class DebugBoundsOverlayController {
|
||||
removeOverlay(directTaggedViewGroup(rootParent, OwnedIconHostManager.TAG_UNLOCKED_CHIP_HOST));
|
||||
}
|
||||
|
||||
private void removeOverlayIfParentDiffers(ViewGroup parent, ViewGroup expectedParent) {
|
||||
if (parent != null && parent != expectedParent) {
|
||||
removeOverlay(parent);
|
||||
}
|
||||
}
|
||||
|
||||
private void removeOverlay(ViewGroup parent) {
|
||||
if (parent == null) {
|
||||
return;
|
||||
@@ -511,6 +480,19 @@ public final class DebugBoundsOverlayController {
|
||||
return null;
|
||||
}
|
||||
|
||||
private int hostSignature(View root, String tag) {
|
||||
if (!(root instanceof ViewGroup parent)) {
|
||||
return 0;
|
||||
}
|
||||
View host = findDirectTaggedChild(parent, tag);
|
||||
Bounds bounds = boundsRelativeTo(root, host);
|
||||
int result = 17;
|
||||
result = 31 * result + signature(bounds);
|
||||
result = 31 * result + (host instanceof ViewGroup group ? group.getChildCount() : 0);
|
||||
result = 31 * result + taggedContainerBounds(host).hashCode();
|
||||
return result;
|
||||
}
|
||||
|
||||
private Bounds boundsRelativeTo(View root, View view) {
|
||||
if (root == null || view == null) {
|
||||
return null;
|
||||
|
||||
@@ -10,6 +10,7 @@ import android.graphics.PorterDuff;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.text.TextUtils;
|
||||
import android.os.SystemClock;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
@@ -946,7 +947,7 @@ final class SnapshotRenderer {
|
||||
int oldMeasuredWidth = view.getMeasuredWidth();
|
||||
int oldMeasuredHeight = view.getMeasuredHeight();
|
||||
ViewFrameState frameState = captureFrameState(view);
|
||||
IdentityHashMap<TextView, Integer> oldMaxWidths = clearTextMaxWidths(view);
|
||||
IdentityHashMap<TextView, TextSnapshotState> textSnapshotStates = prepareTextSnapshotState(view);
|
||||
try {
|
||||
int widthSpec = View.MeasureSpec.makeMeasureSpec(Math.max(1, width), View.MeasureSpec.EXACTLY);
|
||||
int heightSpec = View.MeasureSpec.makeMeasureSpec(Math.max(1, height), View.MeasureSpec.EXACTLY);
|
||||
@@ -955,7 +956,7 @@ final class SnapshotRenderer {
|
||||
clampDescendantsToParent(view);
|
||||
view.draw(canvas);
|
||||
} finally {
|
||||
restoreTextMaxWidths(oldMaxWidths);
|
||||
restoreTextSnapshotState(textSnapshotStates);
|
||||
restoreFrameState(frameState);
|
||||
if (oldMeasuredWidth > 0 && oldMeasuredHeight > 0) {
|
||||
view.measure(
|
||||
@@ -1052,32 +1053,53 @@ final class SnapshotRenderer {
|
||||
) {
|
||||
}
|
||||
|
||||
private IdentityHashMap<TextView, Integer> clearTextMaxWidths(View view) {
|
||||
IdentityHashMap<TextView, Integer> oldMaxWidths = new IdentityHashMap<>();
|
||||
collectTextMaxWidths(view, oldMaxWidths);
|
||||
for (Map.Entry<TextView, Integer> entry : oldMaxWidths.entrySet()) {
|
||||
entry.getKey().setMaxWidth(Integer.MAX_VALUE);
|
||||
private IdentityHashMap<TextView, TextSnapshotState> prepareTextSnapshotState(View view) {
|
||||
IdentityHashMap<TextView, TextSnapshotState> states = new IdentityHashMap<>();
|
||||
collectTextSnapshotState(view, states);
|
||||
for (Map.Entry<TextView, TextSnapshotState> entry : states.entrySet()) {
|
||||
TextView textView = entry.getKey();
|
||||
textView.setMaxWidth(Integer.MAX_VALUE);
|
||||
textView.setHorizontalFadingEdgeEnabled(false);
|
||||
textView.setSelected(false);
|
||||
textView.setEllipsize(null);
|
||||
}
|
||||
return oldMaxWidths;
|
||||
return states;
|
||||
}
|
||||
|
||||
private void collectTextMaxWidths(View view, IdentityHashMap<TextView, Integer> out) {
|
||||
private void collectTextSnapshotState(View view, IdentityHashMap<TextView, TextSnapshotState> out) {
|
||||
if (view instanceof TextView textView) {
|
||||
out.put(textView, textView.getMaxWidth());
|
||||
out.put(textView, new TextSnapshotState(
|
||||
textView.getMaxWidth(),
|
||||
textView.isHorizontalFadingEdgeEnabled(),
|
||||
textView.isSelected(),
|
||||
textView.getEllipsize()));
|
||||
}
|
||||
if (view instanceof ViewGroup group) {
|
||||
for (int i = 0; i < group.getChildCount(); i++) {
|
||||
collectTextMaxWidths(group.getChildAt(i), out);
|
||||
collectTextSnapshotState(group.getChildAt(i), out);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void restoreTextMaxWidths(IdentityHashMap<TextView, Integer> oldMaxWidths) {
|
||||
for (Map.Entry<TextView, Integer> entry : oldMaxWidths.entrySet()) {
|
||||
entry.getKey().setMaxWidth(entry.getValue());
|
||||
private void restoreTextSnapshotState(IdentityHashMap<TextView, TextSnapshotState> states) {
|
||||
for (Map.Entry<TextView, TextSnapshotState> entry : states.entrySet()) {
|
||||
TextView textView = entry.getKey();
|
||||
TextSnapshotState state = entry.getValue();
|
||||
textView.setMaxWidth(state.maxWidth);
|
||||
textView.setHorizontalFadingEdgeEnabled(state.horizontalFadingEdgeEnabled);
|
||||
textView.setSelected(state.selected);
|
||||
textView.setEllipsize(state.ellipsize);
|
||||
}
|
||||
}
|
||||
|
||||
private record TextSnapshotState(
|
||||
int maxWidth,
|
||||
boolean horizontalFadingEdgeEnabled,
|
||||
boolean selected,
|
||||
TextUtils.TruncateAt ellipsize
|
||||
) {
|
||||
}
|
||||
|
||||
private void drawAppIcon(Context context, SnapshotSource source, Bitmap bitmap) {
|
||||
bitmap.eraseColor(Color.TRANSPARENT);
|
||||
if (context == null || source == null || source.keyHint() == null) {
|
||||
|
||||
Reference in New Issue
Block a user