Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2249212ae3 | ||
|
|
d1160a2d2d | ||
|
|
28f08eb2b2 | ||
|
|
dbdc8e2af8 | ||
|
|
ea3d8221b5 | ||
|
|
1fa5fd24b1 | ||
|
|
8e7e825516 |
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
+11
-12
@@ -153,7 +153,7 @@ final class StockClockController {
|
|||||||
}
|
}
|
||||||
runtimeContext.getModeStateRepository().addLayoutEnabledListener(enabled -> {
|
runtimeContext.getModeStateRepository().addLayoutEnabledListener(enabled -> {
|
||||||
if (enabled) {
|
if (enabled) {
|
||||||
restoreAllOwnedClocks();
|
suspendOwnedClockTickers();
|
||||||
} else {
|
} else {
|
||||||
refreshAllClocks();
|
refreshAllClocks();
|
||||||
}
|
}
|
||||||
@@ -212,23 +212,22 @@ final class StockClockController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void removeAllRowOverlays() {
|
private void suspendOwnedClockTickers() {
|
||||||
for (TextView clockView : new ArrayList<>(trackedClocks)) {
|
for (TextView clockView : new ArrayList<>(ownedClocks)) {
|
||||||
removeRowOverlay(clockView);
|
stopTicker(clockView);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void restoreAllOwnedClocks() {
|
|
||||||
for (TextView clockView : new ArrayList<>(trackedClocks)) {
|
|
||||||
restoreOwnedClock(clockView);
|
|
||||||
}
|
|
||||||
removeAllRowOverlays();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void applyClockText(TextView clockView) {
|
private void applyClockText(TextView clockView) {
|
||||||
SbtSettings settings = RuntimeSettingsCache.get(clockView.getContext());
|
SbtSettings settings = RuntimeSettingsCache.get(clockView.getContext());
|
||||||
boolean layoutEnabled = settings.clockEnabled;
|
boolean layoutEnabled = settings.clockEnabled;
|
||||||
if (layoutEnabled || !hasCustomClockTextEnabled(settings)) {
|
if (layoutEnabled) {
|
||||||
|
if (ownedClocks.contains(clockView)) {
|
||||||
|
stopTicker(clockView);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!hasCustomClockTextEnabled(settings)) {
|
||||||
restoreOwnedClock(clockView);
|
restoreOwnedClock(clockView);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
+3
@@ -237,6 +237,9 @@ final class StockUnlockedNotificationIconsController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private boolean shouldManageContainer(View view) {
|
private boolean shouldManageContainer(View view) {
|
||||||
|
if (!isFeatureEnabled(view.getContext())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
if (!isUnlockedScene()) {
|
if (!isUnlockedScene()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
+105
-4
@@ -10,6 +10,7 @@ import android.graphics.drawable.Drawable;
|
|||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
import android.os.PowerManager;
|
import android.os.PowerManager;
|
||||||
import android.service.notification.StatusBarNotification;
|
import android.service.notification.StatusBarNotification;
|
||||||
|
import android.telecom.TelecomManager;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
@@ -34,6 +35,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;
|
||||||
@@ -405,6 +407,9 @@ final class StockLayoutCanvasController {
|
|||||||
Object target = chain.getThisObject();
|
Object target = chain.getThisObject();
|
||||||
Object alphaArg = firstArg(chain.getArgs());
|
Object alphaArg = firstArg(chain.getArgs());
|
||||||
if (target instanceof View view && alphaArg instanceof Float alpha) {
|
if (target instanceof View view && alphaArg instanceof Float alpha) {
|
||||||
|
if (shouldSuppressPrivacyOverlayStatusBarAlpha(view, alpha)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
if (shouldSuppressConflictingShadeHeaderAlpha(view, alpha)) {
|
if (shouldSuppressConflictingShadeHeaderAlpha(view, alpha)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -450,6 +455,16 @@ final class StockLayoutCanvasController {
|
|||||||
}
|
}
|
||||||
return chain.proceed();
|
return chain.proceed();
|
||||||
});
|
});
|
||||||
|
XposedHookSupport.hookAllMethodsIfExists(runtimeContext.getFramework(), viewClass, "setTranslationX", chain -> {
|
||||||
|
Object target = chain.getThisObject();
|
||||||
|
Object translationArg = firstArg(chain.getArgs());
|
||||||
|
if (target instanceof View view && translationArg instanceof Float translationX) {
|
||||||
|
if (shouldSuppressPrivacyOverlayStatusBarTranslationX(view, translationX)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return chain.proceed();
|
||||||
|
});
|
||||||
XposedHookSupport.hookAllMethodsIfExists(runtimeContext.getFramework(), viewClass, "layout", chain -> {
|
XposedHookSupport.hookAllMethodsIfExists(runtimeContext.getFramework(), viewClass, "layout", chain -> {
|
||||||
Object target = chain.getThisObject();
|
Object target = chain.getThisObject();
|
||||||
List<Object> args = chain.getArgs();
|
List<Object> args = chain.getArgs();
|
||||||
@@ -1491,6 +1506,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)) {
|
||||||
@@ -2437,8 +2455,7 @@ final class StockLayoutCanvasController {
|
|||||||
}
|
}
|
||||||
if (!isTrackableStatusChipSurface(view)
|
if (!isTrackableStatusChipSurface(view)
|
||||||
&& !isTrackedHiddenStatusChipSource(root, view)) {
|
&& !isTrackedHiddenStatusChipSource(root, view)) {
|
||||||
hiddenViewStates.remove(view);
|
forgetTrackedStatusChipState(view);
|
||||||
trackedUnlockedStockSurfaces.remove(view);
|
|
||||||
staleViews.add(view);
|
staleViews.add(view);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -2989,6 +3006,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 +3026,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)) {
|
||||||
@@ -3344,6 +3363,60 @@ final class StockLayoutCanvasController {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean shouldSuppressPrivacyOverlayStatusBarAlpha(View view, float alpha) {
|
||||||
|
if (alpha >= 0.99f
|
||||||
|
|| ownHiddenViewAlphaWriteDepth > 0
|
||||||
|
|| !isPhoneStatusBarRoot(view)
|
||||||
|
|| !isLayoutEnabled(view.getContext())
|
||||||
|
|| ongoingPrivacyChipInRoot(view) == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean shouldSuppressPrivacyOverlayStatusBarTranslationX(View view, float translationX) {
|
||||||
|
if (Math.abs(translationX) < 0.5f
|
||||||
|
|| ownHiddenViewAlphaWriteDepth > 0
|
||||||
|
|| !isPhoneStatusBarRoot(view)
|
||||||
|
|| !isLayoutEnabled(view.getContext())
|
||||||
|
|| ongoingPrivacyChipInRoot(view) == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isPhoneStatusBarRoot(View view) {
|
||||||
|
return view != null
|
||||||
|
&& view.getClass().getName().contains("PhoneStatusBarView");
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isOngoingPrivacyChip(View view) {
|
||||||
|
return view != null
|
||||||
|
&& view.getClass().getName().contains("OngoingPrivacyChip")
|
||||||
|
&& "privacy_chip".equals(ViewIdNames.idName(view));
|
||||||
|
}
|
||||||
|
|
||||||
|
private View ongoingPrivacyChipInRoot(View view) {
|
||||||
|
View root = view != null ? view.getRootView() : null;
|
||||||
|
if (!(root instanceof ViewGroup group)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
ArrayDeque<View> queue = new ArrayDeque<>();
|
||||||
|
queue.add(group);
|
||||||
|
while (!queue.isEmpty()) {
|
||||||
|
View current = queue.removeFirst();
|
||||||
|
if (isOngoingPrivacyChip(current)) {
|
||||||
|
return current;
|
||||||
|
}
|
||||||
|
if (current instanceof ViewGroup childGroup) {
|
||||||
|
for (int i = 0; i < childGroup.getChildCount(); i++) {
|
||||||
|
queue.addLast(childGroup.getChildAt(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
private boolean isStatusChipSource(View view) {
|
private boolean isStatusChipSource(View view) {
|
||||||
if (view == null || view.getVisibility() != View.VISIBLE) {
|
if (view == null || view.getVisibility() != View.VISIBLE) {
|
||||||
return false;
|
return false;
|
||||||
@@ -3384,6 +3457,9 @@ final class StockLayoutCanvasController {
|
|||||||
if (view == null || ownedIconHostManager.isOwnedHost(view)) {
|
if (view == null || ownedIconHostManager.isOwnedHost(view)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (view.getVisibility() != View.VISIBLE) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
String idName = ViewIdNames.idName(view);
|
String idName = ViewIdNames.idName(view);
|
||||||
if (!"ongoing_activity_capsule".equals(idName)) {
|
if (!"ongoing_activity_capsule".equals(idName)) {
|
||||||
return false;
|
return false;
|
||||||
@@ -3412,9 +3488,26 @@ final class StockLayoutCanvasController {
|
|||||||
|| !isStatusChipCandidate(view)) {
|
|| !isStatusChipCandidate(view)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (isCallStatusChip(view)
|
||||||
|
&& view.getVisibility() != View.VISIBLE
|
||||||
|
&& !isPhoneCallActive(view)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
return hasVisibleStatusChipContent(view);
|
return hasVisibleStatusChipContent(view);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isPhoneCallActive(View view) {
|
||||||
|
if (view == null || view.getContext() == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
TelecomManager telecomManager = view.getContext().getSystemService(TelecomManager.class);
|
||||||
|
return telecomManager != null && telecomManager.isInCall();
|
||||||
|
} catch (RuntimeException ignored) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private boolean hasVisibleStatusChipContent(View source) {
|
private boolean hasVisibleStatusChipContent(View source) {
|
||||||
if (!(source instanceof ViewGroup group)) {
|
if (!(source instanceof ViewGroup group)) {
|
||||||
return false;
|
return false;
|
||||||
@@ -4230,11 +4323,19 @@ final class StockLayoutCanvasController {
|
|||||||
|| isStatusChipShell(view)) {
|
|| isStatusChipShell(view)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
hiddenViewStates.remove(view);
|
forgetTrackedStatusChip(view);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void forgetTrackedStatusChip(View view) {
|
||||||
|
forgetTrackedStatusChipState(view);
|
||||||
trackedStatusChipSources.remove(view);
|
trackedStatusChipSources.remove(view);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void forgetTrackedStatusChipState(View view) {
|
||||||
|
hiddenViewStates.remove(view);
|
||||||
trackedUnlockedStockSurfaces.remove(view);
|
trackedUnlockedStockSurfaces.remove(view);
|
||||||
statusChipLifecycleLayoutSignatureByView.remove(view);
|
statusChipLifecycleLayoutSignatureByView.remove(view);
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void cleanupLayoutOffRoot(View root, SceneKey activeScene) {
|
private void cleanupLayoutOffRoot(View root, SceneKey activeScene) {
|
||||||
|
|||||||
+120
-36
@@ -11,6 +11,7 @@ import android.graphics.Path;
|
|||||||
import android.graphics.PorterDuff;
|
import android.graphics.PorterDuff;
|
||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
import android.graphics.RectF;
|
import android.graphics.RectF;
|
||||||
|
import android.graphics.drawable.AnimationDrawable;
|
||||||
import android.graphics.drawable.BitmapDrawable;
|
import android.graphics.drawable.BitmapDrawable;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
import android.os.BatteryManager;
|
import android.os.BatteryManager;
|
||||||
@@ -35,6 +36,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;
|
||||||
@@ -238,35 +240,51 @@ final class SnapshotRenderer {
|
|||||||
proxy.setTag(key);
|
proxy.setTag(key);
|
||||||
proxyChanged = true;
|
proxyChanged = true;
|
||||||
}
|
}
|
||||||
BitmapResult bitmapResult = bitmapFor(proxy, bounds);
|
|
||||||
Bitmap bitmap = bitmapResult.bitmap();
|
|
||||||
SnapshotRenderState desiredState = renderStateFor(placement);
|
SnapshotRenderState desiredState = renderStateFor(placement);
|
||||||
boolean bitmapChanged = bitmapResult.created()
|
Drawable animatedDrawable = animatedNotificationDrawable(placement);
|
||||||
|| !desiredState.equals(statesByProxy.get(proxy));
|
if (animatedDrawable != null) {
|
||||||
if (bitmapChanged) {
|
SnapshotRenderState currentState = statesByProxy.get(proxy);
|
||||||
if (placement.overflowDot()) {
|
boolean drawableChanged = !(proxy.getDrawable() instanceof AnimationDrawable)
|
||||||
drawOverflowDot(bitmap, placement.overflowDotColor(), placement.sourceOffsetX());
|
|| !canReuseAnimatedProxy(currentState, desiredState);
|
||||||
} else if (placement.heldSignal() != null) {
|
if (drawableChanged) {
|
||||||
drawHeldSignal(placement.heldSignal(), bitmap);
|
Drawable proxyDrawable = newDrawableInstance(animatedDrawable);
|
||||||
} else if (placement.source() != null
|
proxy.setImageDrawable(proxyDrawable);
|
||||||
&& placement.source().mode() == SnapshotMode.APP_ICON) {
|
proxyChanged = true;
|
||||||
drawAppIcon(host.getContext(), placement.source(), bitmap);
|
}
|
||||||
} else if (placement.source() != null) {
|
startAnimationIfNeeded(proxy.getDrawable());
|
||||||
drawSnapshot(placement, bitmap);
|
if (!desiredState.equals(currentState)) {
|
||||||
applyStatusBarTintTarget(placement.source(), bitmap);
|
statesByProxy.put(proxy, desiredState);
|
||||||
normalizeSemiTransparentDarkIcon(bitmap);
|
}
|
||||||
if (placement.signal()) {
|
} else {
|
||||||
saveHeldSignal(key, bounds, bitmap);
|
BitmapResult bitmapResult = bitmapFor(proxy, bounds);
|
||||||
|
Bitmap bitmap = bitmapResult.bitmap();
|
||||||
|
boolean bitmapChanged = bitmapResult.created()
|
||||||
|
|| !desiredState.equals(statesByProxy.get(proxy));
|
||||||
|
if (bitmapChanged) {
|
||||||
|
if (placement.overflowDot()) {
|
||||||
|
drawOverflowDot(bitmap, placement.overflowDotColor(), placement.sourceOffsetX());
|
||||||
|
} else if (placement.heldSignal() != null) {
|
||||||
|
drawHeldSignal(placement.heldSignal(), bitmap);
|
||||||
|
} else if (placement.source() != null
|
||||||
|
&& placement.source().mode() == SnapshotMode.APP_ICON) {
|
||||||
|
drawAppIcon(host.getContext(), placement.source(), bitmap);
|
||||||
|
} else if (placement.source() != null) {
|
||||||
|
drawSnapshot(placement, bitmap);
|
||||||
|
applyStatusBarTintTarget(placement.source(), bitmap);
|
||||||
|
normalizeSemiTransparentDarkIcon(bitmap);
|
||||||
|
if (placement.signal()) {
|
||||||
|
saveHeldSignal(key, bounds, bitmap);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
bitmap.eraseColor(Color.TRANSPARENT);
|
||||||
}
|
}
|
||||||
} else {
|
statesByProxy.put(proxy, desiredState);
|
||||||
bitmap.eraseColor(Color.TRANSPARENT);
|
proxyChanged = true;
|
||||||
|
}
|
||||||
|
if (proxy.getDrawable() == null) {
|
||||||
|
proxy.setImageBitmap(bitmap);
|
||||||
|
proxyChanged = true;
|
||||||
}
|
}
|
||||||
statesByProxy.put(proxy, desiredState);
|
|
||||||
proxyChanged = true;
|
|
||||||
}
|
|
||||||
if (proxy.getDrawable() == null) {
|
|
||||||
proxy.setImageBitmap(bitmap);
|
|
||||||
proxyChanged = true;
|
|
||||||
}
|
}
|
||||||
if (proxy.getAlpha() != 1f) {
|
if (proxy.getAlpha() != 1f) {
|
||||||
proxy.setAlpha(1f);
|
proxy.setAlpha(1f);
|
||||||
@@ -304,6 +322,52 @@ final class SnapshotRenderer {
|
|||||||
return renderedBounds;
|
return renderedBounds;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean canReuseAnimatedProxy(
|
||||||
|
SnapshotRenderState currentState,
|
||||||
|
SnapshotRenderState desiredState
|
||||||
|
) {
|
||||||
|
return currentState != null
|
||||||
|
&& desiredState != null
|
||||||
|
&& Objects.equals(currentState.key(), desiredState.key())
|
||||||
|
&& currentState.width() == desiredState.width()
|
||||||
|
&& currentState.height() == desiredState.height()
|
||||||
|
&& currentState.signal() == desiredState.signal()
|
||||||
|
&& currentState.overflowDot() == desiredState.overflowDot()
|
||||||
|
&& currentState.overflowDotColor() == desiredState.overflowDotColor()
|
||||||
|
&& currentState.sourceOffsetX() == desiredState.sourceOffsetX()
|
||||||
|
&& currentState.sourceRenderBoundsSignature() == desiredState.sourceRenderBoundsSignature()
|
||||||
|
&& Objects.equals(currentState.heldSignalKey(), desiredState.heldSignalKey())
|
||||||
|
&& currentState.heldBitmapId() == desiredState.heldBitmapId()
|
||||||
|
&& currentState.sourceMode() == desiredState.sourceMode()
|
||||||
|
&& currentState.tintSignature() == desiredState.tintSignature();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Drawable animatedNotificationDrawable(SnapshotPlacement placement) {
|
||||||
|
if (placement == null
|
||||||
|
|| placement.source() == null
|
||||||
|
|| placement.source().mode() != SnapshotMode.NOTIFICATION_DRAWABLE
|
||||||
|
|| !(placement.source().view() instanceof ImageView imageView)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Drawable drawable = imageView.getDrawable();
|
||||||
|
return drawable instanceof AnimationDrawable ? drawable : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Drawable newDrawableInstance(Drawable drawable) {
|
||||||
|
Drawable.ConstantState constantState = drawable != null ? drawable.getConstantState() : null;
|
||||||
|
if (constantState != null) {
|
||||||
|
return constantState.newDrawable().mutate();
|
||||||
|
}
|
||||||
|
return drawable != null ? drawable.mutate() : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void startAnimationIfNeeded(Drawable drawable) {
|
||||||
|
if (drawable instanceof AnimationDrawable animationDrawable && !animationDrawable.isRunning()) {
|
||||||
|
animationDrawable.setVisible(true, true);
|
||||||
|
animationDrawable.start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void clear(ViewGroup host) {
|
void clear(ViewGroup host) {
|
||||||
LinkedHashMap<String, ImageView> proxies = proxiesByHost.remove(host);
|
LinkedHashMap<String, ImageView> proxies = proxiesByHost.remove(host);
|
||||||
if (proxies == null) {
|
if (proxies == null) {
|
||||||
@@ -748,16 +812,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 +1257,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 +1283,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 +1303,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;
|
||||||
|
|||||||
+2
-1
@@ -1188,6 +1188,7 @@ final class UnlockedStockSourceCollector {
|
|||||||
View view = source.view();
|
View view = source.view();
|
||||||
if (view == null
|
if (view == null
|
||||||
|| view == root
|
|| view == root
|
||||||
|
|| view.getVisibility() != View.VISIBLE
|
||||||
|| !view.isAttachedToWindow()
|
|| !view.isAttachedToWindow()
|
||||||
|| !ViewGeometry.isDescendantOf(view, root)
|
|| !ViewGeometry.isDescendantOf(view, root)
|
||||||
|| ReflectionSupport.getBooleanField(view, "sbtStatusChipForcedHidden", false)
|
|| ReflectionSupport.getBooleanField(view, "sbtStatusChipForcedHidden", false)
|
||||||
@@ -1301,7 +1302,7 @@ final class UnlockedStockSourceCollector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private boolean isStatusChipMetricCandidate(View root, View view, boolean allowHidden) {
|
private boolean isStatusChipMetricCandidate(View root, View view, boolean allowHidden) {
|
||||||
if (view == null || view == root || root == null) {
|
if (view == null || view == root || root == null || view.getVisibility() != View.VISIBLE) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!allowHidden && view.getAlpha() <= 0f && !hasRenderableStatusChipContent(view)) {
|
if (!allowHidden && view.getAlpha() <= 0f && !hasRenderableStatusChipContent(view)) {
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import android.view.inputmethod.EditorInfo;
|
|||||||
import android.widget.CheckBox;
|
import android.widget.CheckBox;
|
||||||
import android.widget.EditText;
|
import android.widget.EditText;
|
||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
|
import android.widget.RadioButton;
|
||||||
import android.widget.RadioGroup;
|
import android.widget.RadioGroup;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
@@ -859,15 +860,30 @@ public final class LayoutFragment extends Fragment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private int resolveLeftSideId(RadioGroup group) {
|
private int resolveLeftSideId(RadioGroup group) {
|
||||||
int id = group.getChildCount() > 0 ? group.getChildAt(0).getId() : View.NO_ID;
|
int id = sideButtonId(group, 0);
|
||||||
return id != View.NO_ID ? id : 0;
|
return id != View.NO_ID ? id : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private int resolveRightSideId(RadioGroup group) {
|
private int resolveRightSideId(RadioGroup group) {
|
||||||
int id = group.getChildCount() > 1 ? group.getChildAt(1).getId() : View.NO_ID;
|
int id = sideButtonId(group, 1);
|
||||||
return id != View.NO_ID ? id : resolveLeftSideId(group);
|
return id != View.NO_ID ? id : resolveLeftSideId(group);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private int sideButtonId(RadioGroup group, int radioIndex) {
|
||||||
|
int seen = 0;
|
||||||
|
for (int i = 0; i < group.getChildCount(); i++) {
|
||||||
|
View child = group.getChildAt(i);
|
||||||
|
if (!(child instanceof RadioButton)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (seen == radioIndex) {
|
||||||
|
return child.getId();
|
||||||
|
}
|
||||||
|
seen++;
|
||||||
|
}
|
||||||
|
return View.NO_ID;
|
||||||
|
}
|
||||||
|
|
||||||
private void setNumericText(EditText input, int value) {
|
private void setNumericText(EditText input, int value) {
|
||||||
if (input == null) {
|
if (input == null) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
+2
-1
@@ -10,6 +10,7 @@ import android.view.ViewGroup;
|
|||||||
import android.widget.CheckBox;
|
import android.widget.CheckBox;
|
||||||
import android.widget.EditText;
|
import android.widget.EditText;
|
||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
|
import android.widget.RadioButton;
|
||||||
import android.widget.RadioGroup;
|
import android.widget.RadioGroup;
|
||||||
import android.widget.ScrollView;
|
import android.widget.ScrollView;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
@@ -775,7 +776,7 @@ abstract class LockedSceneLayoutFragment extends Fragment {
|
|||||||
private int firstSideId(RadioGroup group, int rightId) {
|
private int firstSideId(RadioGroup group, int rightId) {
|
||||||
for (int i = 0; i < group.getChildCount(); i++) {
|
for (int i = 0; i < group.getChildCount(); i++) {
|
||||||
View child = group.getChildAt(i);
|
View child = group.getChildAt(i);
|
||||||
if (child.getId() != rightId) {
|
if (child instanceof RadioButton && child.getId() != rightId) {
|
||||||
return child.getId();
|
return child.getId();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -1 +1 @@
|
|||||||
version=0.3
|
version=0.4
|
||||||
|
|||||||
Reference in New Issue
Block a user