Refine runtime layout transitions
This commit is contained in:
+24
@@ -57,6 +57,7 @@ final class BatteryBarController {
|
||||
private final Set<View> pendingOverlayRetries = Collections.newSetFromMap(new WeakHashMap<>());
|
||||
private final Map<View, String> lastSignatures = new WeakHashMap<>();
|
||||
private final Map<View, String> lastOverlaySignatures = new WeakHashMap<>();
|
||||
private final Map<View, Integer> lastRootTransformSignatures = new WeakHashMap<>();
|
||||
private int systemBarAppearance;
|
||||
private int systemBarBehavior;
|
||||
private int systemBarRequestedVisibleTypes = WindowInsets.Type.statusBars();
|
||||
@@ -171,6 +172,11 @@ final class BatteryBarController {
|
||||
}
|
||||
|
||||
private void applyBatteryBarAfterRootTransform(View root) {
|
||||
int transformSignature = rootTransformSignature(root);
|
||||
Integer previousSignature = lastRootTransformSignatures.put(root, transformSignature);
|
||||
if (previousSignature != null && previousSignature == transformSignature) {
|
||||
return;
|
||||
}
|
||||
if (isHiddenKeyguardRoot(root)) {
|
||||
removeBatteryBarView(root);
|
||||
return;
|
||||
@@ -255,9 +261,23 @@ final class BatteryBarController {
|
||||
}
|
||||
roots.remove(root);
|
||||
pendingOverlayRetries.remove(root);
|
||||
lastRootTransformSignatures.remove(root);
|
||||
removeBatteryBarView(root);
|
||||
}
|
||||
|
||||
private int rootTransformSignature(View root) {
|
||||
if (root == null) {
|
||||
return 0;
|
||||
}
|
||||
int result = 17;
|
||||
result = 31 * result + root.getVisibility();
|
||||
result = 31 * result + Float.floatToIntBits(root.getY());
|
||||
result = 31 * result + Float.floatToIntBits(root.getTranslationY());
|
||||
result = 31 * result + root.getWidth();
|
||||
result = 31 * result + root.getHeight();
|
||||
return result;
|
||||
}
|
||||
|
||||
private void registerReceiverIfNeeded(Context context) {
|
||||
if (context == null || receiverRegistered) {
|
||||
return;
|
||||
@@ -340,6 +360,10 @@ final class BatteryBarController {
|
||||
}
|
||||
|
||||
private void applyBatteryBar(View root) {
|
||||
applyBatteryBarInternal(root);
|
||||
}
|
||||
|
||||
private void applyBatteryBarInternal(View root) {
|
||||
if (!(root instanceof ViewGroup rootGroup)) {
|
||||
removeBatteryBarView(root);
|
||||
return;
|
||||
|
||||
+79
-3
@@ -24,6 +24,8 @@ import se.ajpanton.statusbartweak.runtime.ViewIdNames;
|
||||
import se.ajpanton.statusbartweak.runtime.features.RuntimeContext;
|
||||
import se.ajpanton.statusbartweak.runtime.hooks.ReflectionSupport;
|
||||
import se.ajpanton.statusbartweak.runtime.hooks.XposedHookSupport;
|
||||
import se.ajpanton.statusbartweak.runtime.mode.SceneKey;
|
||||
import se.ajpanton.statusbartweak.runtime.mode.SurfaceMode;
|
||||
import se.ajpanton.statusbartweak.runtime.settings.BroadcastReceiverSupport;
|
||||
import se.ajpanton.statusbartweak.runtime.settings.RuntimeSettingsCache;
|
||||
import se.ajpanton.statusbartweak.shell.settings.SbtSettings;
|
||||
@@ -83,6 +85,11 @@ final class DrawerClockTextController {
|
||||
|
||||
private void scanAndApply(View root) {
|
||||
SbtSettings settings = RuntimeSettingsCache.get(root.getContext());
|
||||
SceneKey scene = runtimeContext.getModeStateRepository().getActiveScene();
|
||||
if (scene != null && scene.isAod()) {
|
||||
restoreTrackedDescendants(root);
|
||||
return;
|
||||
}
|
||||
boolean clockEnabled = isEnabled(settings, Role.CLOCK);
|
||||
boolean dateEnabled = isEnabled(settings, Role.DATE);
|
||||
if (!clockEnabled && !dateEnabled) {
|
||||
@@ -95,10 +102,16 @@ final class DrawerClockTextController {
|
||||
registerReceiverIfNeeded(root.getContext());
|
||||
untrackDisabledRoles(clockEnabled, dateEnabled);
|
||||
|
||||
CandidateSelection candidates = cachedCandidates(root, clockEnabled, dateEnabled);
|
||||
SurfaceMode surfaceMode = scene != null ? scene.surfaceMode() : null;
|
||||
if (hasValidTrackedCandidates(root, clockEnabled, dateEnabled, surfaceMode)) {
|
||||
return;
|
||||
}
|
||||
|
||||
CandidateSelection candidates = cachedCandidates(root, clockEnabled, dateEnabled, surfaceMode);
|
||||
if (candidates == null) {
|
||||
candidates = findCandidates(root);
|
||||
candidateCacheByRoot.put(root, new CandidateCache(
|
||||
surfaceMode,
|
||||
candidates.clock != null ? candidates.clock.view : null,
|
||||
candidates.date != null ? candidates.date.view : null));
|
||||
}
|
||||
@@ -126,6 +139,18 @@ final class DrawerClockTextController {
|
||||
}
|
||||
}
|
||||
|
||||
private int restoreTrackedDescendants(View root) {
|
||||
int restored = 0;
|
||||
for (TextView textView : new ArrayList<>(trackedRoles.keySet())) {
|
||||
if (textView == null || root == null || isDescendantOf(textView, root)) {
|
||||
restore(textView);
|
||||
untrack(textView);
|
||||
restored++;
|
||||
}
|
||||
}
|
||||
return restored;
|
||||
}
|
||||
|
||||
private void untrackDisabledRoles(boolean clockEnabled, boolean dateEnabled) {
|
||||
for (TextView textView : new ArrayList<>(trackedRoles.keySet())) {
|
||||
Role role = trackedRoles.get(textView);
|
||||
@@ -136,6 +161,44 @@ final class DrawerClockTextController {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean hasValidTrackedCandidates(
|
||||
View root,
|
||||
boolean clockEnabled,
|
||||
boolean dateEnabled,
|
||||
SurfaceMode surfaceMode
|
||||
) {
|
||||
if (clockEnabled && !hasValidTrackedRole(root, Role.CLOCK, surfaceMode)) {
|
||||
return false;
|
||||
}
|
||||
return !dateEnabled || hasValidTrackedRole(root, Role.DATE, surfaceMode);
|
||||
}
|
||||
|
||||
private boolean hasValidTrackedRole(View root, Role role, SurfaceMode surfaceMode) {
|
||||
CandidateCache cache = candidateCacheByRoot.get(root);
|
||||
if (cache == null || cache.surfaceMode != surfaceMode) {
|
||||
return false;
|
||||
}
|
||||
WeakReference<TextView> expectedReference = role == Role.CLOCK
|
||||
? cache.clockView
|
||||
: cache.dateView;
|
||||
TextView expectedView = expectedReference != null ? expectedReference.get() : null;
|
||||
if (expectedView == null) {
|
||||
return false;
|
||||
}
|
||||
for (Map.Entry<TextView, Role> entry : trackedRoles.entrySet()) {
|
||||
TextView textView = entry.getKey();
|
||||
if (entry.getValue() == role
|
||||
&& textView == expectedView
|
||||
&& textView.isAttachedToWindow()
|
||||
&& isDescendantOf(textView, root)
|
||||
&& !isStatusbarClock(textView)
|
||||
&& ownedTexts.contains(textView)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void track(TextView textView, Role role) {
|
||||
if (textView == null || role == null) {
|
||||
return;
|
||||
@@ -159,6 +222,12 @@ final class DrawerClockTextController {
|
||||
if (role == null) {
|
||||
return;
|
||||
}
|
||||
SceneKey scene = runtimeContext.getModeStateRepository().getActiveScene();
|
||||
if (scene != null && scene.isAod()) {
|
||||
restore(textView);
|
||||
untrack(textView);
|
||||
return;
|
||||
}
|
||||
if (stockTextJustChanged) {
|
||||
captureSnapshot(textView);
|
||||
}
|
||||
@@ -416,12 +485,17 @@ final class DrawerClockTextController {
|
||||
private CandidateSelection cachedCandidates(
|
||||
View root,
|
||||
boolean clockEnabled,
|
||||
boolean dateEnabled
|
||||
boolean dateEnabled,
|
||||
SurfaceMode surfaceMode
|
||||
) {
|
||||
CandidateCache cache = candidateCacheByRoot.get(root);
|
||||
if (cache == null) {
|
||||
return null;
|
||||
}
|
||||
if (cache.surfaceMode != surfaceMode) {
|
||||
candidateCacheByRoot.remove(root);
|
||||
return null;
|
||||
}
|
||||
Candidate clock = candidateFromCache(root, cache.clockView, Role.CLOCK, clockEnabled);
|
||||
Candidate date = candidateFromCache(root, cache.dateView, Role.DATE, dateEnabled);
|
||||
if (clockEnabled && clock == null || dateEnabled && date == null) {
|
||||
@@ -554,10 +628,12 @@ final class DrawerClockTextController {
|
||||
}
|
||||
|
||||
private static final class CandidateCache {
|
||||
final SurfaceMode surfaceMode;
|
||||
final WeakReference<TextView> clockView;
|
||||
final WeakReference<TextView> dateView;
|
||||
|
||||
CandidateCache(TextView clockView, TextView dateView) {
|
||||
CandidateCache(SurfaceMode surfaceMode, TextView clockView, TextView dateView) {
|
||||
this.surfaceMode = surfaceMode;
|
||||
this.clockView = new WeakReference<>(clockView);
|
||||
this.dateView = new WeakReference<>(dateView);
|
||||
}
|
||||
|
||||
+19
-7
@@ -153,7 +153,7 @@ final class StockClockController {
|
||||
}
|
||||
runtimeContext.getModeStateRepository().addLayoutEnabledListener(enabled -> {
|
||||
if (enabled) {
|
||||
removeAllRowOverlays();
|
||||
restoreAllOwnedClocks();
|
||||
} else {
|
||||
refreshAllClocks();
|
||||
}
|
||||
@@ -218,14 +218,18 @@ final class StockClockController {
|
||||
}
|
||||
}
|
||||
|
||||
private void restoreAllOwnedClocks() {
|
||||
for (TextView clockView : new ArrayList<>(trackedClocks)) {
|
||||
restoreOwnedClock(clockView);
|
||||
}
|
||||
removeAllRowOverlays();
|
||||
}
|
||||
|
||||
private void applyClockText(TextView clockView) {
|
||||
SbtSettings settings = RuntimeSettingsCache.get(clockView.getContext());
|
||||
if (!hasCustomClockTextEnabled(settings)) {
|
||||
stopTicker(clockView);
|
||||
if (ownedClocks.contains(clockView)) {
|
||||
restoreStockText(clockView);
|
||||
ownedClocks.remove(clockView);
|
||||
}
|
||||
boolean layoutEnabled = settings.clockEnabled;
|
||||
if (layoutEnabled || !hasCustomClockTextEnabled(settings)) {
|
||||
restoreOwnedClock(clockView);
|
||||
return;
|
||||
}
|
||||
captureCurrentStockSnapshot(clockView);
|
||||
@@ -255,6 +259,14 @@ final class StockClockController {
|
||||
}
|
||||
}
|
||||
|
||||
private void restoreOwnedClock(TextView clockView) {
|
||||
stopTicker(clockView);
|
||||
if (ownedClocks.contains(clockView)) {
|
||||
restoreStockText(clockView);
|
||||
ownedClocks.remove(clockView);
|
||||
}
|
||||
}
|
||||
|
||||
private ArrayList<ClockTextRenderer.LayoutRowResult> layoutRowsFromModel(
|
||||
ClockLayoutTextFactory.Model model
|
||||
) {
|
||||
|
||||
+22
@@ -53,6 +53,28 @@ final class LockscreenCardsNotificationRowFilter {
|
||||
return changed;
|
||||
}
|
||||
|
||||
boolean applyRow(View row, boolean allowAfterKeyguardUnlock) {
|
||||
if (!isNotificationRow(row)) {
|
||||
return false;
|
||||
}
|
||||
Context context = row.getContext();
|
||||
boolean active = isActive(context, allowAfterKeyguardUnlock);
|
||||
boolean changed;
|
||||
if (active && shouldHideRow(context, row, allowAfterKeyguardUnlock)) {
|
||||
changed = hideRow(row);
|
||||
} else {
|
||||
changed = restoreRow(row);
|
||||
}
|
||||
if (changed) {
|
||||
requestLayout(row);
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
void restoreRemovedRow(View row) {
|
||||
restoreRow(row);
|
||||
}
|
||||
|
||||
void restoreAll() {
|
||||
if (hiddenRows.isEmpty()) {
|
||||
return;
|
||||
|
||||
+224
-28
@@ -138,12 +138,15 @@ final class StockLayoutCanvasController {
|
||||
Collections.newSetFromMap(new WeakHashMap<>());
|
||||
private final Set<View> pendingUnlockedAppearanceRefreshRoots =
|
||||
Collections.newSetFromMap(new WeakHashMap<>());
|
||||
private final Set<View> pendingUnlockedClockTextRefreshRoots =
|
||||
Collections.newSetFromMap(new WeakHashMap<>());
|
||||
private final Set<View> pendingDrawerAppearanceRefreshRoots =
|
||||
Collections.newSetFromMap(new WeakHashMap<>());
|
||||
private final Set<View> dirtyUnlockedLayoutRoots =
|
||||
Collections.newSetFromMap(new WeakHashMap<>());
|
||||
private final Set<View> pendingDrawerStatusChipRefreshRoots =
|
||||
Collections.newSetFromMap(new WeakHashMap<>());
|
||||
private final Map<View, Runnable> unlockedClockTickersByRoot = new WeakHashMap<>();
|
||||
private final Set<ClassLoader> hookedPluginClassLoaders =
|
||||
Collections.newSetFromMap(new IdentityHashMap<>());
|
||||
private final Set<ClassLoader> pendingPluginClassLoaders =
|
||||
@@ -479,8 +482,9 @@ final class StockLayoutCanvasController {
|
||||
"onViewAdded",
|
||||
chain -> {
|
||||
Object result = chain.proceed();
|
||||
if (chain.getThisObject() instanceof ViewGroup stack) {
|
||||
applyLockscreenCardsNotificationRowFilter(stack, false);
|
||||
List<Object> args = chain.getArgs();
|
||||
if (!args.isEmpty() && args.get(0) instanceof View row) {
|
||||
applyLockscreenCardsNotificationRowFilterRow(row, false);
|
||||
}
|
||||
return result;
|
||||
});
|
||||
@@ -490,8 +494,9 @@ final class StockLayoutCanvasController {
|
||||
"onViewRemoved",
|
||||
chain -> {
|
||||
Object result = chain.proceed();
|
||||
if (chain.getThisObject() instanceof ViewGroup stack) {
|
||||
applyLockscreenCardsNotificationRowFilter(stack, false);
|
||||
List<Object> args = chain.getArgs();
|
||||
if (!args.isEmpty() && args.get(0) instanceof View row) {
|
||||
lockscreenCardsNotificationRowFilter.restoreRemovedRow(row);
|
||||
}
|
||||
return result;
|
||||
});
|
||||
@@ -1780,6 +1785,7 @@ final class StockLayoutCanvasController {
|
||||
return;
|
||||
}
|
||||
SceneKey activeScene = runtimeContext.getModeStateRepository().getActiveScene();
|
||||
ensureUnlockedClockTickerState(root, settings, activeScene);
|
||||
if (!clockTextRefreshEnabledForScene(settings, activeScene)) {
|
||||
return;
|
||||
}
|
||||
@@ -1804,6 +1810,80 @@ final class StockLayoutCanvasController {
|
||||
return System.currentTimeMillis() / divisor;
|
||||
}
|
||||
|
||||
private void ensureUnlockedClockTickerState(View root, SbtSettings settings, SceneKey scene) {
|
||||
if (!clockNeedsSecondTicker(root, settings, scene)) {
|
||||
stopUnlockedClockTicker(root);
|
||||
return;
|
||||
}
|
||||
Runnable existing = unlockedClockTickersByRoot.get(root);
|
||||
if (existing != null) {
|
||||
return;
|
||||
}
|
||||
Runnable ticker = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (!clockNeedsSecondTicker(root, RuntimeSettingsCache.get(root.getContext()),
|
||||
runtimeContext.getModeStateRepository().getActiveScene())) {
|
||||
stopUnlockedClockTicker(root);
|
||||
return;
|
||||
}
|
||||
scheduleUnlockedClockTextRefreshForRoot(root);
|
||||
scheduleNextUnlockedClockTick(root, this);
|
||||
}
|
||||
};
|
||||
unlockedClockTickersByRoot.put(root, ticker);
|
||||
scheduleNextUnlockedClockTick(root, ticker);
|
||||
}
|
||||
|
||||
private boolean clockNeedsSecondTicker(View root, SbtSettings settings, SceneKey scene) {
|
||||
if (root == null
|
||||
|| !root.isAttachedToWindow()
|
||||
|| !isUnlockedStatusBarRoot(root)
|
||||
|| settings == null
|
||||
|| !settings.clockEnabled
|
||||
|| !clockTextRefreshEnabledForScene(settings, scene)) {
|
||||
return false;
|
||||
}
|
||||
return clockUsesSeconds(settings);
|
||||
}
|
||||
|
||||
private boolean clockUsesSeconds(SbtSettings settings) {
|
||||
if (settings == null) {
|
||||
return false;
|
||||
}
|
||||
String pattern = settings.clockCustomFormat != null ? settings.clockCustomFormat : "";
|
||||
return settings.clockShowSeconds
|
||||
|| (settings.clockCustomFormatEnabled && pattern.contains("s"));
|
||||
}
|
||||
|
||||
private void scheduleNextUnlockedClockTick(View root, Runnable ticker) {
|
||||
if (root == null || ticker == null) {
|
||||
return;
|
||||
}
|
||||
long now = System.currentTimeMillis();
|
||||
long next = now - (now % 1000L) + 1000L;
|
||||
root.postDelayed(ticker, Math.max(1L, next - now));
|
||||
}
|
||||
|
||||
private void stopUnlockedClockTicker(View root) {
|
||||
if (root == null) {
|
||||
return;
|
||||
}
|
||||
Runnable ticker = unlockedClockTickersByRoot.remove(root);
|
||||
if (ticker != null) {
|
||||
root.removeCallbacks(ticker);
|
||||
}
|
||||
}
|
||||
|
||||
private void clearUnlockedClockRefreshState(View root) {
|
||||
if (root == null) {
|
||||
return;
|
||||
}
|
||||
stopUnlockedClockTicker(root);
|
||||
pendingUnlockedClockTextRefreshRoots.remove(root);
|
||||
clockTimeBucketByRoot.remove(root);
|
||||
}
|
||||
|
||||
private void scheduleUnlockedAppearanceRefreshForAllRoots() {
|
||||
scheduleUnlockedAppearanceRefreshForAllRoots(false);
|
||||
}
|
||||
@@ -1830,8 +1910,15 @@ final class StockLayoutCanvasController {
|
||||
if (previous == null || current == null || previous.equals(current)) {
|
||||
return;
|
||||
}
|
||||
if (previous.isLockscreen() && !current.isLockscreen()) {
|
||||
if (current.isUnlocked() && !previous.isUnlocked()) {
|
||||
darkIconDispatcherGuard.restoreForcedStates();
|
||||
trackedLockedStatusBarIconSurfaces.clear();
|
||||
} else if (previous.isLockscreen() && current.isAod()) {
|
||||
darkIconDispatcherGuard.restoreForcedStates();
|
||||
hideTrackedLockedStatusBarIconSurfaces(null);
|
||||
} else if (previous.isLockscreen() && !current.isLockscreen()) {
|
||||
darkIconDispatcherGuard.restoreForcedStates();
|
||||
restoreTrackedLockedStatusBarIconSurfaces(null);
|
||||
}
|
||||
boolean lockscreenEntry = current.isLockscreen();
|
||||
if (lockscreenEntry) {
|
||||
@@ -1847,6 +1934,7 @@ final class StockLayoutCanvasController {
|
||||
if (root == null || !root.isAttachedToWindow()) {
|
||||
rootGeometries.remove(root);
|
||||
unlockedHostsByRoot.remove(root);
|
||||
clearUnlockedClockRefreshState(root);
|
||||
continue;
|
||||
}
|
||||
Runnable refresh = () -> refreshSceneRoot(root);
|
||||
@@ -1866,6 +1954,7 @@ final class StockLayoutCanvasController {
|
||||
if (root == null || !root.isAttachedToWindow()) {
|
||||
rootGeometries.remove(root);
|
||||
unlockedHostsByRoot.remove(root);
|
||||
clearUnlockedClockRefreshState(root);
|
||||
return;
|
||||
}
|
||||
unlockedIconRenderController.clearRoot(root);
|
||||
@@ -1926,11 +2015,11 @@ final class StockLayoutCanvasController {
|
||||
if (root == null
|
||||
|| !root.isAttachedToWindow()
|
||||
|| !isUnlockedStatusBarRoot(root)
|
||||
|| !pendingUnlockedAppearanceRefreshRoots.add(root)) {
|
||||
|| !pendingUnlockedClockTextRefreshRoots.add(root)) {
|
||||
return;
|
||||
}
|
||||
root.post(() -> {
|
||||
pendingUnlockedAppearanceRefreshRoots.remove(root);
|
||||
pendingUnlockedClockTextRefreshRoots.remove(root);
|
||||
refreshUnlockedClockTextNow(root);
|
||||
});
|
||||
}
|
||||
@@ -2077,11 +2166,19 @@ final class StockLayoutCanvasController {
|
||||
}
|
||||
if (!layoutRoot) {
|
||||
if (activeScene != null
|
||||
&& activeScene.isUnlocked()
|
||||
&& isNotificationShadeWindowRoot(root)) {
|
||||
hideUnlockedShadeShelfIconSurfaces(root);
|
||||
removeSharedLayoutHosts(root);
|
||||
} else if (activeScene != null
|
||||
&& activeScene.isLockscreen()
|
||||
&& canContainLockedStatusBarIconSurfaces(root)) {
|
||||
removeUnlockedLayoutHosts(root);
|
||||
removeAodCardsNotificationHost(root);
|
||||
renderLockscreenCardsNotificationStripIfNeeded(root, settings, activeScene);
|
||||
if (activeScene.notificationDisplayStyle() != NotificationDisplayStyle.CARDS
|
||||
&& hasLockscreenCardsNotificationHost(root)) {
|
||||
removeLockscreenCardsNotificationHost(root);
|
||||
}
|
||||
hideOrDiscoverLockedStatusBarIconSurfaces(root);
|
||||
} else {
|
||||
removeSharedLayoutHosts(root);
|
||||
@@ -2100,9 +2197,6 @@ final class StockLayoutCanvasController {
|
||||
&& (unlockedScene
|
||||
|| activeScene != null && activeScene.isLockscreen()
|
||||
|| aodScene)) {
|
||||
if (!unlockedScene) {
|
||||
restoreTrackedLockedStatusBarIconSurfaces(root);
|
||||
}
|
||||
boolean shouldRender = !unlockedIconRenderController.hasLayoutPlan(root)
|
||||
|| rootDirty;
|
||||
if (shouldRender && shouldDeferUnlockedRenderForDrawer(root)) {
|
||||
@@ -2225,6 +2319,13 @@ final class StockLayoutCanvasController {
|
||||
|| findDirectOwnedHost(group, OwnedIconHostManager.TAG_AOD_CARDS_NOTIFICATION_HOST) != null;
|
||||
}
|
||||
|
||||
private boolean hasLockscreenCardsNotificationHost(View root) {
|
||||
return root instanceof ViewGroup group
|
||||
&& findDirectOwnedHost(
|
||||
group,
|
||||
OwnedIconHostManager.TAG_LOCKSCREEN_CARDS_NOTIFICATION_HOST) != null;
|
||||
}
|
||||
|
||||
private void applyDebugOverlay(
|
||||
View root,
|
||||
boolean layoutEnabled,
|
||||
@@ -2346,6 +2447,51 @@ final class StockLayoutCanvasController {
|
||||
});
|
||||
}
|
||||
|
||||
private void hideUnlockedShadeShelfIconSurfaces(View root) {
|
||||
if (root == null) {
|
||||
return;
|
||||
}
|
||||
boolean foundTracked = hideTrackedUnlockedShadeShelfIconSurfaces(root);
|
||||
if (foundTracked) {
|
||||
return;
|
||||
}
|
||||
walkTree(root, view -> {
|
||||
if (isUnlockedShadeShelfIconSurface(view)) {
|
||||
trackedUnlockedStockSurfaces.add(view);
|
||||
hideView(view, false);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private boolean hideTrackedUnlockedShadeShelfIconSurfaces(View root) {
|
||||
if (trackedUnlockedStockSurfaces.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
boolean foundIconSurfaceInRoot = false;
|
||||
ArrayDeque<View> staleViews = new ArrayDeque<>();
|
||||
for (View view : trackedUnlockedStockSurfaces) {
|
||||
if (view == null || !view.isAttachedToWindow()) {
|
||||
staleViews.add(view);
|
||||
continue;
|
||||
}
|
||||
if (!isDescendantOf(view, root)) {
|
||||
continue;
|
||||
}
|
||||
if (!isUnlockedShadeShelfIconSurface(view)) {
|
||||
continue;
|
||||
}
|
||||
foundIconSurfaceInRoot |= isCardsNotificationIconSurface(view);
|
||||
hideView(view, false);
|
||||
}
|
||||
removeStaleViews(trackedUnlockedStockSurfaces, staleViews);
|
||||
return foundIconSurfaceInRoot;
|
||||
}
|
||||
|
||||
private boolean isUnlockedShadeShelfIconSurface(View view) {
|
||||
return isCardsNotificationIconSurface(view)
|
||||
|| isCardsNotificationShelfBackgroundSurface(view);
|
||||
}
|
||||
|
||||
private boolean hasTrackedUnlockedStockSurfaces(View root) {
|
||||
if (trackedUnlockedStockSurfaces.isEmpty()) {
|
||||
return false;
|
||||
@@ -2748,14 +2894,17 @@ final class StockLayoutCanvasController {
|
||||
return false;
|
||||
}
|
||||
|
||||
private void trackAndHideLockedStatusBarIconSurfaces(View root) {
|
||||
private int trackAndHideLockedStatusBarIconSurfaces(View root) {
|
||||
final int[] found = {0};
|
||||
walkTree(root, view -> {
|
||||
if (isLockedStatusBarIconSurface(view)) {
|
||||
rememberLockedCarrierTextSource(view);
|
||||
trackedLockedStatusBarIconSurfaces.add(view);
|
||||
hideView(view, isCarrierView(view));
|
||||
found[0]++;
|
||||
}
|
||||
});
|
||||
return found[0];
|
||||
}
|
||||
|
||||
private void hideOrDiscoverLockedStatusBarIconSurfaces(View root) {
|
||||
@@ -2776,13 +2925,18 @@ final class StockLayoutCanvasController {
|
||||
staleViews.add(view);
|
||||
continue;
|
||||
}
|
||||
if (root == null || isDescendantOf(view, root)) {
|
||||
foundInRoot = true;
|
||||
if (isAlreadySuppressedHiddenView(view)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (!isLockedStatusBarIconSurface(view)) {
|
||||
restoreView(view);
|
||||
staleViews.add(view);
|
||||
continue;
|
||||
}
|
||||
if (root == null || isDescendantOf(view, root)) {
|
||||
foundInRoot = true;
|
||||
hideView(view, isCarrierView(view));
|
||||
}
|
||||
}
|
||||
@@ -2790,6 +2944,13 @@ final class StockLayoutCanvasController {
|
||||
return foundInRoot;
|
||||
}
|
||||
|
||||
private boolean isAlreadySuppressedHiddenView(View view) {
|
||||
return view != null
|
||||
&& hiddenViewStates.containsKey(view)
|
||||
&& view.getAlpha() == 0f
|
||||
&& (view.getVisibility() == View.GONE || view.getVisibility() == View.VISIBLE);
|
||||
}
|
||||
|
||||
private boolean shouldSuppressConflictingShadeHeaderAlpha(View view, float alpha) {
|
||||
return view != null
|
||||
&& alpha != view.getAlpha()
|
||||
@@ -2928,11 +3089,18 @@ final class StockLayoutCanvasController {
|
||||
if (trackedLockedStatusBarIconSurfaces.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
ArrayDeque<View> restoredViews = new ArrayDeque<>();
|
||||
for (View view : trackedLockedStatusBarIconSurfaces) {
|
||||
if (view != null && view.isAttachedToWindow() && (root == null || isDescendantOf(view, root))) {
|
||||
if (view == null || !view.isAttachedToWindow()) {
|
||||
restoredViews.add(view);
|
||||
continue;
|
||||
}
|
||||
if (root == null || isDescendantOf(view, root)) {
|
||||
restoreView(view);
|
||||
restoredViews.add(view);
|
||||
}
|
||||
}
|
||||
removeStaleViews(trackedLockedStatusBarIconSurfaces, restoredViews);
|
||||
}
|
||||
|
||||
private boolean hasTrackedStatusChipSources(View root) {
|
||||
@@ -3297,7 +3465,7 @@ final class StockLayoutCanvasController {
|
||||
aodBeforeDrawSignatureByRoot.remove(root);
|
||||
lockscreenCardsRowFilterSignatures.remove(root);
|
||||
lockscreenCardsNotificationRenderGenerationByRoot.remove(root);
|
||||
clockTimeBucketByRoot.remove(root);
|
||||
clearUnlockedClockRefreshState(root);
|
||||
removeDebugOverlay(root);
|
||||
root.requestLayout();
|
||||
root.invalidate();
|
||||
@@ -4046,7 +4214,7 @@ final class StockLayoutCanvasController {
|
||||
dirtyUnlockedLayoutRoots.remove(root);
|
||||
settingsIdentityByRoot.remove(root);
|
||||
lockscreenCardsRowFilterSignatures.remove(root);
|
||||
clockTimeBucketByRoot.remove(root);
|
||||
clearUnlockedClockRefreshState(root);
|
||||
if (!isUnlockedStatusBarRoot(root) || !layoutOffCleanedRoots.add(root)) {
|
||||
unlockedHostsByRoot.remove(root);
|
||||
rootGeometries.remove(root);
|
||||
@@ -4117,7 +4285,7 @@ final class StockLayoutCanvasController {
|
||||
pendingUnlockedAppearanceRefreshRoots.remove(root);
|
||||
dirtyUnlockedLayoutRoots.remove(root);
|
||||
settingsIdentityByRoot.remove(root);
|
||||
clockTimeBucketByRoot.remove(root);
|
||||
clearUnlockedClockRefreshState(root);
|
||||
}
|
||||
|
||||
private void removeUnlockedLayoutHosts(View root) {
|
||||
@@ -4130,7 +4298,7 @@ final class StockLayoutCanvasController {
|
||||
pendingUnlockedAppearanceRefreshRoots.remove(root);
|
||||
dirtyUnlockedLayoutRoots.remove(root);
|
||||
settingsIdentityByRoot.remove(root);
|
||||
clockTimeBucketByRoot.remove(root);
|
||||
clearUnlockedClockRefreshState(root);
|
||||
}
|
||||
|
||||
private boolean isDescendantOfNotificationShadeWindow(View view) {
|
||||
@@ -4185,16 +4353,23 @@ final class StockLayoutCanvasController {
|
||||
SbtSettings settings,
|
||||
SceneKey activeScene
|
||||
) {
|
||||
View visibleBouncerSurface = findVisibleBouncerSurface(root);
|
||||
boolean suppressForTransition = runtimeContext.getModeStateRepository().isSystemUiShadeLocked()
|
||||
|| visibleBouncerSurface != null;
|
||||
if (root == null
|
||||
|| settings == null
|
||||
|| activeScene == null
|
||||
|| !activeScene.isLockscreen()
|
||||
|| activeScene.notificationDisplayStyle() != NotificationDisplayStyle.CARDS
|
||||
|| !isNotificationShadeWindowRoot(root)
|
||||
|| suppressForTransition) {
|
||||
|| !isNotificationShadeWindowRoot(root)) {
|
||||
removeLockscreenCardsNotificationHost(root);
|
||||
lockscreenCardsNotificationRenderGenerationByRoot.remove(root);
|
||||
return;
|
||||
}
|
||||
if (runtimeContext.getModeStateRepository().isSystemUiShadeLocked()) {
|
||||
removeLockscreenCardsNotificationHost(root);
|
||||
lockscreenCardsNotificationRenderGenerationByRoot.remove(root);
|
||||
return;
|
||||
}
|
||||
View visibleBouncerSurface = findVisibleBouncerSurface(root);
|
||||
if (visibleBouncerSurface != null) {
|
||||
removeLockscreenCardsNotificationHost(root);
|
||||
lockscreenCardsNotificationRenderGenerationByRoot.remove(root);
|
||||
return;
|
||||
@@ -4210,7 +4385,7 @@ final class StockLayoutCanvasController {
|
||||
int rootHeight = root.getHeight();
|
||||
int activeKeyGeneration = NotificationActiveKeyStore.generation();
|
||||
int sourceSignature =
|
||||
LockscreenCardsNotificationIconSourceStore.snapshotSourceSignatureForRoot(root);
|
||||
LockscreenCardsNotificationIconSourceStore.lightweightSourceSignatureForRoot(root);
|
||||
int generation = settingsId;
|
||||
generation = 31 * generation + rootWidth;
|
||||
generation = 31 * generation + rootHeight;
|
||||
@@ -4224,7 +4399,7 @@ final class StockLayoutCanvasController {
|
||||
lockscreenCardsNotificationRenderGenerationByRoot.put(root, generation);
|
||||
lockscreenCardsNotificationStripRenderer.render(root, hostGroup, settings, activeScene);
|
||||
}
|
||||
host.bringToFront();
|
||||
bringToFrontIfNeeded(host);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4271,10 +4446,21 @@ final class StockLayoutCanvasController {
|
||||
lockscreenCardsNotificationStripRenderer.render(root, hostGroup, settings, activeScene);
|
||||
}
|
||||
setHostAlpha(host, aodVisualAlphaForRoot(root));
|
||||
host.bringToFront();
|
||||
bringToFrontIfNeeded(host);
|
||||
}
|
||||
}
|
||||
|
||||
private void bringToFrontIfNeeded(View view) {
|
||||
if (view == null || !(view.getParent() instanceof ViewGroup group)) {
|
||||
return;
|
||||
}
|
||||
int childCount = group.getChildCount();
|
||||
if (childCount <= 0 || group.getChildAt(childCount - 1) == view) {
|
||||
return;
|
||||
}
|
||||
view.bringToFront();
|
||||
}
|
||||
|
||||
private void applyLockscreenCardsNotificationRowFilter(ViewGroup stack, boolean allowAfterKeyguardUnlock) {
|
||||
if (stack == null) {
|
||||
return;
|
||||
@@ -4286,6 +4472,17 @@ final class StockLayoutCanvasController {
|
||||
lockscreenCardsNotificationRowFilter.apply(stack, allowAfterKeyguardUnlock);
|
||||
}
|
||||
|
||||
private void applyLockscreenCardsNotificationRowFilterRow(View row, boolean allowAfterKeyguardUnlock) {
|
||||
if (row == null) {
|
||||
return;
|
||||
}
|
||||
if (runtimeContext.getModeStateRepository().isSystemUiShadeLocked()) {
|
||||
lockscreenCardsNotificationRowFilter.restoreRemovedRow(row);
|
||||
return;
|
||||
}
|
||||
lockscreenCardsNotificationRowFilter.applyRow(row, allowAfterKeyguardUnlock);
|
||||
}
|
||||
|
||||
private boolean applyLockscreenCardsNotificationRowFilterInTreeIfNeeded(
|
||||
View root,
|
||||
SbtSettings settings,
|
||||
@@ -4311,7 +4508,6 @@ final class StockLayoutCanvasController {
|
||||
+ (runtimeContext.getModeStateRepository().isSystemUiShadeLocked() ? 1 : 0);
|
||||
result = 31 * result + root.getWidth();
|
||||
result = 31 * result + root.getHeight();
|
||||
result = 31 * result + (root instanceof ViewGroup group ? group.getChildCount() : 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -4471,7 +4667,7 @@ final class StockLayoutCanvasController {
|
||||
dirtyUnlockedLayoutRoots.remove(root);
|
||||
settingsIdentityByRoot.remove(root);
|
||||
lockscreenCardsRowFilterSignatures.remove(root);
|
||||
clockTimeBucketByRoot.remove(root);
|
||||
clearUnlockedClockRefreshState(root);
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -63,7 +63,6 @@ final class ClockLayout {
|
||||
int baseHeightSteps,
|
||||
int autoGapSteps,
|
||||
int statusbarHeight,
|
||||
int visualBaselineY,
|
||||
int verticalOffsetSteps
|
||||
) {
|
||||
if (source == null || model == null || model.rows.isEmpty()) {
|
||||
@@ -102,10 +101,8 @@ final class ClockLayout {
|
||||
}
|
||||
measuredRows = positionRowsFromLogicalSteps(
|
||||
measuredRows,
|
||||
Math.max(1, baseHeightSteps),
|
||||
Math.max(1, autoGapSteps),
|
||||
Math.max(1, statusbarHeight),
|
||||
visualBaselineY,
|
||||
verticalOffsetSteps);
|
||||
|
||||
RowAlignment alignment = alignRows(measuredRows, position);
|
||||
@@ -216,10 +213,8 @@ final class ClockLayout {
|
||||
|
||||
private static ArrayList<MeasuredClockRow> positionRowsFromLogicalSteps(
|
||||
ArrayList<MeasuredClockRow> measuredRows,
|
||||
int baseHeightSteps,
|
||||
int autoGapSteps,
|
||||
int statusbarHeight,
|
||||
int visualBaselineY,
|
||||
int verticalOffsetSteps
|
||||
) {
|
||||
ArrayList<MeasuredClockRow> positionedRows = new ArrayList<>(measuredRows);
|
||||
@@ -232,8 +227,7 @@ 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));
|
||||
int baselineY = visualBaselineY - stepsToPx(verticalOffsetSteps, statusbarHeight);
|
||||
bottomPx = baselineY - row.baseline + heightPx;
|
||||
bottomPx = Math.max(1, statusbarHeight) - stepsToPx(verticalOffsetSteps, statusbarHeight);
|
||||
} else {
|
||||
MeasuredClockRow nextRow = measuredRows.get(rowIndex + 1);
|
||||
int gapSteps = resolveGapSteps(nextRow.source.gapBeforePx, autoGapSteps);
|
||||
|
||||
+105
-14
@@ -27,6 +27,7 @@ public final class LockscreenCardsNotificationIconSourceStore {
|
||||
new WeakHashMap<>();
|
||||
private static final ArrayList<String> AOD_NOTIFICATION_PACKAGES = new ArrayList<>();
|
||||
private static final int VIRTUAL_ICON_SIZE_PX = 39;
|
||||
private static int generation;
|
||||
|
||||
private LockscreenCardsNotificationIconSourceStore() {
|
||||
}
|
||||
@@ -34,7 +35,9 @@ public final class LockscreenCardsNotificationIconSourceStore {
|
||||
public static void put(ViewGroup container, ArrayList<SourceEntry> sources) {
|
||||
if (container == null || sources == null || sources.isEmpty()) {
|
||||
if (container != null) {
|
||||
SOURCES_BY_CONTAINER.remove(container);
|
||||
if (SOURCES_BY_CONTAINER.remove(container) != null) {
|
||||
bumpGeneration();
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -47,7 +50,12 @@ public final class LockscreenCardsNotificationIconSourceStore {
|
||||
attached.add(source);
|
||||
}
|
||||
if (attached.isEmpty()) {
|
||||
SOURCES_BY_CONTAINER.remove(container);
|
||||
if (SOURCES_BY_CONTAINER.remove(container) != null) {
|
||||
bumpGeneration();
|
||||
}
|
||||
} else if (!sameSourceEntries(SOURCES_BY_CONTAINER.get(container), attached)) {
|
||||
SOURCES_BY_CONTAINER.put(container, attached);
|
||||
bumpGeneration();
|
||||
} else {
|
||||
SOURCES_BY_CONTAINER.put(container, attached);
|
||||
}
|
||||
@@ -56,7 +64,11 @@ public final class LockscreenCardsNotificationIconSourceStore {
|
||||
public static boolean putPackages(ViewGroup container, ArrayList<String> packages) {
|
||||
if (container == null || packages == null || packages.isEmpty()) {
|
||||
if (container != null) {
|
||||
return PACKAGES_BY_CONTAINER.remove(container) != null;
|
||||
boolean changed = PACKAGES_BY_CONTAINER.remove(container) != null;
|
||||
if (changed) {
|
||||
bumpGeneration();
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -71,13 +83,18 @@ public final class LockscreenCardsNotificationIconSourceStore {
|
||||
}
|
||||
}
|
||||
if (!hasValid) {
|
||||
return PACKAGES_BY_CONTAINER.remove(container) != null;
|
||||
boolean changed = PACKAGES_BY_CONTAINER.remove(container) != null;
|
||||
if (changed) {
|
||||
bumpGeneration();
|
||||
}
|
||||
return changed;
|
||||
} else {
|
||||
ArrayList<String> previous = PACKAGES_BY_CONTAINER.get(container);
|
||||
if (previous != null && previous.equals(valid)) {
|
||||
return false;
|
||||
}
|
||||
PACKAGES_BY_CONTAINER.put(container, valid);
|
||||
bumpGeneration();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -85,7 +102,11 @@ public final class LockscreenCardsNotificationIconSourceStore {
|
||||
public static boolean putAodDrawables(ViewGroup container, ArrayList<? extends View> views) {
|
||||
if (container == null || views == null || views.isEmpty()) {
|
||||
if (container != null) {
|
||||
return AOD_DRAWABLES_BY_CONTAINER.remove(container) != null;
|
||||
boolean changed = AOD_DRAWABLES_BY_CONTAINER.remove(container) != null;
|
||||
if (changed) {
|
||||
bumpGeneration();
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -100,18 +121,28 @@ public final class LockscreenCardsNotificationIconSourceStore {
|
||||
valid.add(view);
|
||||
}
|
||||
if (valid.isEmpty()) {
|
||||
return AOD_DRAWABLES_BY_CONTAINER.remove(container) != null;
|
||||
boolean changed = AOD_DRAWABLES_BY_CONTAINER.remove(container) != null;
|
||||
if (changed) {
|
||||
bumpGeneration();
|
||||
}
|
||||
return changed;
|
||||
} else {
|
||||
ArrayList<View> previous = AOD_DRAWABLES_BY_CONTAINER.get(container);
|
||||
if (sameViews(previous, valid)) {
|
||||
return false;
|
||||
}
|
||||
AOD_DRAWABLES_BY_CONTAINER.put(container, valid);
|
||||
bumpGeneration();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public static void clearAodSources() {
|
||||
if (!PACKAGES_BY_CONTAINER.isEmpty()
|
||||
|| !AOD_DRAWABLES_BY_CONTAINER.isEmpty()
|
||||
|| !AOD_NOTIFICATION_PACKAGES.isEmpty()) {
|
||||
bumpGeneration();
|
||||
}
|
||||
PACKAGES_BY_CONTAINER.clear();
|
||||
AOD_DRAWABLES_BY_CONTAINER.clear();
|
||||
AOD_NOTIFICATION_PACKAGES.clear();
|
||||
@@ -121,20 +152,76 @@ public final class LockscreenCardsNotificationIconSourceStore {
|
||||
if (container == null) {
|
||||
return;
|
||||
}
|
||||
PACKAGES_BY_CONTAINER.remove(container);
|
||||
AOD_DRAWABLES_BY_CONTAINER.remove(container);
|
||||
boolean changed = PACKAGES_BY_CONTAINER.remove(container) != null;
|
||||
changed |= AOD_DRAWABLES_BY_CONTAINER.remove(container) != null;
|
||||
if (changed) {
|
||||
bumpGeneration();
|
||||
}
|
||||
}
|
||||
|
||||
public static void putAodNotificationPackages(ArrayList<String> packages) {
|
||||
ArrayList<String> previous = new ArrayList<>(AOD_NOTIFICATION_PACKAGES);
|
||||
AOD_NOTIFICATION_PACKAGES.clear();
|
||||
if (packages == null || packages.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
for (String pkg : packages) {
|
||||
if (AppIconRules.isValidPackageName(pkg) && !AOD_NOTIFICATION_PACKAGES.contains(pkg)) {
|
||||
AOD_NOTIFICATION_PACKAGES.add(pkg);
|
||||
if (packages != null && !packages.isEmpty()) {
|
||||
for (String pkg : packages) {
|
||||
if (AppIconRules.isValidPackageName(pkg) && !AOD_NOTIFICATION_PACKAGES.contains(pkg)) {
|
||||
AOD_NOTIFICATION_PACKAGES.add(pkg);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!previous.equals(AOD_NOTIFICATION_PACKAGES)) {
|
||||
bumpGeneration();
|
||||
}
|
||||
}
|
||||
|
||||
public static int generation() {
|
||||
return generation;
|
||||
}
|
||||
|
||||
private static void bumpGeneration() {
|
||||
generation++;
|
||||
}
|
||||
|
||||
private static boolean sameSourceEntries(
|
||||
ArrayList<SourceEntry> previous,
|
||||
ArrayList<SourceEntry> current
|
||||
) {
|
||||
if (previous == current) {
|
||||
return true;
|
||||
}
|
||||
if (previous == null || current == null || previous.size() != current.size()) {
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < previous.size(); i++) {
|
||||
SourceEntry oldEntry = previous.get(i);
|
||||
SourceEntry newEntry = current.get(i);
|
||||
if (oldEntry == newEntry) {
|
||||
continue;
|
||||
}
|
||||
if (oldEntry == null || newEntry == null) {
|
||||
return false;
|
||||
}
|
||||
if (oldEntry.view != newEntry.view) {
|
||||
return false;
|
||||
}
|
||||
if (oldEntry.key == null ? newEntry.key != null : !oldEntry.key.equals(newEntry.key)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static int lightweightSourceSignatureForRoot(View root) {
|
||||
int result = 17;
|
||||
result = 31 * result + generation();
|
||||
ViewGroup container = sourceContainerForRoot(root);
|
||||
Bounds bounds = sourceBoundsRelativeTo(root, container);
|
||||
if (isZeroSizeDotContainer(container, bounds)) {
|
||||
bounds = new Bounds(bounds.left, bounds.top, VIRTUAL_ICON_SIZE_PX, VIRTUAL_ICON_SIZE_PX);
|
||||
}
|
||||
result = 31 * result + (bounds != null ? bounds.signature() : 0);
|
||||
result = 31 * result + (sourceContainerHasHiddenAncestor(root, container) ? 1 : 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
private static boolean sameViews(ArrayList<View> previous, ArrayList<View> current) {
|
||||
@@ -348,6 +435,10 @@ public final class LockscreenCardsNotificationIconSourceStore {
|
||||
|
||||
public static boolean sourceContainerHasHiddenAncestorForRoot(View root) {
|
||||
ViewGroup container = sourceContainerForRoot(root);
|
||||
return sourceContainerHasHiddenAncestor(root, container);
|
||||
}
|
||||
|
||||
private static boolean sourceContainerHasHiddenAncestor(View root, ViewGroup container) {
|
||||
if (container == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -579,11 +579,21 @@ final class SnapshotRenderer {
|
||||
int result = 17;
|
||||
result = 31 * result + sourceTreeSignature(source.view());
|
||||
Bounds boundsOverride = source.boundsOverride();
|
||||
result = 31 * result + (boundsOverride != null ? boundsOverride.signature() : 0);
|
||||
result = 31 * result + boundsSizeSignature(boundsOverride);
|
||||
result = 31 * result + tintSignatureFor(source);
|
||||
return result;
|
||||
}
|
||||
|
||||
private int boundsSizeSignature(Bounds bounds) {
|
||||
if (bounds == null) {
|
||||
return 0;
|
||||
}
|
||||
int result = 17;
|
||||
result = 31 * result + bounds.width;
|
||||
result = 31 * result + bounds.height;
|
||||
return result;
|
||||
}
|
||||
|
||||
private int tintSignatureFor(SnapshotSource source) {
|
||||
return shouldApplyStatusBarTintTarget(source) ? StatusBarTintTarget.signature() : 0;
|
||||
}
|
||||
|
||||
+147
-18
@@ -113,7 +113,14 @@ public final class UnlockedIconSnapshotRenderController {
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
!scene.isLockscreen() || lastLayoutPlanByRoot.get(root) != null);
|
||||
!scene.isLockscreen() || lastLayoutPlanByRoot.get(root) != null,
|
||||
lockscreenIconDebugSummary(
|
||||
root,
|
||||
notificationHost,
|
||||
scene,
|
||||
cachedPlan,
|
||||
lastCollectedIconsByRoot.get(root),
|
||||
"cacheHit"));
|
||||
}
|
||||
lastLayoutSignatureByRoot.put(root, signature);
|
||||
Integer currentClockSourceGeometry = clockSourceGeometrySignature(
|
||||
@@ -191,7 +198,18 @@ public final class UnlockedIconSnapshotRenderController {
|
||||
if (scene.isLockscreen() && clockEnabledForScene(settings, scene) && currentClockLayout == null) {
|
||||
clearLockscreenHosts(clockHost, carrierHost, chipHost, statusHost, notificationHost);
|
||||
lastLayoutPlanByRoot.remove(root);
|
||||
return new RenderResult(false, stockSourcesChanged, chipSourcesChanged, false);
|
||||
return new RenderResult(
|
||||
false,
|
||||
stockSourcesChanged,
|
||||
chipSourcesChanged,
|
||||
false,
|
||||
lockscreenIconDebugSummary(
|
||||
root,
|
||||
notificationHost,
|
||||
scene,
|
||||
null,
|
||||
collectedIcons,
|
||||
"missingClock"));
|
||||
}
|
||||
LayoutPlan layoutPlan = layoutPlanner.solve(
|
||||
root,
|
||||
@@ -237,7 +255,18 @@ public final class UnlockedIconSnapshotRenderController {
|
||||
} else {
|
||||
notificationRenderer.clear(notificationHost);
|
||||
}
|
||||
return new RenderResult(true, stockSourcesChanged, chipSourcesChanged);
|
||||
return new RenderResult(
|
||||
true,
|
||||
stockSourcesChanged,
|
||||
chipSourcesChanged,
|
||||
true,
|
||||
lockscreenIconDebugSummary(
|
||||
root,
|
||||
notificationHost,
|
||||
scene,
|
||||
layoutPlan,
|
||||
collectedIcons,
|
||||
"solved"));
|
||||
}
|
||||
|
||||
public void refreshUnlockedAppearance(
|
||||
@@ -722,7 +751,6 @@ public final class UnlockedIconSnapshotRenderController {
|
||||
int textSizeSteps = clockTextSizeSteps(settings, scene);
|
||||
float textSizePx = clockTextSizePx(statusbarHeight, textSizeSteps);
|
||||
int autoGapSteps = clockAutoGapSteps(source, statusbarHeight, textSizeSteps);
|
||||
int visualBaselineY = clockVisualBaselineY(source, sourceBounds, statusbarHeight);
|
||||
ClockLayout layout = ClockLayout.measure(
|
||||
source,
|
||||
model,
|
||||
@@ -735,7 +763,6 @@ public final class UnlockedIconSnapshotRenderController {
|
||||
textSizeSteps,
|
||||
autoGapSteps,
|
||||
statusbarHeight,
|
||||
visualBaselineY,
|
||||
settings.clockVerticalOffsetPx);
|
||||
return layout;
|
||||
}
|
||||
@@ -748,17 +775,6 @@ public final class UnlockedIconSnapshotRenderController {
|
||||
return Math.max(1, Math.round(lineHeight * 100f / statusbarHeight));
|
||||
}
|
||||
|
||||
private int clockVisualBaselineY(TextView source, Bounds sourceBounds, int fallbackBaselineY) {
|
||||
if (source == null || sourceBounds == null) {
|
||||
return Math.max(1, fallbackBaselineY);
|
||||
}
|
||||
int baseline = source.getBaseline();
|
||||
if (baseline <= 0) {
|
||||
return Math.max(1, sourceBounds.top + sourceBounds.height);
|
||||
}
|
||||
return Math.max(1, sourceBounds.top + baseline);
|
||||
}
|
||||
|
||||
private int clockTextSizeSteps(SbtSettings settings, SceneKey scene) {
|
||||
return scene != null && scene.isLockscreen()
|
||||
? settings.clockLockTextSizeSteps
|
||||
@@ -1039,14 +1055,127 @@ public final class UnlockedIconSnapshotRenderController {
|
||||
return result;
|
||||
}
|
||||
|
||||
private String lockscreenIconDebugSummary(
|
||||
View root,
|
||||
ViewGroup notificationHost,
|
||||
SceneKey scene,
|
||||
LayoutPlan plan,
|
||||
CollectedIcons icons,
|
||||
String phase
|
||||
) {
|
||||
if (scene == null
|
||||
|| !scene.isLockscreen()
|
||||
|| scene.notificationDisplayStyle() != NotificationDisplayStyle.ICONS) {
|
||||
return null;
|
||||
}
|
||||
ArrayList<SnapshotPlacement> notificationPlacements =
|
||||
plan != null ? plan.notificationPlacements : null;
|
||||
return "phase=" + phase
|
||||
+ " root=" + viewBounds(root)
|
||||
+ " hostChildren=" + (notificationHost != null ? notificationHost.getChildCount() : -1)
|
||||
+ " sourceNotifs=" + sizeOf(icons != null ? icons.notificationIcons : null)
|
||||
+ " placementCount=" + sizeOf(notificationPlacements)
|
||||
+ " renderableCount=" + renderablePlacementCount(notificationPlacements)
|
||||
+ " clock=" + boundsText(plan != null && plan.clockPlacement != null
|
||||
? plan.clockPlacement.bounds
|
||||
: null)
|
||||
+ " carrier=" + boundsText(plan != null && plan.carrierPlacement != null
|
||||
? plan.carrierPlacement.bounds
|
||||
: null)
|
||||
+ " notifs=" + placementSummary(notificationPlacements);
|
||||
}
|
||||
|
||||
private int sizeOf(ArrayList<?> values) {
|
||||
return values != null ? values.size() : 0;
|
||||
}
|
||||
|
||||
private int renderablePlacementCount(ArrayList<SnapshotPlacement> placements) {
|
||||
if (placements == null) {
|
||||
return 0;
|
||||
}
|
||||
int count = 0;
|
||||
for (SnapshotPlacement placement : placements) {
|
||||
if (isRenderablePlacement(placement)) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
private boolean isRenderablePlacement(SnapshotPlacement placement) {
|
||||
return placement != null
|
||||
&& (placement.source != null
|
||||
|| placement.overflowDot
|
||||
|| placement.heldSignal != null);
|
||||
}
|
||||
|
||||
private String placementSummary(ArrayList<SnapshotPlacement> placements) {
|
||||
if (placements == null || placements.isEmpty()) {
|
||||
return "[]";
|
||||
}
|
||||
StringBuilder out = new StringBuilder("[");
|
||||
int limit = Math.min(placements.size(), 8);
|
||||
for (int i = 0; i < limit; i++) {
|
||||
if (i > 0) {
|
||||
out.append(';');
|
||||
}
|
||||
SnapshotPlacement placement = placements.get(i);
|
||||
out.append(i).append('{');
|
||||
if (placement == null) {
|
||||
out.append("null");
|
||||
} else {
|
||||
out.append("key=").append(placement.key)
|
||||
.append(",b=").append(boundsText(placement.bounds))
|
||||
.append(",source=").append(placement.source != null)
|
||||
.append(",dot=").append(placement.overflowDot)
|
||||
.append(",held=").append(placement.heldSignal != null)
|
||||
.append(",renderable=").append(isRenderablePlacement(placement));
|
||||
}
|
||||
out.append('}');
|
||||
}
|
||||
if (placements.size() > limit) {
|
||||
out.append(";...");
|
||||
}
|
||||
out.append(']');
|
||||
return out.toString();
|
||||
}
|
||||
|
||||
private String viewBounds(View view) {
|
||||
if (view == null) {
|
||||
return "null";
|
||||
}
|
||||
return view.getWidth() + "x" + view.getHeight()
|
||||
+ "+" + view.getLeft()
|
||||
+ "," + view.getTop();
|
||||
}
|
||||
|
||||
private String boundsText(Bounds bounds) {
|
||||
if (bounds == null) {
|
||||
return "null";
|
||||
}
|
||||
return bounds.width + "x" + bounds.height
|
||||
+ "+" + bounds.left
|
||||
+ "," + bounds.top;
|
||||
}
|
||||
|
||||
public record RenderResult(
|
||||
boolean layoutChanged,
|
||||
boolean stockSourcesChanged,
|
||||
boolean chipSourcesChanged,
|
||||
boolean shouldOwnLockscreen
|
||||
boolean shouldOwnLockscreen,
|
||||
String debugSummary
|
||||
) {
|
||||
public RenderResult(boolean layoutChanged, boolean stockSourcesChanged, boolean chipSourcesChanged) {
|
||||
this(layoutChanged, stockSourcesChanged, chipSourcesChanged, true);
|
||||
this(layoutChanged, stockSourcesChanged, chipSourcesChanged, true, null);
|
||||
}
|
||||
|
||||
public RenderResult(
|
||||
boolean layoutChanged,
|
||||
boolean stockSourcesChanged,
|
||||
boolean chipSourcesChanged,
|
||||
boolean shouldOwnLockscreen
|
||||
) {
|
||||
this(layoutChanged, stockSourcesChanged, chipSourcesChanged, shouldOwnLockscreen, null);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+63
-13
@@ -103,7 +103,8 @@ final class UnlockedLayoutPlanner {
|
||||
scene,
|
||||
edges,
|
||||
layoutCutoutBounds,
|
||||
clockLayout);
|
||||
clockLayout,
|
||||
statusbarHeight);
|
||||
if (carrierLayout != null && carrierLayout.width() > 0) {
|
||||
bands.add(UnlockedLayoutBand.carrier(
|
||||
carrierHost,
|
||||
@@ -649,7 +650,8 @@ final class UnlockedLayoutPlanner {
|
||||
SceneKey scene,
|
||||
LayoutEdges edges,
|
||||
Bounds cutoutBounds,
|
||||
ClockLayout clockLayout
|
||||
ClockLayout clockLayout,
|
||||
int statusbarHeight
|
||||
) {
|
||||
if (root == null
|
||||
|| collectedIcons == null
|
||||
@@ -687,9 +689,11 @@ final class UnlockedLayoutPlanner {
|
||||
settings,
|
||||
edges,
|
||||
cutoutBounds,
|
||||
scene,
|
||||
positionFor(settings.layoutCarrierPosition),
|
||||
sideFor(settings.layoutCarrierMiddleSide),
|
||||
clockLayout));
|
||||
clockLayout,
|
||||
statusbarHeight));
|
||||
}
|
||||
|
||||
private int carrierMaxWidth(
|
||||
@@ -697,9 +701,11 @@ final class UnlockedLayoutPlanner {
|
||||
SbtSettings settings,
|
||||
LayoutEdges edges,
|
||||
Bounds cutoutBounds,
|
||||
SceneKey scene,
|
||||
LayoutPosition position,
|
||||
AnchorSide middleSide,
|
||||
ClockLayout clockLayout
|
||||
ClockLayout clockLayout,
|
||||
int statusbarHeight
|
||||
) {
|
||||
int rootWidth = root != null ? root.getWidth() : 0;
|
||||
if (rootWidth <= 0 || edges == null) {
|
||||
@@ -723,42 +729,86 @@ final class UnlockedLayoutPlanner {
|
||||
return carrierMaxWidthWithClockReserve(
|
||||
Math.max(1, right - minLeft),
|
||||
settings,
|
||||
scene,
|
||||
position,
|
||||
middleSide,
|
||||
clockLayout,
|
||||
AnchorSide.RIGHT);
|
||||
AnchorSide.RIGHT,
|
||||
statusbarHeight);
|
||||
}
|
||||
int maxRight = usableCutout ? Math.max(left, cutoutBounds.left) : right;
|
||||
return carrierMaxWidthWithClockReserve(
|
||||
Math.max(1, maxRight - left),
|
||||
settings,
|
||||
scene,
|
||||
position,
|
||||
middleSide,
|
||||
clockLayout,
|
||||
AnchorSide.LEFT);
|
||||
AnchorSide.LEFT,
|
||||
statusbarHeight);
|
||||
}
|
||||
|
||||
private int carrierMaxWidthWithClockReserve(
|
||||
int sideWidth,
|
||||
SbtSettings settings,
|
||||
SceneKey scene,
|
||||
LayoutPosition carrierPosition,
|
||||
AnchorSide carrierMiddleSide,
|
||||
ClockLayout clockLayout,
|
||||
AnchorSide side
|
||||
AnchorSide side,
|
||||
int statusbarHeight
|
||||
) {
|
||||
if (sideWidth <= 0 || settings == null || clockLayout == null || clockLayout.width() <= 0) {
|
||||
if (sideWidth <= 0 || settings == null) {
|
||||
return Math.max(1, sideWidth);
|
||||
}
|
||||
LayoutPosition clockPosition = positionFor(settings.clockPosition);
|
||||
AnchorSide clockMiddleSide = sideFor(settings.clockMiddleCutoutSide);
|
||||
if (!occupiesSide(clockPosition, clockMiddleSide, side)
|
||||
|| !occupiesSide(carrierPosition, carrierMiddleSide, side)) {
|
||||
if (!occupiesSide(carrierPosition, carrierMiddleSide, side)) {
|
||||
return Math.max(1, sideWidth);
|
||||
}
|
||||
int reserved = clockLayout.width() + Math.max(0, settings.layoutItemPaddingPx);
|
||||
int reserved = notificationDotReserveForSide(settings, scene, side, statusbarHeight);
|
||||
if (clockLayout != null && clockLayout.width() > 0) {
|
||||
LayoutPosition clockPosition = positionFor(settings.clockPosition);
|
||||
AnchorSide clockMiddleSide = sideFor(settings.clockMiddleCutoutSide);
|
||||
if (occupiesSide(clockPosition, clockMiddleSide, side)) {
|
||||
reserved += clockLayout.width() + Math.max(0, settings.layoutItemPaddingPx);
|
||||
}
|
||||
}
|
||||
return Math.max(1, sideWidth - reserved);
|
||||
}
|
||||
|
||||
private int notificationDotReserveForSide(
|
||||
SbtSettings settings,
|
||||
SceneKey scene,
|
||||
AnchorSide side,
|
||||
int statusbarHeight
|
||||
) {
|
||||
if (settings == null
|
||||
|| scene == null
|
||||
|| !scene.isLockscreen()
|
||||
|| !settings.layoutNotifEnabledLockscreen
|
||||
|| (scene.notificationDisplayStyle() != NotificationDisplayStyle.ICONS
|
||||
&& scene.notificationDisplayStyle() != NotificationDisplayStyle.DOT)) {
|
||||
return 0;
|
||||
}
|
||||
int count = notificationCountForScene(settings, scene);
|
||||
if (count <= 0) {
|
||||
return 0;
|
||||
}
|
||||
String[] positions = notificationPositionsForScene(settings, scene);
|
||||
String[] middleSides = notificationMiddleSidesForScene(settings, scene);
|
||||
for (int i = 0; i < count; i++) {
|
||||
LayoutPosition position = positionFor(stringAt(positions, i, settings.layoutNotifPosition));
|
||||
AnchorSide middleSide = sideFor(stringAt(middleSides, i, settings.layoutNotifMiddleSide));
|
||||
if (occupiesSide(position, middleSide, side)) {
|
||||
int iconHeight = iconHeightPx(
|
||||
statusbarHeight,
|
||||
notificationIconHeightSteps(settings, scene));
|
||||
int dotWidth = Math.max(1, Math.round(Math.max(1, iconHeight) * 0.75f));
|
||||
return dotWidth + Math.max(0, settings.layoutItemPaddingPx);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
private boolean occupiesSide(
|
||||
LayoutPosition position,
|
||||
AnchorSide middleSide,
|
||||
|
||||
Reference in New Issue
Block a user