From 9d7cb0b3f9353314c6fc060f0ccede578e43220f Mon Sep 17 00:00:00 2001 From: ajp_anton Date: Mon, 1 Jun 2026 01:40:00 +0000 Subject: [PATCH] Clean up post-AOD layout pipeline --- .../ExampleInstrumentedTest.java | 26 - .../runtime/NotificationKeyReflection.java | 8 +- .../runtime/features/RuntimeContext.java | 6 +- .../features/chips/StatusChipHider.java | 548 +------------- .../LockscreenCardsNotificationRowFilter.java | 4 + .../layout/StockLayoutCanvasController.java | 677 +++++++++++++---- .../PackedStatusBarLayoutSolver.java | 7 +- .../layoutsolver/StatusBarLayoutSolver.java | 710 +----------------- .../runtime/mode/ModeStateRepository.java | 56 +- .../NotificationActiveKeyStore.java | 68 ++ .../NotificationUnreadTracker.java | 137 ++++ .../render/DebugBoundsOverlayController.java | 42 +- ...creenCardsNotificationIconSourceStore.java | 59 +- .../runtime/render/SnapshotModels.java | 9 - .../UnlockedIconSnapshotRenderController.java | 19 +- .../runtime/render/UnlockedLayoutBand.java | 232 +----- .../runtime/render/UnlockedLayoutPlanner.java | 135 ++-- .../render/UnlockedStockSourceCollector.java | 66 +- .../shell/settings/SbtDefaults.java | 7 - .../shell/settings/SbtSettings.java | 203 ----- .../shell/settings/SbtSettingsProvider.java | 40 - .../shell/ui/LayoutFragment.java | 272 ++----- .../shell/ui/LayoutHomeFragment.java | 107 +-- .../shell/ui/LayoutOrderingUi.java | 24 +- .../shell/ui/LayoutSectionCopySupport.java | 23 +- .../shell/ui/LockedSceneLayoutFragment.java | 250 ++---- .../shell/ui/ViewTreeSupport.java | 157 +++- app/src/main/res/layout/fragment_layout.xml | 24 - app/src/main/res/values/strings.xml | 2 - .../statusbartweak/ExampleUnitTest.java | 17 - .../render/UnlockedLayoutBandTest.java | 12 +- 31 files changed, 1366 insertions(+), 2581 deletions(-) delete mode 100644 app/src/androidTest/java/se/ajpanton/statusbartweak/ExampleInstrumentedTest.java create mode 100644 app/src/main/java/se/ajpanton/statusbartweak/runtime/notifications/NotificationActiveKeyStore.java create mode 100644 app/src/main/java/se/ajpanton/statusbartweak/runtime/notifications/NotificationUnreadTracker.java delete mode 100644 app/src/test/java/se/ajpanton/statusbartweak/ExampleUnitTest.java diff --git a/app/src/androidTest/java/se/ajpanton/statusbartweak/ExampleInstrumentedTest.java b/app/src/androidTest/java/se/ajpanton/statusbartweak/ExampleInstrumentedTest.java deleted file mode 100644 index fff5314..0000000 --- a/app/src/androidTest/java/se/ajpanton/statusbartweak/ExampleInstrumentedTest.java +++ /dev/null @@ -1,26 +0,0 @@ -package se.ajpanton.statusbartweak; - -import android.content.Context; - -import androidx.test.platform.app.InstrumentationRegistry; -import androidx.test.ext.junit.runners.AndroidJUnit4; - -import org.junit.Test; -import org.junit.runner.RunWith; - -import static org.junit.Assert.*; - -/** - * Instrumented test, which will execute on an Android device. - * - * @see Testing documentation - */ -@RunWith(AndroidJUnit4.class) -public class ExampleInstrumentedTest { - @Test - public void useAppContext() { - // Context of the app under test. - Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext(); - assertEquals("se.ajpanton.statusbartweak", appContext.getPackageName()); - } -} diff --git a/app/src/main/java/se/ajpanton/statusbartweak/runtime/NotificationKeyReflection.java b/app/src/main/java/se/ajpanton/statusbartweak/runtime/NotificationKeyReflection.java index e2ce979..39847fe 100644 --- a/app/src/main/java/se/ajpanton/statusbartweak/runtime/NotificationKeyReflection.java +++ b/app/src/main/java/se/ajpanton/statusbartweak/runtime/NotificationKeyReflection.java @@ -16,7 +16,9 @@ public final class NotificationKeyReflection { "mNotificationKey", "notificationKey", "mKey", - "key" + "key", + "mSlot", + "slot" }; private NotificationKeyReflection() { @@ -53,6 +55,10 @@ public final class NotificationKeyReflection { if (key != null) { return key; } + key = nonEmptyStringFromMethod(view, "getSlot"); + if (key != null) { + return key; + } return nonEmptyStringFromFields(view, ICON_VIEW_KEY_FIELD_NAMES); } diff --git a/app/src/main/java/se/ajpanton/statusbartweak/runtime/features/RuntimeContext.java b/app/src/main/java/se/ajpanton/statusbartweak/runtime/features/RuntimeContext.java index abfaa5b..899946f 100644 --- a/app/src/main/java/se/ajpanton/statusbartweak/runtime/features/RuntimeContext.java +++ b/app/src/main/java/se/ajpanton/statusbartweak/runtime/features/RuntimeContext.java @@ -37,10 +37,6 @@ public final class RuntimeContext { return modeStateRepository; } - public boolean isLogEnabled() { - return RuntimeLogGate.isEnabled(); - } - public void logWarning(String message, Throwable throwable) { logSplit(Log.WARN, message, throwable); } @@ -50,7 +46,7 @@ public final class RuntimeContext { } private void logSplit(int priority, String message, Throwable throwable) { - if (!isLogEnabled()) { + if (!RuntimeLogGate.isEnabled()) { return; } String safeMessage = message != null ? message : ""; diff --git a/app/src/main/java/se/ajpanton/statusbartweak/runtime/features/chips/StatusChipHider.java b/app/src/main/java/se/ajpanton/statusbartweak/runtime/features/chips/StatusChipHider.java index 0b09675..abafe29 100644 --- a/app/src/main/java/se/ajpanton/statusbartweak/runtime/features/chips/StatusChipHider.java +++ b/app/src/main/java/se/ajpanton/statusbartweak/runtime/features/chips/StatusChipHider.java @@ -3,21 +3,14 @@ package se.ajpanton.statusbartweak.runtime.features.chips; import android.app.KeyguardManager; import android.content.Context; import android.content.Intent; -import android.view.View; -import android.view.ViewGroup; -import android.view.ViewParent; -import android.widget.TextView; -import java.util.ArrayDeque; import java.util.Collections; import java.util.Locale; import java.util.Set; import java.util.WeakHashMap; import se.ajpanton.statusbartweak.runtime.SystemContextProvider; -import se.ajpanton.statusbartweak.runtime.ViewIdNames; import se.ajpanton.statusbartweak.runtime.features.RuntimeContext; -import se.ajpanton.statusbartweak.runtime.hooks.InstanceStateStore; import se.ajpanton.statusbartweak.runtime.hooks.ReflectionSupport; import se.ajpanton.statusbartweak.runtime.hooks.XposedHookSupport; import se.ajpanton.statusbartweak.runtime.settings.BroadcastReceiverSupport; @@ -26,25 +19,12 @@ import se.ajpanton.statusbartweak.shell.settings.SbtSettings; final class StatusChipHider { - private static final String FIELD_FORCED_HIDDEN = "sbtStatusChipForcedHidden"; - private static final String FIELD_PREV_VIS = "sbtStatusChipPrevVis"; - private static final int TOP_REGION_DP = 220; - private static final int MAX_TEXT_SCAN_LEN = 160; - private static final int MAX_CLASS_SCAN_LEN = 480; - private static final int MAX_TEXT_NODES = 48; - private static final int MAX_ASCENT = 8; - private static final int ZONE_NONE = 0; - private static final int ZONE_TOP = 1; private static final int KIND_UNKNOWN = 0; private static final int KIND_MEDIA = 1; private static final int KIND_NAV = 2; private static final int KIND_CALL = 3; private final RuntimeContext runtimeContext; - private final InstanceStateStore instanceStateStore = new InstanceStateStore(); - private final Set trackedRoots = Collections.newSetFromMap(new WeakHashMap<>()); - private final Set scannedRoots = Collections.newSetFromMap(new WeakHashMap<>()); - private final Set forcedHiddenViews = Collections.newSetFromMap(new WeakHashMap<>()); private final Set ongoingControllers = Collections.newSetFromMap(new WeakHashMap<>()); private boolean hooksInstalled; @@ -69,8 +49,6 @@ final class StatusChipHider { installBroadcastReceiver(SystemContextProvider.currentApplication()); refreshSettings(); installOngoingActivityHooks(classLoader); - installTouchInterceptHooks(classLoader); - installViewRootHooks(); hooksInstalled = true; } @@ -100,7 +78,6 @@ final class StatusChipHider { refreshSettings(); if (isAnyChipHidingEnabled()) { refreshOngoingActivityController(controller); - rescanTrackedRoots(); } } return result; @@ -130,90 +107,11 @@ final class StatusChipHider { return result; } Object data = chain.getArg(1); - boolean suppress = shouldHide(classifyOngoingData(data), ZONE_TOP); - return suppress ? true : result; + int kind = classifyOngoingData(data); + return shouldHideEnabledKind(kind) ? true : result; }); } - private void installViewRootHooks() { - Class viewRootClass = ReflectionSupport.requireClass("android.view.ViewRootImpl", null); - XposedHookSupport.hookAllMethods(runtimeContext.getFramework(), viewRootClass, "performTraversals", chain -> { - Object result = chain.proceed(); - Object rootObj = ReflectionSupport.requireFieldValue(chain.getThisObject(), "mView"); - if (!(rootObj instanceof View root)) { - return result; - } - installBroadcastReceiver(root.getContext()); - trackedRoots.add(root); - if (!isAnyChipHidingEnabled()) { - restoreForcedHiddenViews(); - return result; - } - if (scannedRoots.add(root)) { - applyToViewTree(root); - } else { - keepForcedHiddenViewsHidden(); - } - return result; - }); - } - - private void installTouchInterceptHooks(ClassLoader classLoader) { - Class targetClass = ReflectionSupport.findClassIfExists( - "com.android.systemui.statusbar.phone.TouchInterceptFrameLayout", - classLoader - ); - if (targetClass == null) { - return; - } - XposedHookSupport.hookAllMethodsIfExists(runtimeContext.getFramework(), targetClass, "onLayout", chain -> { - Object result = chain.proceed(); - if (!isAnyChipHidingEnabled()) { - return result; - } - if (!(chain.getThisObject() instanceof View view)) { - return result; - } - if (view.getWidth() > 0 && view.getHeight() > 0) { - applySourceDecision(view); - } - return result; - }); - XposedHookSupport.hookAllMethodsIfExists(runtimeContext.getFramework(), targetClass, "onAttachedToWindow", chain -> { - Object result = chain.proceed(); - if (!isAnyChipHidingEnabled()) { - return result; - } - if (chain.getThisObject() instanceof View view && shouldPreemptivelyHide(view)) { - forceHide(view); - } - return result; - }); - XposedHookSupport.hookAllMethodsIfExists(runtimeContext.getFramework(), targetClass, "setVisibility", chain -> { - if (!(chain.getThisObject() instanceof View view)) { - return chain.proceed(); - } - if (isAnyChipHidingEnabled() - && !chain.getArgs().isEmpty() - && chain.getArg(0) instanceof Integer requestedVisibility - && requestedVisibility != View.GONE - && shouldPreemptivelyHide(view)) { - markForcedHidden(view, requestedVisibility); - Object[] args = chain.getArgs().toArray(); - args[0] = View.GONE; - return chain.proceed(args); - } - Object result = chain.proceed(); - if (!isAnyChipHidingEnabled()) { - return result; - } - if (view.getWidth() > 0 && view.getHeight() > 0) { - applySourceDecision(view); - } - return result; - }); - } - private void installBroadcastReceiver(Context context) { if (broadcastInstalled) { return; @@ -226,9 +124,7 @@ final class StatusChipHider { public void onReceive(Context context, Intent intent) { RuntimeSettingsCache.invalidate(); refreshSettings(); - scannedRoots.clear(); refreshOngoingActivityLists(); - rescanTrackedRoots(); } }; BroadcastReceiverSupport.registerExportedOnApplicationContext( @@ -260,19 +156,6 @@ final class StatusChipHider { return hideAll || hideMediaUnlocked || hideNavUnlocked || hideCallUnlocked; } - private void rescanTrackedRoots() { - if (!isAnyChipHidingEnabled()) { - restoreForcedHiddenViews(); - return; - } - for (View root : trackedRoots) { - if (root != null) { - scannedRoots.add(root); - applyToViewTree(root); - } - } - } - private void refreshOngoingActivityLists() { if (ongoingActivityDataHelperClass == null || notificationLockscreenUserManagerClass == null) { return; @@ -315,200 +198,14 @@ final class StatusChipHider { boolean sawItem = false; for (Object data : iterable) { sawItem = true; - if (!shouldHide(classifyOngoingData(data), ZONE_TOP)) { + if (!shouldHideEnabledKind(classifyOngoingData(data))) { return false; } } return sawItem; } - private void applyToViewTree(View root) { - ArrayDeque stack = new ArrayDeque<>(); - stack.push(root); - while (!stack.isEmpty()) { - View source = stack.pop(); - if (source == null) { - continue; - } - if (source instanceof ViewGroup group) { - for (int index = group.getChildCount() - 1; index >= 0; index--) { - stack.push(group.getChildAt(index)); - } - } - applySourceDecision(source); - } - } - - private boolean applySourceDecision(View source) { - if (source == null) { - return false; - } - int zone = detectZone(source); - if (zone == ZONE_NONE || !isSourceCandidate(source)) { - restoreIfForcedHidden(source); - return false; - } - View target = resolveHideTarget(source, zone); - if (target == null) { - restoreIfForcedHidden(source); - return false; - } - int targetZone = detectZone(target); - if (targetZone == ZONE_NONE) { - restoreIfForcedHidden(target); - return false; - } - String sourceText = collectText(source); - String targetText = target == source ? sourceText : collectText(target); - String kindText = sourceText.isEmpty() ? targetText : sourceText; - String classNames = target == source - ? collectClassNames(source) - : collectClassNames(source) + " " + collectClassNames(target); - String lowerText = kindText.toLowerCase(Locale.ROOT); - if (looksLikePrivacy(target, kindText) || isDefinitelyNotChipText(lowerText)) { - restoreIfForcedHidden(target); - return false; - } - int kind = classifyKind(source, kindText, classNames); - if (shouldHide(kind, targetZone)) { - forceHide(target); - return true; - } else { - restoreIfForcedHidden(target); - return false; - } - } - - private boolean shouldPreemptivelyHide(View source) { - if (source == null) { - return false; - } - if (isForcedHidden(source) && shouldHideTopUnlocked()) { - return true; - } - if (!isTransitionSourceCandidate(source)) { - return false; - } - return shouldHideSource(source, true); - } - - private boolean shouldHideSource(View source, boolean allowRelaxedGeometry) { - int zone = detectZone(source); - boolean relaxedGeometry = false; - if (zone == ZONE_NONE) { - if (!allowRelaxedGeometry || !isTransitionSourceCandidate(source)) { - return false; - } - if (source.getWidth() > 0 && source.getHeight() > 0) { - return false; - } - zone = ZONE_TOP; - relaxedGeometry = true; - } else if (!isSourceCandidate(source)) { - return false; - } - String sourceText = collectText(source); - String lowerText = sourceText.toLowerCase(Locale.ROOT); - if (looksLikePrivacy(source, sourceText) || isDefinitelyNotChipText(lowerText)) { - return false; - } - int kind = classifyKind(source, sourceText, collectClassNames(source)); - if (relaxedGeometry && kind == KIND_UNKNOWN && lowerText.isEmpty()) { - return false; - } - return shouldHide(kind, zone); - } - - private boolean isSourceCandidate(View view) { - return isTransitionSourceCandidate(view) && looksLikeChipGeometry(view); - } - - private boolean isTransitionSourceCandidate(View view) { - if (isOngoingActivityCapsule(view)) { - return false; - } - if (!isSystemUiView(view)) { - return false; - } - String className = className(view).toLowerCase(Locale.ROOT); - if (className.contains("privacy") || isDefinitelyNotChipClass(className)) { - return false; - } - return isChipClassName(className); - } - - private View resolveHideTarget(View source, int sourceZone) { - String sourceClass = className(source).toLowerCase(Locale.ROOT); - if (sourceClass.contains("touchinterceptframelayout")) { - return source; - } - View best = null; - View current = source; - int depth = 0; - int screenWidth = source.getResources().getDisplayMetrics().widthPixels; - while (current != null && depth < MAX_ASCENT) { - if (!isSystemUiView(current)) { - break; - } - if (detectZone(current) != sourceZone) { - break; - } - if (looksLikeHideTarget(current, source, screenWidth)) { - best = current; - } - ViewParent parent = current.getParent(); - current = parent instanceof View view ? view : null; - depth++; - } - return best; - } - - private boolean looksLikeHideTarget(View candidate, View source, int screenWidth) { - if (!looksLikeChipGeometry(candidate)) { - return false; - } - String className = className(candidate).toLowerCase(Locale.ROOT); - if (className.contains("privacy") || isDefinitelyNotChipClass(className)) { - return false; - } - if (!isChipClassName(className)) { - return false; - } - int width = candidate.getWidth(); - int height = candidate.getHeight(); - if (width >= (int) (screenWidth * 0.98f) && height < dp(candidate, 90)) { - return false; - } - if (candidate == source) { - return true; - } - return candidate instanceof ViewGroup && width >= source.getWidth(); - } - - private boolean isChipClassName(String lowerClass) { - return lowerClass.contains("chip") - || lowerClass.contains("ongoing") - || lowerClass.contains("statusevent") - || lowerClass.contains("touchinterceptframelayout"); - } - - private int detectZone(View view) { - if (view == null || view.getWidth() <= 0 || view.getHeight() <= 0) { - return ZONE_NONE; - } - int[] location = new int[2]; - try { - view.getLocationOnScreen(location); - } catch (Throwable ignored) { - return ZONE_NONE; - } - return location[1] >= 0 && location[1] <= dp(view, TOP_REGION_DP) ? ZONE_TOP : ZONE_NONE; - } - - private boolean shouldHide(int kind, int zone) { - if (zone != ZONE_TOP || !shouldHideTopUnlocked()) { - return false; - } + private boolean shouldHideEnabledKind(int kind) { if (hideAll && kind == KIND_UNKNOWN) { return true; } @@ -528,13 +225,10 @@ final class StatusChipHider { return isAnyChipHidingEnabled() && !isKeyguardLocked(); } - private int classifyKind(View view, String text, String classNames) { + private int classifyKind(String text, String classNames) { String lowerText = text != null ? text.toLowerCase(Locale.ROOT) : ""; - String lowerClass = classNames != null && !classNames.isEmpty() - ? classNames.toLowerCase(Locale.ROOT) - : (view != null ? className(view).toLowerCase(Locale.ROOT) : ""); + String lowerClass = classNames != null ? classNames.toLowerCase(Locale.ROOT) : ""; if (containsToken(lowerText, "call") - || containsPhrase(lowerText, "ongoing call") || lowerClass.contains("call")) { return KIND_CALL; } @@ -577,188 +271,7 @@ final class StatusChipHider { + textField(data, "mSecondaryInfo") + " " + textField(data, "mDescription") + " " + textField(data, "mExpandedChipText")).trim(); - return classifyKind(null, text, data.getClass().getName()); - } - - private boolean looksLikePrivacy(View view, String text) { - String lowerClass = className(view).toLowerCase(Locale.ROOT); - String lowerText = text != null ? text.toLowerCase(Locale.ROOT) : ""; - return lowerClass.contains("privacy") - || containsToken(lowerText, "camera") - || containsToken(lowerText, "microphone") - || containsPhrase(lowerText, "location in use") - || containsPhrase(lowerText, "mic in use"); - } - - private String collectClassNames(View root) { - StringBuilder out = new StringBuilder(); - appendClassName(out, root); - if (!(root instanceof ViewGroup)) { - return out.toString(); - } - ArrayDeque stack = new ArrayDeque<>(); - stack.push(root); - int nodes = 0; - while (!stack.isEmpty() && out.length() < MAX_CLASS_SCAN_LEN && nodes < MAX_TEXT_NODES) { - View current = stack.pop(); - nodes++; - if (current != root) { - appendClassName(out, current); - } - if (current instanceof ViewGroup group) { - for (int index = 0; index < group.getChildCount(); index++) { - stack.push(group.getChildAt(index)); - } - } - } - return out.toString(); - } - - private String collectText(View root) { - StringBuilder out = new StringBuilder(); - appendText(out, root.getContentDescription()); - if (root instanceof TextView textView) { - appendText(out, textView.getText()); - } - if (!(root instanceof ViewGroup)) { - return out.toString(); - } - ArrayDeque stack = new ArrayDeque<>(); - stack.push(root); - int nodes = 0; - while (!stack.isEmpty() && out.length() < MAX_TEXT_SCAN_LEN && nodes < MAX_TEXT_NODES) { - View current = stack.pop(); - nodes++; - if (current != root) { - appendText(out, current.getContentDescription()); - if (current instanceof TextView textView) { - appendText(out, textView.getText()); - } - } - if (current instanceof ViewGroup group) { - for (int index = 0; index < group.getChildCount(); index++) { - stack.push(group.getChildAt(index)); - } - } - } - return out.toString(); - } - - private void forceHide(View view) { - int restoreVisibility = view.getVisibility() != View.GONE ? view.getVisibility() : View.VISIBLE; - markForcedHidden(view, restoreVisibility); - if (view.getVisibility() != View.GONE) { - view.setVisibility(View.GONE); - } - } - - private void keepForcedHiddenViewsHidden() { - if (forcedHiddenViews.isEmpty()) { - return; - } - ArrayDeque staleViews = new ArrayDeque<>(); - for (View view : forcedHiddenViews) { - if (view == null || !view.isAttachedToWindow()) { - staleViews.add(view); - continue; - } - if (view.getVisibility() != View.GONE) { - view.setVisibility(View.GONE); - } - } - while (!staleViews.isEmpty()) { - forcedHiddenViews.remove(staleViews.removeFirst()); - } - } - - private void restoreForcedHiddenViews() { - if (forcedHiddenViews.isEmpty()) { - return; - } - ArrayDeque views = new ArrayDeque<>(forcedHiddenViews); - while (!views.isEmpty()) { - restoreIfForcedHidden(views.removeFirst()); - } - } - - private void markForcedHidden(View view, int restoreVisibility) { - instanceStateStore.put(view, FIELD_PREV_VIS, restoreVisibility); - instanceStateStore.put(view, FIELD_FORCED_HIDDEN, Boolean.TRUE); - forcedHiddenViews.add(view); - } - - private void restoreIfForcedHidden(View view) { - if (!isForcedHidden(view)) { - return; - } - Object previous = instanceStateStore.get(view, FIELD_PREV_VIS); - int restoreVisibility = previous instanceof Integer integer ? integer : View.VISIBLE; - instanceStateStore.remove(view, FIELD_FORCED_HIDDEN); - instanceStateStore.remove(view, FIELD_PREV_VIS); - forcedHiddenViews.remove(view); - if (view.getVisibility() != restoreVisibility) { - view.setVisibility(restoreVisibility); - } - if (restoreVisibility == View.VISIBLE && view.getAlpha() == 0f) { - view.setAlpha(1f); - } - } - - private boolean isForcedHidden(View view) { - Object marker = instanceStateStore.get(view, FIELD_FORCED_HIDDEN); - return marker instanceof Boolean bool && bool; - } - - private boolean isSystemUiView(View view) { - return className(view).contains("systemui"); - } - - private boolean looksLikeChipGeometry(View view) { - if (view == null || view.getWidth() <= 0 || view.getHeight() <= 0) { - return false; - } - int width = view.getWidth(); - int height = view.getHeight(); - int screenWidth = view.getResources().getDisplayMetrics().widthPixels; - if (height < dp(view, 18) || height > dp(view, 160)) { - return false; - } - if (width < height * 2) { - return false; - } - return !(width > (int) (screenWidth * 0.95f) && height < dp(view, 110)); - } - - private boolean isDefinitelyNotChipClass(String lowerClass) { - return lowerClass.contains("clock") - || lowerClass.contains("date") - || lowerClass.contains("brightness") - || lowerClass.contains("tile") - || lowerClass.contains("qsbuttonscontainer") - || lowerClass.contains("sectionheaderview") - || lowerClass.contains("expandablenotificationrow") - || lowerClass.contains("carrier") - || lowerClass.contains("statusicon") - || lowerClass.contains("indicator") - || lowerClass.contains("launchabletextview") - || lowerClass.contains("qsshortendate") - || lowerClass.contains("qsclock") - || lowerClass.contains("quickqs"); - } - - private boolean isDefinitelyNotChipText(String lowerText) { - if (lowerText == null || lowerText.isEmpty()) { - return false; - } - return containsPhrase(lowerText, "notification settings") - || containsToken(lowerText, "brightness") - || containsToken(lowerText, "wifi") - || containsPhrase(lowerText, "smart view") - || containsToken(lowerText, "mirror"); - } - - private String className(View view) { - return view != null && view.getClass() != null ? view.getClass().getName() : ""; + return classifyKind(text, data.getClass().getName()); } private String textField(Object target, String fieldName) { @@ -766,44 +279,6 @@ final class StatusChipHider { return value != null ? String.valueOf(value) : ""; } - private boolean isOngoingActivityCapsule(View view) { - return ViewIdNames.hasIdName(view, "ongoing_activity_capsule"); - } - - private void appendText(StringBuilder out, CharSequence value) { - if (value == null || value.length() == 0 || out.length() >= MAX_TEXT_SCAN_LEN) { - return; - } - if (out.length() > 0) { - out.append(' '); - } - int remaining = MAX_TEXT_SCAN_LEN - out.length(); - if (value.length() > remaining) { - out.append(value, 0, remaining); - } else { - out.append(value); - } - } - - private void appendClassName(StringBuilder out, View view) { - if (view == null || out.length() >= MAX_CLASS_SCAN_LEN) { - return; - } - String value = className(view); - if (value.isEmpty()) { - return; - } - if (out.length() > 0) { - out.append(' '); - } - int remaining = MAX_CLASS_SCAN_LEN - out.length(); - if (value.length() > remaining) { - out.append(value, 0, remaining); - } else { - out.append(value); - } - } - private boolean containsAny(String value, String... needles) { if (value == null || value.isEmpty()) { return false; @@ -816,10 +291,6 @@ final class StatusChipHider { return false; } - private boolean containsPhrase(String value, String phrase) { - return value != null && phrase != null && value.contains(phrase); - } - private boolean containsToken(String value, String token) { if (value == null || value.isEmpty() || token == null || token.isEmpty()) { return false; @@ -850,10 +321,6 @@ final class StatusChipHider { return value != null && !value.isEmpty() && value.matches(".*\\b\\d+\\s*(m|km|mi|ft)\\b.*"); } - private int dp(View view, int dp) { - return Math.round(dp * view.getResources().getDisplayMetrics().density); - } - private boolean isKeyguardLocked() { try { Context context = SystemContextProvider.currentApplication(); @@ -876,4 +343,5 @@ final class StatusChipHider { } return keyguardManager; } + } diff --git a/app/src/main/java/se/ajpanton/statusbartweak/runtime/layout/LockscreenCardsNotificationRowFilter.java b/app/src/main/java/se/ajpanton/statusbartweak/runtime/layout/LockscreenCardsNotificationRowFilter.java index 1b01ada..b793abb 100644 --- a/app/src/main/java/se/ajpanton/statusbartweak/runtime/layout/LockscreenCardsNotificationRowFilter.java +++ b/app/src/main/java/se/ajpanton/statusbartweak/runtime/layout/LockscreenCardsNotificationRowFilter.java @@ -63,6 +63,10 @@ final class LockscreenCardsNotificationRowFilter { } } + boolean hasHiddenRows() { + return !hiddenRows.isEmpty(); + } + void suppressHiddenRows() { if (hiddenRows.isEmpty()) { return; diff --git a/app/src/main/java/se/ajpanton/statusbartweak/runtime/layout/StockLayoutCanvasController.java b/app/src/main/java/se/ajpanton/statusbartweak/runtime/layout/StockLayoutCanvasController.java index ab727de..08fcc3e 100644 --- a/app/src/main/java/se/ajpanton/statusbartweak/runtime/layout/StockLayoutCanvasController.java +++ b/app/src/main/java/se/ajpanton/statusbartweak/runtime/layout/StockLayoutCanvasController.java @@ -16,11 +16,13 @@ import android.widget.TextView; import java.lang.ref.WeakReference; import java.lang.reflect.Field; +import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; +import java.util.HashSet; import java.util.IdentityHashMap; import java.util.List; import java.util.Locale; @@ -42,6 +44,8 @@ import se.ajpanton.statusbartweak.runtime.render.AodStatusbarSourceStore; import se.ajpanton.statusbartweak.runtime.render.DebugBoundsOverlayController; import se.ajpanton.statusbartweak.runtime.render.LockscreenCardsNotificationIconSourceStore; import se.ajpanton.statusbartweak.runtime.render.LockscreenCardsNotificationStripRenderer; +import se.ajpanton.statusbartweak.runtime.notifications.NotificationActiveKeyStore; +import se.ajpanton.statusbartweak.runtime.notifications.NotificationUnreadTracker; import se.ajpanton.statusbartweak.runtime.render.OwnedIconHostManager; import se.ajpanton.statusbartweak.runtime.render.UnlockedIconSnapshotRenderController; import se.ajpanton.statusbartweak.runtime.render.UnlockedIconSnapshotRenderController.RenderResult; @@ -94,19 +98,7 @@ final class StockLayoutCanvasController { "notification_icon_area_inner", "notificationIcons" ); - - private static final Set LAYOUT_OFF_EXTRA_RECOVERABLE_IDS = Set.of( - "system_icon_area", - "statusIcons", - "battery" - ); - - private static final Set LAYOUT_OFF_RECOVERABLE_CLASS_SUBSTRINGS = Set.of( - "NotificationIconContainer", - "StatusIconContainer", - "BatteryMeterView", - "QSClockIndicatorView" - ); + private static final int STATUS_BAR_STATE_SHADE_LOCKED = 2; private final RuntimeContext runtimeContext; private final Map hiddenViewStates = new WeakHashMap<>(); @@ -172,6 +164,7 @@ final class StockLayoutCanvasController { private boolean hooksInstalled; private int ownHiddenViewAlphaWriteDepth; + private boolean notificationDrawerWasOpen; StockLayoutCanvasController(RuntimeContext runtimeContext) { this.runtimeContext = runtimeContext; @@ -184,6 +177,8 @@ final class StockLayoutCanvasController { new LockscreenCardsNotificationStripRenderer(); unlockedIconRenderController = new UnlockedIconSnapshotRenderController(); runtimeContext.getModeStateRepository().addSceneListener(this::scheduleSceneRefresh); + runtimeContext.getModeStateRepository().addSystemUiStatusBarStateListener( + this::handleSystemUiStatusBarStateChanged); } void install(ClassLoader classLoader) { @@ -194,12 +189,147 @@ final class StockLayoutCanvasController { installCardsNotificationIconSourceHook(classLoader); installLockscreenCardsNotificationRowFilterHook(classLoader); installUnlockedAppearanceInvalidationHooks(classLoader); + installNotificationCollectionHooks(classLoader); statusIconModelTracker.installHooks(classLoader); + installShadeExpansionHooks(classLoader); installShadeHeaderAnimationGuardHook(classLoader); installViewRootHook(classLoader); hooksInstalled = true; } + private void installNotificationCollectionHooks(ClassLoader classLoader) { + for (String className : List.of( + "com.android.systemui.statusbar.notification.collection.NotifCollection", + "com.android.systemui.statusbar.notification.NotificationEntryManager")) { + Class type = ReflectionSupport.findClassIfExists(className, classLoader); + if (type == null) { + continue; + } + for (Method method : type.getDeclaredMethods()) { + String lowerName = method.getName().toLowerCase(Locale.ROOT); + if (!isNotificationCollectionMutationMethod(lowerName)) { + continue; + } + method.setAccessible(true); + runtimeContext.getFramework().hook(method).intercept(chain -> { + Object result = chain.proceed(); + refreshActiveNotificationKeysFromCollection(chain.getThisObject()); + return result; + }); + } + } + } + + private boolean isNotificationCollectionMutationMethod(String lowerName) { + boolean subject = lowerName.contains("notification") + || lowerName.contains("notif") + || lowerName.contains("entry"); + boolean mutation = lowerName.contains("add") + || lowerName.contains("post") + || lowerName.contains("update") + || lowerName.contains("remove") + || lowerName.contains("dismiss") + || lowerName.contains("cancel") + || lowerName.contains("cleanup") + || lowerName.contains("clean") + || lowerName.contains("clear"); + return subject + && mutation + && !lowerName.contains("listener") + && !lowerName.contains("lifetime") + && !lowerName.contains("interceptor"); + } + + private void installShadeExpansionHooks(ClassLoader classLoader) { + for (String className : List.of( + "com.android.systemui.shade.ShadeExpansionStateManager", + "com.android.systemui.shade.NotificationPanelViewController", + "com.android.systemui.statusbar.phone.NotificationPanelViewController")) { + Class type = ReflectionSupport.findClassIfExists(className, classLoader); + if (type == null) { + continue; + } + for (Method method : type.getDeclaredMethods()) { + String lowerName = method.getName().toLowerCase(Locale.ROOT); + if (!lowerName.contains("expansion") && !lowerName.contains("expandedheight")) { + continue; + } + method.setAccessible(true); + runtimeContext.getFramework().hook(method).intercept(chain -> { + Object result = chain.proceed(); + handleShadeExpansionHookCall(chain.getThisObject(), chain.getArgs()); + return result; + }); + } + } + } + + private void handleShadeExpansionHookCall(Object target, List args) { + SceneKey activeScene = runtimeContext.getModeStateRepository().getActiveScene(); + if (activeScene == null || !activeScene.isUnlocked()) { + return; + } + Float expansion = firstExpansionFraction(args); + if (expansion == null) { + expansion = reflectedExpansion(target); + } + if (expansion == null) { + return; + } + if (expansion <= 0.01f) { + notificationDrawerWasOpen = false; + return; + } + if (expansion <= 0.05f) { + return; + } + markNotificationDrawerSeen(); + } + + private Float firstExpansionFraction(List args) { + if (args == null || args.isEmpty()) { + return null; + } + for (Object arg : args) { + Float value = fractionValue(arg); + if (value == null) { + value = reflectedFraction(arg); + } + if (value != null) { + return value; + } + } + return null; + } + + private void markNotificationDrawerSeen() { + if (notificationDrawerWasOpen) { + return; + } + notificationDrawerWasOpen = true; + boolean changed = NotificationUnreadTracker.markSeen(); + if (changed) { + scheduleUnlockedAppearanceRefreshForAllRoots(); + } + } + + private void handleSystemUiStatusBarStateChanged( + int previousState, + int currentState, + boolean dozing + ) { + if (dozing) { + return; + } + if (currentState == STATUS_BAR_STATE_SHADE_LOCKED + && previousState != STATUS_BAR_STATE_SHADE_LOCKED) { + markNotificationDrawerSeen(); + } else if (previousState == STATUS_BAR_STATE_SHADE_LOCKED + && currentState != STATUS_BAR_STATE_SHADE_LOCKED) { + notificationDrawerWasOpen = false; + } + } + private void installShadeHeaderAnimationGuardHook(ClassLoader classLoader) { Class viewClass = ReflectionSupport.requireClass("android.view.View", classLoader); XposedHookSupport.hookAllMethodsIfExists(runtimeContext.getFramework(), viewClass, "setAlpha", chain -> { @@ -494,6 +624,9 @@ final class StockLayoutCanvasController { methodName, chain -> { ViewGroup parent = chain.getThisObject() instanceof ViewGroup group ? group : null; + if (parent != null && !isLayoutEnabled(parent.getContext())) { + return chain.proceed(); + } View child = firstArg(chain.getArgs()) instanceof View view ? view : null; View rootBefore = parent != null ? unlockedStatusBarRootFor(parent) : null; boolean affectedBefore = isStatusChipTreeMutation(parent, child); @@ -541,17 +674,21 @@ final class StockLayoutCanvasController { return chain.proceed(); } if (!isLayoutEnabled(container.getContext())) { - Object result = chain.proceed(); - LockscreenCardsNotificationIconSourceStore.put(container, new ArrayList<>()); - return result; - } - if (!isCardsNotificationIconSourceContainer(container)) { - Object result = chain.proceed(); - markUnlockedLayoutDirty(container); - return result; + return chain.proceed(); } @SuppressWarnings("unchecked") Function original = (Function) args.get(functionIndex); + if (!isCardsNotificationIconSourceContainer(container)) { + Function wrapped = entryObj -> { + recordNotificationEntry(entryObj); + return original.apply(entryObj); + }; + Object[] newArgs = args.toArray(new Object[0]); + newArgs[functionIndex] = wrapped; + Object result = chain.proceed(newArgs); + requestUnlockedLayoutRefreshFromSource(container); + return result; + } ArrayList captured = new ArrayList<>(); Function wrapped = entryObj -> { @@ -563,6 +700,7 @@ final class StockLayoutCanvasController { return null; } Object result = original.apply(entryObj); + recordNotificationEntry(entryObj); if (result == null) { result = fallbackStatusBarIcon(entryObj); } @@ -578,6 +716,7 @@ final class StockLayoutCanvasController { newArgs[functionIndex] = wrapped; Object result = chain.proceed(newArgs); LockscreenCardsNotificationIconSourceStore.put(container, captured); + requestUnlockedLayoutRefreshFromSource(container); return result; }); } @@ -711,11 +850,39 @@ final class StockLayoutCanvasController { private void captureAodPackagesFromNotifCollection(Object wrapper) { Object collection = ReflectionSupport.getFieldValue(wrapper, "mNotifCollection"); - ArrayList notifications = notificationsFromNotifCollection(collection); - if (notifications.isEmpty()) { + if (collection == null) { return; } + ArrayList notifications = notificationsFromNotifCollection(collection); + if (notifications.isEmpty()) { + latestAodNotifications = new ArrayList<>(); + latestAodIconImageViews = new ArrayList<>(); + NotificationActiveKeyStore.replace(Collections.emptySet()); + NotificationUnreadTracker.retainActiveKeys(Collections.emptySet()); + LockscreenCardsNotificationIconSourceStore.clearAodSources(); + markKnownAodNotificationRootsDirty(); + updateKnownAodNotificationSources(); + return; + } + boolean changed = false; + ArrayList packages = new ArrayList<>(); + HashSet activeKeys = new HashSet<>(); + for (StatusBarNotification sbn : notifications) { + changed |= NotificationUnreadTracker.record(sbn); + if (sbn != null && sbn.getKey() != null) { + activeKeys.add(sbn.getKey()); + } + if (sbn != null && AppIconRules.isValidPackageName(sbn.getPackageName())) { + packages.add(sbn.getPackageName()); + } + } + updateActiveNotificationKeys(activeNotificationIconKeys(notifications)); + changed |= NotificationUnreadTracker.retainActiveKeys(activeKeys); + LockscreenCardsNotificationIconSourceStore.putAodNotificationPackages(packages); latestAodNotifications = notifications; + if (changed) { + markKnownAodNotificationRootsDirty(); + } updateKnownAodNotificationSources(); } @@ -787,6 +954,52 @@ final class StockLayoutCanvasController { notifications.add(sbn); } + private boolean recordNotificationEntry(Object entry) { + StatusBarNotification sbn = NotificationReflection.statusBarNotificationEntry(entry); + return NotificationUnreadTracker.record(sbn); + } + + private void refreshActiveNotificationKeysFromCollection(Object collection) { + ArrayList notifications = notificationsFromNotifCollection(collection); + if (notifications.isEmpty()) { + return; + } + for (StatusBarNotification sbn : notifications) { + if (sbn != null && sbn.getKey() != null && AppIconRules.isValidPackageName(sbn.getPackageName())) { + NotificationUnreadTracker.record(sbn); + } + } + updateActiveNotificationKeys(activeNotificationIconKeys(notifications)); + } + + private void updateActiveNotificationKeys(ArrayList keys) { + if (!NotificationActiveKeyStore.replace(keys)) { + return; + } + requestUnlockedLayoutRefreshForAllRoots(); + markKnownAodNotificationRootsDirty(); + } + + private ArrayList activeNotificationIconKeys(ArrayList notifications) { + ArrayList keys = new ArrayList<>(); + if (notifications == null) { + return keys; + } + for (StatusBarNotification sbn : notifications) { + if (sbn == null || !AppIconRules.isValidPackageName(sbn.getPackageName())) { + continue; + } + if (sbn.getKey() != null) { + keys.add(sbn.getKey()); + } + String packageName = sbn.getPackageName(); + int id = sbn.getId(); + keys.add(packageName + "/" + id); + keys.add(packageName + "/0x" + Integer.toHexString(id)); + } + return keys; + } + private void installViewRootHook(ClassLoader classLoader) { Class viewRootClass = ReflectionSupport.requireClass("android.view.ViewRootImpl", classLoader); XposedHookSupport.hookAllMethods(runtimeContext.getFramework(), viewRootClass, "performDraw", chain -> { @@ -838,6 +1051,9 @@ final class StockLayoutCanvasController { if (activeScene == null) { return; } + if (!runtimeContext.getModeStateRepository().isSystemUiShadeLocked() && !activeScene.isAod()) { + notificationDrawerWasOpen = false; + } if (isNotificationShadeWindowRoot(root)) { if (shouldPrepareCarrierlessAodNotificationTransition(settings, activeScene)) { prepareCarrierlessAodNotificationTransition(root); @@ -848,12 +1064,14 @@ final class StockLayoutCanvasController { if (activeScene.isLockscreen() && activeScene.notificationDisplayStyle() == NotificationDisplayStyle.CARDS && isNotificationShadeWindowRoot(root)) { - applyLockscreenCardsNotificationRowFilterInTreeIfNeeded( + boolean applied = applyLockscreenCardsNotificationRowFilterInTreeIfNeeded( root, settings, activeScene, true); - lockscreenCardsNotificationRowFilter.suppressHiddenRows(); + if (!applied && lockscreenCardsNotificationRowFilter.hasHiddenRows()) { + lockscreenCardsNotificationRowFilter.suppressHiddenRows(); + } } else if (activeScene.isUnlocked() && isNotificationShadeWindowRoot(root)) { lockscreenCardsNotificationRowFilter.restoreAll(); } else if (activeScene.isAod() @@ -862,6 +1080,98 @@ final class StockLayoutCanvasController { } } + private Float reflectedExpansion(Object target) { + for (String method : List.of( + "getExpandedFraction", + "getExpansionFraction", + "getPanelExpansion", + "getShadeExpansion")) { + Float value = floatValue(ReflectionSupport.invokeMethod(target, method)); + if (value != null) { + return value; + } + } + for (String field : List.of( + "mExpandedFraction", + "mExpansionFraction", + "mPanelExpansionFraction", + "mShadeExpansion")) { + Float value = floatValue(ReflectionSupport.getFieldValue(target, field)); + if (value != null) { + return value; + } + } + Float height = heightValue(ReflectionSupport.invokeMethod(target, "getExpandedHeight")); + if (height == null) { + height = heightValue(ReflectionSupport.getFieldValue(target, "mExpandedHeight")); + } + if (height != null && target instanceof View view && view.getHeight() > 0) { + return Math.min(1f, Math.max(0f, height / view.getHeight())); + } + return null; + } + + private Float reflectedFraction(Object target) { + for (String method : List.of( + "getFraction", + "getExpandedFraction", + "getExpansionFraction", + "getPanelExpansion", + "getShadeExpansion")) { + Float value = fractionValue(ReflectionSupport.invokeMethod(target, method)); + if (value != null) { + return value; + } + } + for (String field : List.of( + "fraction", + "expandedFraction", + "expansionFraction", + "panelExpansionFraction", + "shadeExpansion")) { + Float value = fractionValue(ReflectionSupport.getFieldValue(target, field)); + if (value != null) { + return value; + } + } + return null; + } + + private Float floatValue(Object value) { + return fractionValue(value); + } + + private Float fractionValue(Object value) { + if (value instanceof Float floatValue) { + return fraction(floatValue); + } + if (value instanceof Double doubleValue) { + return fraction(doubleValue.floatValue()); + } + return null; + } + + private Float heightValue(Object value) { + if (value instanceof Number number) { + float floatValue = number.floatValue(); + if (Float.isNaN(floatValue) || Float.isInfinite(floatValue) || floatValue < 0f) { + return null; + } + return floatValue; + } + return null; + } + + private Float fraction(float value) { + if (Float.isNaN(value) || Float.isInfinite(value)) { + return null; + } + if (value < 0f || value > 1f) { + return null; + } + return value; + } + private void applyBeforeDrawInternal(View root) { if (root == null) { return; @@ -894,11 +1204,13 @@ final class StockLayoutCanvasController { && activeScene.isLockscreen() && activeScene.notificationDisplayStyle() == NotificationDisplayStyle.CARDS && canContainLockedStatusBarIconSurfaces(root)) { - applyLockscreenCardsNotificationRowFilterInTreeIfNeeded( - root, - settings, - activeScene, - isNotificationShadeWindowRoot(root)); + if (isNotificationShadeWindowRoot(root)) { + applyLockscreenCardsNotificationRowFilterInTreeIfNeeded( + root, + settings, + activeScene, + true); + } renderLockscreenCardsNotificationStripIfNeeded(root, settings, activeScene); } else if (activeScene != null && activeScene.isAod() @@ -943,10 +1255,29 @@ final class StockLayoutCanvasController { if (root != null) { dirtyUnlockedLayoutRoots.add(root); } + View current = sourceView; + while (current != null) { + if (isUnlockedStatusBarRoot(current)) { + dirtyUnlockedLayoutRoots.add(current); + } + Object parent = current.getParent(); + current = parent instanceof View ? (View) parent : null; + } } - private void markStatusChipLifecycleDirtyIfNeeded(View view) { - markStatusChipLifecycleDirtyIfNeeded(view, null); + private void requestUnlockedLayoutRefreshFromSource(View sourceView) { + View root = unlockedStatusBarRootFor(sourceView); + if (root != null) { + requestUnlockedLayoutRefresh(root); + } + View current = sourceView; + while (current != null) { + if (current != root && isUnlockedStatusBarRoot(current)) { + requestUnlockedLayoutRefresh(current); + } + Object parent = current.getParent(); + current = parent instanceof View ? (View) parent : null; + } } private void markStatusChipLifecycleDirtyIfNeeded(View view, View fallbackRoot) { @@ -991,9 +1322,9 @@ final class StockLayoutCanvasController { && activeScene.isUnlocked() && areUnlockedHostsAttached(root, unlockedHosts) && unlockedIconRenderController.refreshUnlockedChipContent( - root, - unlockedHosts.chipHost, - activeScene)) { + root, + unlockedHosts.chipHost, + activeScene)) { bringUnlockedHostsAndDebugOverlayToFront(root); return; } @@ -1189,6 +1520,18 @@ final class StockLayoutCanvasController { } } + private void requestUnlockedLayoutRefreshForAllRoots() { + ArrayList roots = new ArrayList<>(rootGeometries.keySet()); + for (View root : new ArrayList<>(unlockedHostsByRoot.keySet())) { + if (!roots.contains(root)) { + roots.add(root); + } + } + for (View root : roots) { + requestUnlockedLayoutRefresh(root); + } + } + private void scheduleSceneRefresh(SceneKey previous, SceneKey current) { if (previous == null || current == null || previous.equals(current)) { return; @@ -1436,7 +1779,7 @@ final class StockLayoutCanvasController { return; } UnlockedHosts unlockedHosts = updateUnlockedOwnedHosts(root, activeScene); - RenderResult renderResult = new RenderResult(false, false); + RenderResult renderResult = new RenderResult(false, false, false); if (unlockedHosts != null && (unlockedScene || activeScene != null && activeScene.isLockscreen() @@ -1456,6 +1799,7 @@ final class StockLayoutCanvasController { unlockedHosts.statusHost, unlockedHosts.notificationHost, activeScene, + rootDirty, lockedCarrierTextSource()); boolean shouldShowUnlockedHosts = unlockedScene || aodScene || renderResult.shouldOwnLockscreen(); ownedIconHostManager.setUnlockedHostsVisible(root, shouldShowUnlockedHosts); @@ -1532,9 +1876,35 @@ final class StockLayoutCanvasController { } else { removeDebugOverlay(root); } + if (isLayoutOffCleanupNoOp(root)) { + return; + } cleanupLayoutOffRoot(root, activeScene); } + private boolean isLayoutOffCleanupNoOp(View root) { + return hiddenViewStates.isEmpty() + && trackedStatusChipSources.isEmpty() + && trackedUnlockedStockSurfaces.isEmpty() + && trackedLockedStatusBarIconSurfaces.isEmpty() + && !lockscreenCardsNotificationRowFilter.hasHiddenRows() + && !unlockedHostsByRoot.containsKey(root) + && !hasDirectOwnedLayoutHost(root); + } + + private boolean hasDirectOwnedLayoutHost(View root) { + if (!(root instanceof ViewGroup group)) { + return false; + } + return findDirectOwnedHost(group, OwnedIconHostManager.TAG_UNLOCKED_STATUS_HOST) != null + || findDirectOwnedHost(group, OwnedIconHostManager.TAG_UNLOCKED_NOTIFICATION_HOST) != null + || findDirectOwnedHost(group, OwnedIconHostManager.TAG_UNLOCKED_CLOCK_HOST) != null + || findDirectOwnedHost(group, OwnedIconHostManager.TAG_UNLOCKED_CARRIER_HOST) != null + || findDirectOwnedHost(group, OwnedIconHostManager.TAG_UNLOCKED_CHIP_HOST) != null + || findDirectOwnedHost(group, OwnedIconHostManager.TAG_LOCKSCREEN_CARDS_NOTIFICATION_HOST) != null + || findDirectOwnedHost(group, OwnedIconHostManager.TAG_AOD_CARDS_NOTIFICATION_HOST) != null; + } + private void applyDebugOverlay( View root, boolean layoutEnabled, @@ -2113,7 +2483,8 @@ final class StockLayoutCanvasController { private boolean shouldSuppressTrackedStatusChipVisibility(View view, int visibility) { return visibility != View.VISIBLE && isTrackedStatusChipWriteTarget(view) - && hasVisibleStatusChipContent(view); + && hasVisibleStatusChipContent(view) + && !isCallStatusChip(view); } private boolean isTrackedStatusChipWriteTarget(View view) { @@ -2528,6 +2899,43 @@ final class StockLayoutCanvasController { return false; } + private boolean isCallStatusChip(View source) { + if (source == null) { + return false; + } + ArrayDeque queue = new ArrayDeque<>(); + queue.add(source); + int scanned = 0; + while (!queue.isEmpty() && scanned++ < 48) { + View view = queue.removeFirst(); + String className = view.getClass().getName().toLowerCase(Locale.ROOT); + String idName = ViewIdNames.idName(view).toLowerCase(Locale.ROOT); + if (className.contains("call") || idName.contains("call")) { + return true; + } + if (containsCallToken(view.getContentDescription())) { + return true; + } + if (view instanceof TextView textView && containsCallToken(textView.getText())) { + return true; + } + if (view instanceof ViewGroup childGroup) { + for (int i = 0; i < childGroup.getChildCount(); i++) { + queue.addLast(childGroup.getChildAt(i)); + } + } + } + return false; + } + + private boolean containsCallToken(CharSequence value) { + if (value == null || value.length() == 0) { + return false; + } + String text = value.toString().toLowerCase(Locale.ROOT); + return text.contains("call") || text.contains("phone"); + } + private boolean isStatusChipCandidate(View view) { String className = view.getClass().getName().toLowerCase(Locale.ROOT); String idName = ViewIdNames.idName(view).toLowerCase(Locale.ROOT); @@ -2798,16 +3206,7 @@ final class StockLayoutCanvasController { LockscreenCardsNotificationIconSourceStore.clearAodSources(container); return; } - boolean changed = false; - ArrayList packages = alignedAodIconPackages(container.getContext()); - if (!packages.isEmpty()) { - changed |= LockscreenCardsNotificationIconSourceStore.putPackages(container, packages); - } - boolean prepared = prepareAodNotificationIconSources(container); - changed |= prepared; - changed |= LockscreenCardsNotificationIconSourceStore.putAodDrawables( - container, - latestAodIconImageViews); + boolean changed = refreshAodNotificationSources(container); knownAodNotificationContainers.add(container); if (changed) { View root = container.getRootView(); @@ -2827,16 +3226,7 @@ final class StockLayoutCanvasController { LockscreenCardsNotificationIconSourceStore.clearAodSources(container); continue; } - ArrayList packages = alignedAodIconPackages(container.getContext()); - boolean changed = false; - if (!packages.isEmpty()) { - changed |= LockscreenCardsNotificationIconSourceStore.putPackages(container, packages); - } - boolean prepared = prepareAodNotificationIconSources(container); - changed |= prepared; - changed |= LockscreenCardsNotificationIconSourceStore.putAodDrawables( - container, - latestAodIconImageViews); + boolean changed = refreshAodNotificationSources(container); if (changed) { View root = container.getRootView(); invalidateAodNotificationRoot(root); @@ -2844,10 +3234,24 @@ final class StockLayoutCanvasController { } } + private boolean refreshAodNotificationSources(ViewGroup container) { + ArrayList packages = alignedAodIconPackages(container.getContext()); + if (packages.isEmpty() && isAodDotScene()) { + packages = aodNotificationPackages(); + } + boolean changed = false; + if (!packages.isEmpty()) { + changed |= LockscreenCardsNotificationIconSourceStore.putPackages(container, packages); + } + changed |= prepareAodNotificationIconSources(container); + changed |= LockscreenCardsNotificationIconSourceStore.putAodDrawables( + container, + latestAodIconImageViews); + return changed; + } + private boolean prepareAodNotificationIconSources(ViewGroup container) { - if (container == null - || latestAodIconImageViews == null - || latestAodIconImageViews.isEmpty()) { + if (container == null || latestAodIconImageViews.isEmpty()) { return false; } boolean invoked = false; @@ -2867,9 +3271,25 @@ final class StockLayoutCanvasController { return invoked; } + private boolean isAodDotScene() { + SceneKey scene = runtimeContext.getModeStateRepository().getActiveScene(); + return scene != null + && scene.isAod() + && scene.notificationDisplayStyle() == NotificationDisplayStyle.DOT; + } + + private ArrayList aodNotificationPackages() { + ArrayList result = new ArrayList<>(); + for (StatusBarNotification sbn : latestAodNotifications) { + if (sbn != null && AppIconRules.isValidPackageName(sbn.getPackageName())) { + result.add(sbn.getPackageName()); + } + } + return result; + } + private ArrayList alignedAodIconPackages(Context context) { - int imageCount = latestAodIconImageViews != null ? latestAodIconImageViews.size() : 0; - if (imageCount <= 0) { + if (latestAodIconImageViews.isEmpty()) { return new ArrayList<>(); } ArrayList aligned = alignAodPackagesByDrawable(context); @@ -2882,9 +3302,7 @@ final class StockLayoutCanvasController { private ArrayList alignAodPackagesByDrawable(Context context) { ArrayList aligned = new ArrayList<>(); if (context == null - || latestAodIconImageViews == null || latestAodIconImageViews.isEmpty() - || latestAodNotifications == null || latestAodNotifications.isEmpty()) { return aligned; } @@ -2989,6 +3407,20 @@ final class StockLayoutCanvasController { dirtyUnlockedLayoutRoots.add(root); } + private void markKnownAodNotificationRootsDirty() { + for (ViewGroup container : knownAodNotificationContainers) { + if (container == null || !container.isAttachedToWindow()) { + continue; + } + View root = container.getRootView(); + if (root != null) { + dirtyUnlockedLayoutRoots.add(root); + root.requestLayout(); + root.invalidate(); + } + } + } + private void markAodLayoutDirty(View view) { if (view == null || !view.isAttachedToWindow()) { return; @@ -3151,19 +3583,19 @@ final class StockLayoutCanvasController { return true; } - private void restoreAllHiddenViews() { + private void restoreAllHiddenViews(View root, SceneKey activeScene) { ArrayDeque views = new ArrayDeque<>(hiddenViewStates.keySet()); while (!views.isEmpty()) { View view = views.removeFirst(); if (forgetInactiveTrackedStatusChip(view)) { continue; } + if (shouldDeferLayoutOffRestore(root, activeScene, view)) { + keepViewHidden(view); + continue; + } restoreView(view); } - trackedStatusChipSources.clear(); - trackedLockedStatusBarIconSurfaces.clear(); - trackedUnlockedStockSurfaces.clear(); - aodPluginVisualAlphaByView.clear(); } private boolean forgetInactiveTrackedStatusChip(View view) { @@ -3176,16 +3608,16 @@ final class StockLayoutCanvasController { hiddenViewStates.remove(view); trackedStatusChipSources.remove(view); trackedUnlockedStockSurfaces.remove(view); + statusChipLifecycleLayoutSignatureByView.remove(view); return true; } private void cleanupLayoutOffRoot(View root, SceneKey activeScene) { lockscreenCardsNotificationRowFilter.restoreAll(); if (!hiddenViewStates.isEmpty()) { - restoreAllHiddenViews(); + restoreAllHiddenViews(root, activeScene); } - restoreLayoutOffStockSurfaces(root, activeScene); - trackedStatusChipSources.clear(); + clearTrackedStatusChipState(); trackedLockedStatusBarIconSurfaces.clear(); trackedUnlockedStockSurfaces.clear(); confirmedAodPluginViews.clear(); @@ -3219,63 +3651,38 @@ final class StockLayoutCanvasController { ownedIconHostManager.removeOwnedHosts(root); } - private void restoreLayoutOffStockSurfaces(View root, SceneKey activeScene) { - if (root == null || !isViewThread(root)) { - return; - } - boolean unlockedScene = activeScene == null || activeScene.isUnlocked(); - walkTree(root, view -> { - if (!isLayoutOffRecoverableStockSurface(view)) { - return; - } - String idName = ViewIdNames.idName(view); - int beforeVisibility = view.getVisibility(); - float beforeAlpha = view.getAlpha(); - restoreView(view); - if (!unlockedScene && LAYOUT_OFF_UNLOCKED_ONLY_IDS.contains(idName)) { - if (view.getAlpha() != 0f) { - view.setAlpha(0f); - } - if (view.getVisibility() != View.INVISIBLE) { - view.setVisibility(View.INVISIBLE); - } - return; - } - if (unlockedScene && view.getVisibility() != View.VISIBLE) { - view.setVisibility(View.VISIBLE); - } - if (shouldPreserveUnlockedStockAlpha(idName, beforeVisibility, beforeAlpha)) { - if (view.getAlpha() != beforeAlpha) { - view.setAlpha(beforeAlpha); - } - return; - } - if (unlockedScene && view.getAlpha() <= 0f) { - view.setAlpha(1f); - } - }); - } - - private boolean shouldPreserveUnlockedStockAlpha( - String idName, - int beforeVisibility, - float beforeAlpha + private boolean shouldDeferLayoutOffRestore( + View root, + SceneKey activeScene, + View view ) { - if (!"notification_icon_area_inner".equals(idName)) { - return false; - } - return beforeVisibility == View.VISIBLE && beforeAlpha < 1f; + return shouldKeepUnlockedShadeShelfOwnedByCustomLayout(root, activeScene, view); } - private boolean isLayoutOffRecoverableStockSurface(View view) { - if (view == null || ownedIconHostManager.isOwnedHost(view)) { + private void keepViewHidden(View view) { + hideView(view, false); + } + + private boolean shouldKeepUnlockedShadeShelfOwnedByCustomLayout( + View root, + SceneKey activeScene, + View view + ) { + if (root == null + || activeScene == null + || !activeScene.isUnlocked() + || !isDescendantOfNotificationShadeWindow(view)) { return false; } - String idName = ViewIdNames.idName(view); - String className = view.getClass().getName(); - return LAYOUT_OFF_UNLOCKED_ONLY_IDS.contains(idName) - || LAYOUT_OFF_EXTRA_RECOVERABLE_IDS.contains(idName) - || containsAny(className, LAYOUT_OFF_RECOVERABLE_CLASS_SUBSTRINGS); + return (isCardsNotificationIconSurface(view) || isCardsNotificationShelfBackgroundSurface(view)) + && hasAncestorClass(view, "NotificationShelf"); + } + + private void clearTrackedStatusChipState() { + trackedStatusChipSources.clear(); + statusChipContentSignatureByRoot.clear(); + statusChipLayoutSignatureByRoot.clear(); + statusChipLifecycleLayoutSignatureByView.clear(); } private static boolean containsAny(String value, Set tokens) { @@ -3395,11 +3802,20 @@ final class StockLayoutCanvasController { generation = 31 * generation + latestAodNotifications.size(); Bounds sourceBounds = LockscreenCardsNotificationIconSourceStore .sourceContainerBoundsForRoot(root); + boolean hiddenSource = LockscreenCardsNotificationIconSourceStore + .sourceContainerHasHiddenAncestorForRoot(root); + if (hiddenSource) { + // Samsung hides the cards icon source during the clock/date handoff. + // Keep our mirror hidden too instead of following its transient translation. + setHostAlpha(host, 0f); + return; + } generation = 31 * generation + (sourceBounds != null ? sourceBounds.signature() : 0); Integer previous = aodCardsNotificationRenderGenerationByRoot.get(root); + boolean dirty = dirtyUnlockedLayoutRoots.contains(root); boolean shouldRender = previous == null || previous != generation - || dirtyUnlockedLayoutRoots.contains(root) + || dirty || hostGroup.getChildCount() <= 0; if (shouldRender) { aodCardsNotificationRenderGenerationByRoot.put(root, generation); @@ -3421,7 +3837,7 @@ final class StockLayoutCanvasController { lockscreenCardsNotificationRowFilter.apply(stack, allowAfterKeyguardUnlock); } - private void applyLockscreenCardsNotificationRowFilterInTreeIfNeeded( + private boolean applyLockscreenCardsNotificationRowFilterInTreeIfNeeded( View root, SbtSettings settings, SceneKey activeScene, @@ -3429,9 +3845,10 @@ final class StockLayoutCanvasController { int signature = lockscreenCardsRowFilterSignature(root, settings, activeScene); Integer previous = lockscreenCardsRowFilterSignatures.put(root, signature); if (previous != null && previous == signature) { - return; + return false; } applyLockscreenCardsNotificationRowFilterInTree(root, allowAfterKeyguardUnlock); + return true; } private int lockscreenCardsRowFilterSignature( @@ -3620,11 +4037,13 @@ final class StockLayoutCanvasController { } NotificationDisplayStyle notificationStyle = SystemNotificationDisplayStyleDetector.read(context); - if (isAodRoot(root) || (isKeyguardLocked(context) && !isInteractive(context))) { + boolean keyguardLocked = isKeyguardLocked(context); + boolean interactive = isInteractive(context); + if (isAodRoot(root) || (keyguardLocked && !interactive)) { runtimeContext.getModeStateRepository().setAod(notificationStyle); return; } - if (isKeyguardLocked(context)) { + if (keyguardLocked) { runtimeContext.getModeStateRepository().setLockscreen(notificationStyle); return; } diff --git a/app/src/main/java/se/ajpanton/statusbartweak/runtime/layoutsolver/PackedStatusBarLayoutSolver.java b/app/src/main/java/se/ajpanton/statusbartweak/runtime/layoutsolver/PackedStatusBarLayoutSolver.java index c52ef64..f176515 100644 --- a/app/src/main/java/se/ajpanton/statusbartweak/runtime/layoutsolver/PackedStatusBarLayoutSolver.java +++ b/app/src/main/java/se/ajpanton/statusbartweak/runtime/layoutsolver/PackedStatusBarLayoutSolver.java @@ -798,7 +798,7 @@ public final class PackedStatusBarLayoutSolver { } } - public static void collisionTree(ArrayList items) { + private static void collisionTree(ArrayList items) { for (LayoutItem item : items) { for (Box box : item.boxes) { box.collisionLeft.clear(); @@ -1165,11 +1165,6 @@ public final class PackedStatusBarLayoutSolver { return oldWidth - width(); } - public void setPoolRemaining(int remaining) { - poolRemaining = Math.max(0, remaining); - recomputeIconState(); - } - public void setPoolIcons(ArrayList widths, int startIndex) { widthLimit = Math.min(currentWidthLimit(), width()); poolIconWidths = widths != null ? new ArrayList<>(widths) : new ArrayList<>(); diff --git a/app/src/main/java/se/ajpanton/statusbartweak/runtime/layoutsolver/StatusBarLayoutSolver.java b/app/src/main/java/se/ajpanton/statusbartweak/runtime/layoutsolver/StatusBarLayoutSolver.java index 005d543..db1fa85 100644 --- a/app/src/main/java/se/ajpanton/statusbartweak/runtime/layoutsolver/StatusBarLayoutSolver.java +++ b/app/src/main/java/se/ajpanton/statusbartweak/runtime/layoutsolver/StatusBarLayoutSolver.java @@ -1,668 +1,9 @@ package se.ajpanton.statusbartweak.runtime.layoutsolver; -import java.util.ArrayList; -import java.util.Collections; - public final class StatusBarLayoutSolver { - private static final int MIDDLE_COLLISION_MARGIN_PX = 2; - private StatusBarLayoutSolver() { } - public static ArrayList bandsForPosition( - ArrayList bands, - LayoutPosition position, - ArrayList itemOrder - ) { - ArrayList result = new ArrayList<>(); - for (LayoutItemKind kind : itemOrder) { - for (T band : bands) { - if (band.kind == kind - && band.position == position - && band.splitRegion == SplitRegion.NONE) { - result.add(band); - } - } - } - return result; - } - - public static ArrayList middleBandsForPlacement( - ArrayList bands, - ArrayList itemOrder, - AnchorSide side - ) { - ArrayList result = new ArrayList<>(); - SplitRegion sideRegion = side == AnchorSide.LEFT ? SplitRegion.LEFT : SplitRegion.RIGHT; - for (T band : bands) { - if (band.splitRegion == sideRegion) { - result.add(band); - } - } - result.addAll(bandsForPosition(bands, LayoutPosition.MIDDLE, itemOrder)); - return result; - } - - public static RegionPlan planRegions( - int rootWidth, - LayoutEdges edges, - ArrayList bands, - ArrayList itemOrder, - Bounds cutoutBounds, - int itemPadding - ) { - int leftEdge = Math.max(0, Math.min(rootWidth, edges.left)); - int rightEdge = Math.max(leftEdge, Math.min(rootWidth, edges.right)); - Region leftRegion; - Region rightRegion = null; - if (cutoutBounds == null) { - leftRegion = new Region<>(leftEdge, rightEdge); - } else { - leftRegion = new Region<>(leftEdge, Math.min(cutoutBounds.left, rightEdge)); - rightRegion = new Region<>( - Math.max(cutoutBounds.left + cutoutBounds.width, leftEdge), - rightEdge); - } - - ArrayList leftBands = bandsForPosition(bands, LayoutPosition.LEFT, itemOrder); - ArrayList middleBands = bandsForPosition(bands, LayoutPosition.MIDDLE, itemOrder); - ArrayList rightBands = bandsForPosition(bands, LayoutPosition.RIGHT, itemOrder); - AnchorSide middleSide = sideForMiddleRegion(rootWidth, middleBands, cutoutBounds, itemPadding); - if (rightRegion == null) { - addSplitRegionBands(bands, leftRegion, SplitRegion.LEFT); - addSplitRegionBands(bands, leftRegion, SplitRegion.RIGHT); - leftRegion.bands.addAll(leftBands); - leftRegion.bands.addAll(middleBands); - Collections.reverse(rightBands); - leftRegion.bands.addAll(rightBands); - } else { - leftRegion.bands.addAll(leftBands); - ArrayList middleRegionBands = new ArrayList<>(middleBands); - Collections.reverse(middleRegionBands); - if (middleSide == AnchorSide.LEFT) { - leftRegion.bands.addAll(middleRegionBands); - } - addSplitRegionBands(bands, leftRegion, SplitRegion.LEFT); - - addSplitRegionBands(bands, rightRegion, SplitRegion.RIGHT); - if (middleSide == AnchorSide.RIGHT) { - rightRegion.bands.addAll(middleRegionBands); - } - Collections.reverse(rightBands); - rightRegion.bands.addAll(rightBands); - } - - ArrayList> regions = new ArrayList<>(); - regions.add(leftRegion); - if (rightRegion != null) { - regions.add(rightRegion); - } - return new RegionPlan<>(regions, middleSide); - } - - private static void addSplitRegionBands( - ArrayList source, - Region target, - SplitRegion region - ) { - if (source == null || target == null || region == SplitRegion.NONE) { - return; - } - for (T band : source) { - if (band.splitRegion == region) { - target.bands.add(band); - } - } - } - - public static AnchorSide sideForMiddleRegion( - int rootWidth, - ArrayList middleBands, - Bounds cutoutBounds, - int itemPadding - ) { - int middle = rootWidth / 2; - if (middleBands == null || middleBands.isEmpty()) { - return cutoutBounds == null || cutoutBounds.left + cutoutBounds.width / 2 < middle - ? AnchorSide.RIGHT - : AnchorSide.LEFT; - } - T firstBand = middleBands.get(0); - int width = packedWidth(middleBands, itemPadding); - int cameraDistance = distanceFromMiddle(cutoutBounds, middle); - boolean centered = cutoutBounds != null - && cutoutBounds.left <= middle + MIDDLE_COLLISION_MARGIN_PX - && cutoutBounds.left + cutoutBounds.width >= middle - MIDDLE_COLLISION_MARGIN_PX; - if (cameraDistance < width / 2 && (centered || !firstBand.middleAutoNearestSide)) { - return firstBand.middleSide; - } - if (cutoutBounds == null || cutoutBounds.left + cutoutBounds.width / 2 < middle) { - return AnchorSide.RIGHT; - } - return AnchorSide.LEFT; - } - - public static Anchor anchorForMiddle( - int rootWidth, - ArrayList bands, - ArrayList placedBands, - Bounds cutoutBounds, - AnchorSide side, - int itemPadding - ) { - int middle = rootWidth / 2; - int width = packedWidth(bands, itemPadding); - if (coversMiddle(cutoutBounds, middle)) { - return obstacleAnchor(cutoutBounds, side, AnchorKind.WALL); - } - Bounds nearestItem = nearestPlacedBand(placedBands, middle); - int cameraDistance = distanceFromMiddle(cutoutBounds, middle); - int itemDistance = distanceFromMiddle(nearestItem, middle); - if (Math.min(cameraDistance, itemDistance) < width / 2) { - if (cameraDistance < itemDistance) { - return obstacleAnchor(cutoutBounds, side, AnchorKind.WALL); - } - return obstacleAnchor(nearestItem, side, AnchorKind.ITEM); - } - return middleAnchor(rootWidth, width, side); - } - - private static Anchor obstacleAnchor(Bounds obstacle, AnchorSide side, AnchorKind kind) { - if (obstacle == null) { - return new Anchor(0, side, kind); - } - int anchorPoint = side == AnchorSide.RIGHT ? obstacle.left + obstacle.width : obstacle.left; - return new Anchor(anchorPoint, side, kind); - } - - private static Anchor middleAnchor(int rootWidth, int width, AnchorSide side) { - int middle = rootWidth / 2; - if (side == AnchorSide.RIGHT) { - return new Anchor(middle - width / 2, AnchorSide.RIGHT, AnchorKind.CENTER); - } - return new Anchor(middle + width / 2, AnchorSide.LEFT, AnchorKind.CENTER); - } - - public static void placeStackedBands( - ArrayList bands, - Anchor anchor, - ArrayList placedBands, - String sortOrder, - boolean avoidPlacedBands, - int itemPadding - ) { - if (bands == null || bands.isEmpty()) { - return; - } - for (T band : bands) { - band.prepareForSide(anchor.side, sortOrder); - } - ArrayList> stackedBands = stackBands(bands, itemPadding); - int shift = avoidPlacedBands ? middleShift(stackedBands, anchor, placedBands, itemPadding) : 0; - for (StackedBand stackedBand : stackedBands) { - T band = stackedBand.band; - int wallDotSlack = anchor.kind == AnchorKind.WALL - && stackedBand.left == 0 - && shift == 0 - ? band.wallDotSlack(anchor.side) - : 0; - int left = stackedLeft(stackedBand, anchor, shift, wallDotSlack, itemPadding); - band.place(left); - ArrayList bounds = band.placedCollisionBounds(); - if (!bounds.isEmpty()) { - placedBands.add(new PlacedBand(band.kind, band.position, bounds)); - } - } - } - - private static int middleShift( - ArrayList> stackedBands, - Anchor anchor, - ArrayList placedBands, - int itemPadding - ) { - int shift = 0; - for (StackedBand stackedBand : stackedBands) { - ArrayList bounds = boundsForStackedBand(stackedBand, anchor, shift, itemPadding); - int leftOverstep = overstepFromPlacedBands(bounds, placedBands, LayoutPosition.LEFT, itemPadding); - if (leftOverstep > 0) { - shift += leftOverstep; - continue; - } - int rightOverstep = overstepFromPlacedBands(bounds, placedBands, LayoutPosition.RIGHT, itemPadding); - if (rightOverstep > 0) { - shift -= rightOverstep; - } - } - return shift; - } - - private static ArrayList boundsForStackedBand( - StackedBand stackedBand, - Anchor anchor, - int shift, - int itemPadding - ) { - ArrayList result = new ArrayList<>(); - int left = stackedLeft(stackedBand, anchor, shift, 0, itemPadding); - for (Bounds box : stackedBand.boxes) { - result.add(new Bounds(left + box.left, box.top, box.width, box.height)); - } - return result; - } - - private static int stackedLeft( - StackedBand stackedBand, - Anchor anchor, - int shift, - int wallDotSlack, - int itemPadding - ) { - T band = stackedBand.band; - int anchorGap = anchor.kind == AnchorKind.ITEM ? Math.max(0, itemPadding) : 0; - if (anchor.side == AnchorSide.RIGHT) { - return anchor.point + anchorGap + stackedBand.left + shift - wallDotSlack; - } - return anchor.point - anchorGap - stackedBand.left - band.width() + shift + wallDotSlack; - } - - private static int overstepFromPlacedBands( - ArrayList bounds, - ArrayList placedBands, - LayoutPosition position, - int itemPadding - ) { - int overstep = 0; - if (bounds == null || placedBands == null) { - return overstep; - } - for (Bounds boundsItem : bounds) { - if (boundsItem == null) { - continue; - } - for (PlacedBand placedBand : placedBands) { - if (placedBand.position != position) { - continue; - } - for (Bounds obstacle : placedBand.bounds) { - if (obstacle == null - || !verticalRangesOverlap( - boundsItem.top, - boundsItem.height, - obstacle.top, - obstacle.height)) { - continue; - } - overstep = Math.max(overstep, horizontalOverstep(boundsItem, obstacle, position, itemPadding)); - } - } - } - return overstep; - } - - private static int horizontalOverstep( - Bounds item, - Bounds obstacle, - LayoutPosition obstaclePosition, - int itemPadding - ) { - int gap = Math.max(0, itemPadding); - if (obstaclePosition == LayoutPosition.LEFT) { - return Math.max(0, obstacle.left + blockingWidth(obstacle) + gap - item.left); - } - if (obstaclePosition == LayoutPosition.RIGHT) { - return Math.max(0, item.left + blockingWidth(item) + gap - obstacle.left); - } - return 0; - } - - public static void truncateToFit( - ArrayList bands, - int freeSpace, - AnchorSide middleSide, - String sortOrder, - int itemPadding - ) { - int target = Math.max(0, freeSpace); - for (T band : bands) { - band.prepareForSide(truncationAnchorSide(band, middleSide), sortOrder); - } - int guard = 64; - while (packedWidthForTruncation(bands, middleSide, itemPadding) > target && guard-- > 0) { - if (shrinkToReducePackedWidth(bands, LayoutItemKind.NOTIFICATIONS, middleSide, itemPadding)) { - continue; - } - if (shrinkToReducePackedWidth(bands, LayoutItemKind.STATUS, middleSide, itemPadding)) { - continue; - } - if (clipToReducePackedWidth(bands, LayoutItemKind.CHIP, middleSide, target, itemPadding)) { - continue; - } - if (removeDotToReducePackedWidth(bands, LayoutItemKind.NOTIFICATIONS, middleSide, itemPadding)) { - continue; - } - if (removeDotToReducePackedWidth(bands, LayoutItemKind.STATUS, middleSide, itemPadding)) { - continue; - } - if (clipToReducePackedWidth(bands, LayoutItemKind.CLOCK, middleSide, target, itemPadding)) { - continue; - } - break; - } - } - - private static boolean shrinkToReducePackedWidth( - ArrayList bands, - LayoutItemKind kind, - AnchorSide middleSide, - int itemPadding - ) { - return mutateBandToReducePackedWidth( - bands, - kind, - middleSide, - itemPadding, - LayoutBand::shrinkOneIcon, - false, - true); - } - - private static boolean removeDotToReducePackedWidth( - ArrayList bands, - LayoutItemKind kind, - AnchorSide middleSide, - int itemPadding - ) { - return mutateBandToReducePackedWidth( - bands, - kind, - middleSide, - itemPadding, - LayoutBand::removeOverflowDot, - true, - false); - } - - private static boolean mutateBandToReducePackedWidth( - ArrayList bands, - LayoutItemKind kind, - AnchorSide middleSide, - int itemPadding, - BandMutation mutation, - boolean acceptEqualWidth, - boolean acceptCreatedDot - ) { - T band = findBand(bands, kind); - if (band == null) { - return false; - } - int before = packedWidthForTruncation(bands, middleSide, itemPadding); - Object state = band.captureState(); - if (!mutation.apply(band)) { - return false; - } - int after = packedWidthForTruncation(bands, middleSide, itemPadding); - if (after < before - || (acceptEqualWidth && after == before) - || (acceptCreatedDot && band.createdOverflowDotSince(state))) { - return true; - } - band.restoreState(state); - return false; - } - - private static boolean clipToReducePackedWidth( - ArrayList bands, - LayoutItemKind kind, - AnchorSide middleSide, - int target, - int itemPadding - ) { - T band = findBand(bands, kind); - if (band == null || !band.canClipContinuously()) { - return false; - } - int before = packedWidthForTruncation(bands, middleSide, itemPadding); - int amount = Math.max(1, before - target); - if (!band.clipContinuous(truncationAnchorSide(band, middleSide), amount)) { - return false; - } - return packedWidthForTruncation(bands, middleSide, itemPadding) <= before; - } - - public static int packedWidth(ArrayList bands) { - return packedWidth(bands, 0); - } - - public static int packedWidth(ArrayList bands, int itemPadding) { - return stackBounds(stackBands(bands, itemPadding)).width; - } - - private static int packedWidthForTruncation( - ArrayList bands, - AnchorSide middleSide, - int itemPadding - ) { - ArrayList> stackedBands = stackBands(bands, itemPadding); - Bounds bounds = stackBounds(stackedBands); - int width = bounds.width; - if (width <= 0 || stackedBands.isEmpty()) { - return width; - } - int leftEdge = bounds.left; - int rightEdge = bounds.left + bounds.width; - Integer leftSlack = null; - Integer rightSlack = null; - for (StackedBand stackedBand : stackedBands) { - T band = stackedBand.band; - Bounds bandBounds = shiftedBounds(stackedBand.boxes, stackedBand.left); - int bandLeft = bandBounds != null ? bandBounds.left : stackedBand.left; - int bandRight = bandBounds != null ? bandBounds.left + bandBounds.width : bandLeft; - if (bandLeft == leftEdge) { - int slack = band.wallDotSlack(AnchorSide.RIGHT); - leftSlack = leftSlack == null ? slack : Math.min(leftSlack, slack); - } - if (bandRight == rightEdge) { - int slack = band.wallDotSlack(AnchorSide.LEFT); - rightSlack = rightSlack == null ? slack : Math.min(rightSlack, slack); - } - } - return Math.max(0, width - (leftSlack != null ? leftSlack : 0) - (rightSlack != null ? rightSlack : 0)); - } - - private static AnchorSide truncationAnchorSide(LayoutBand band, AnchorSide middleSide) { - if (band.splitRegion == SplitRegion.LEFT) { - return AnchorSide.LEFT; - } - if (band.splitRegion == SplitRegion.RIGHT) { - return AnchorSide.RIGHT; - } - if (band.position == LayoutPosition.LEFT) { - return AnchorSide.RIGHT; - } - if (band.position == LayoutPosition.RIGHT) { - return AnchorSide.LEFT; - } - return middleSide; - } - - private static ArrayList> stackBands( - ArrayList bands, - int itemPadding - ) { - ArrayList> stackedBands = new ArrayList<>(); - if (bands == null) { - return stackedBands; - } - int gap = Math.max(0, itemPadding); - for (T band : bands) { - int left = 0; - ArrayList boxes = band.collisionBoxes(); - for (StackedBand stackedBand : stackedBands) { - for (Bounds box : boxes) { - for (Bounds placedBox : stackedBand.boxes) { - if (verticalRangesOverlap(box.top, box.height, placedBox.top, placedBox.height)) { - left = Math.max( - left, - stackedBand.left + placedBox.left + blockingWidth(placedBox) + gap - box.left); - } - } - } - } - stackedBands.add(new StackedBand<>(band, left, boxes)); - } - return stackedBands; - } - - private static Bounds stackBounds(ArrayList> stackedBands) { - Bounds bounds = new Bounds(0, 0, 0, 0); - if (stackedBands == null || stackedBands.isEmpty()) { - return bounds; - } - Bounds union = null; - for (StackedBand stackedBand : stackedBands) { - Bounds bandBounds = shiftedBounds(stackedBand.boxes, stackedBand.left); - if (bandBounds != null) { - union = union == null ? bandBounds : union.union(bandBounds); - } - } - return union != null ? union : bounds; - } - - private static Bounds shiftedBounds(ArrayList boxes, int left) { - Bounds union = null; - if (boxes == null) { - return null; - } - for (Bounds box : boxes) { - Bounds shifted = new Bounds(left + box.left, box.top, blockingWidth(box), box.height); - union = union == null ? shifted : union.union(shifted); - } - return union; - } - - private static boolean verticalRangesOverlap(int topA, int heightA, int topB, int heightB) { - return topA < topB + heightB && topB < topA + heightA; - } - - private static int blockingWidth(Bounds bounds) { - return bounds != null && bounds.height > 0 ? Math.max(1, bounds.width) : 0; - } - - private static T findBand(ArrayList bands, LayoutItemKind kind) { - for (T band : bands) { - if (band.kind == kind) { - return band; - } - } - return null; - } - - private static Bounds nearestPlacedBand(ArrayList placedBands, int middle) { - Bounds nearest = null; - int nearestDistance = Integer.MAX_VALUE; - for (PlacedBand placedBand : placedBands) { - for (Bounds bounds : placedBand.bounds) { - int distance = distanceFromMiddle(bounds, middle); - if (distance < nearestDistance) { - nearest = bounds; - nearestDistance = distance; - } - } - } - return nearest; - } - - public static int distanceFromMiddle(Bounds bounds, int middle) { - if (bounds == null) { - return Integer.MAX_VALUE; - } - if (bounds.left <= middle && bounds.left + bounds.width >= middle) { - return 0; - } - return Math.min(Math.abs(middle - bounds.left), Math.abs(middle - (bounds.left + bounds.width))); - } - - public static boolean coversMiddle(Bounds bounds, int middle) { - return bounds != null - && bounds.left <= middle + MIDDLE_COLLISION_MARGIN_PX - && bounds.left + bounds.width >= middle - MIDDLE_COLLISION_MARGIN_PX; - } - - public abstract static class LayoutBand { - public final LayoutItemKind kind; - public final LayoutPosition position; - public final boolean middleAutoNearestSide; - public final AnchorSide middleSide; - public final SplitRegion splitRegion; - - protected LayoutBand( - LayoutItemKind kind, - LayoutPosition position, - boolean middleAutoNearestSide, - AnchorSide middleSide, - SplitRegion splitRegion - ) { - this.kind = kind; - this.position = position; - this.middleAutoNearestSide = middleAutoNearestSide; - this.middleSide = middleSide; - this.splitRegion = splitRegion != null ? splitRegion : SplitRegion.NONE; - } - - protected abstract void prepareForSide(AnchorSide side, String sortOrder); - - protected abstract int width(); - - protected abstract ArrayList collisionBoxes(); - - protected abstract void place(int left); - - protected abstract ArrayList placedCollisionBounds(); - - protected int wallDotSlack(AnchorSide side) { - return 0; - } - - protected boolean shrinkOneIcon() { - return false; - } - - protected boolean removeOverflowDot() { - return false; - } - - protected Object captureState() { - return null; - } - - protected void restoreState(Object state) { - } - - protected boolean createdOverflowDotSince(Object state) { - return false; - } - - protected boolean canClipContinuously() { - return false; - } - - protected boolean clipContinuous(AnchorSide wallSide, int amountPx) { - return false; - } - } - - private interface BandMutation { - boolean apply(LayoutBand band); - } - - private record StackedBand( - T band, - int left, - ArrayList boxes - ) { - } - public enum LayoutItemKind { CARRIER, CLOCK, @@ -682,21 +23,12 @@ public final class StatusBarLayoutSolver { RIGHT } - public enum AnchorKind { - WALL, - ITEM, - CENTER - } - public enum SplitRegion { NONE, LEFT, RIGHT } - public record Anchor(int point, AnchorSide side, AnchorKind kind) { - } - public static final class Bounds { public final int left; public final int top; @@ -726,36 +58,24 @@ public final class StatusBarLayoutSolver { result = 31 * result + height; return result; } - } - public record PlacedBand( - LayoutItemKind kind, - LayoutPosition position, - ArrayList bounds - ) { - } - - public record RegionPlan( - ArrayList> regions, - AnchorSide middleSide - ) { - } - - public record LayoutEdges(int left, int right) { - } - - public static final class Region { - public final int left; - public final int right; - public final ArrayList bands = new ArrayList<>(); - - Region(int left, int right) { - this.left = left; - this.right = Math.max(left, right); + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof Bounds other)) { + return false; + } + return left == other.left + && top == other.top + && width == other.width + && height == other.height; } - public int width() { - return Math.max(0, right - left); + @Override + public int hashCode() { + return signature(); } } } diff --git a/app/src/main/java/se/ajpanton/statusbartweak/runtime/mode/ModeStateRepository.java b/app/src/main/java/se/ajpanton/statusbartweak/runtime/mode/ModeStateRepository.java index 24684b9..b456526 100644 --- a/app/src/main/java/se/ajpanton/statusbartweak/runtime/mode/ModeStateRepository.java +++ b/app/src/main/java/se/ajpanton/statusbartweak/runtime/mode/ModeStateRepository.java @@ -2,15 +2,9 @@ package se.ajpanton.statusbartweak.runtime.mode; import java.util.ArrayList; import java.util.List; -import java.util.Objects; /** * Central source of truth for the current scene. - * - * This is intentionally small at the reset stage: it only tracks the active - * scene and whether the custom layout runtime should currently output anything. - * Hook-driven updates can be wired in later without changing the rest of the - * runtime API. */ public final class ModeStateRepository { private SceneKey activeScene = SceneKey.unlocked(); @@ -19,6 +13,7 @@ public final class ModeStateRepository { private boolean layoutEnabled; private final List layoutEnabledListeners = new ArrayList<>(); private final List sceneListeners = new ArrayList<>(); + private final List systemUiStatusBarStateListeners = new ArrayList<>(); public synchronized SceneKey getActiveScene() { return activeScene; @@ -68,10 +63,6 @@ public final class ModeStateRepository { setActiveScene(SceneKey.aod(requireDisplayStyle(style))); } - public void setScene(SceneKey sceneKey) { - setActiveScene(Objects.requireNonNull(sceneKey, "sceneKey")); - } - public void setSystemUiStatusBarState( int state, boolean dozing, @@ -84,11 +75,23 @@ public final class ModeStateRepository { SceneKey scene = dozing ? SceneKey.aod(style) : state == 0 ? SceneKey.unlocked() : SceneKey.lockscreen(style); + boolean changed; + int previousState; + boolean previousKnown; synchronized (this) { + previousKnown = systemUiStatusBarStateKnown; + previousState = systemUiStatusBarState; + changed = !systemUiStatusBarStateKnown || systemUiStatusBarState != state; systemUiStatusBarStateKnown = true; systemUiStatusBarState = state; } setActiveScene(scene); + if (changed) { + notifySystemUiStatusBarStateListeners( + previousKnown ? previousState : -1, + state, + dozing); + } } public synchronized void addSceneListener(SceneListener listener) { @@ -97,6 +100,14 @@ public final class ModeStateRepository { } } + public synchronized void addSystemUiStatusBarStateListener( + SystemUiStatusBarStateListener listener + ) { + if (listener != null && !systemUiStatusBarStateListeners.contains(listener)) { + systemUiStatusBarStateListeners.add(listener); + } + } + private void setActiveScene(SceneKey scene) { SceneKey previous; List listeners; @@ -108,19 +119,22 @@ public final class ModeStateRepository { activeScene = scene; listeners = new ArrayList<>(sceneListeners); } - notifySceneChanged(previous, scene, listeners); + for (SceneListener listener : listeners) { + listener.onSceneChanged(previous, scene); + } } - private void notifySceneChanged( - SceneKey previous, - SceneKey current, - List listeners + private void notifySystemUiStatusBarStateListeners( + int previousState, + int currentState, + boolean dozing ) { - if (listeners == null || listeners.isEmpty()) { - return; + List listeners; + synchronized (this) { + listeners = new ArrayList<>(systemUiStatusBarStateListeners); } - for (SceneListener listener : listeners) { - listener.onSceneChanged(previous, current); + for (SystemUiStatusBarStateListener listener : listeners) { + listener.onSystemUiStatusBarStateChanged(previousState, currentState, dozing); } } @@ -138,4 +152,8 @@ public final class ModeStateRepository { public interface SceneListener { void onSceneChanged(SceneKey previous, SceneKey current); } + + public interface SystemUiStatusBarStateListener { + void onSystemUiStatusBarStateChanged(int previousState, int currentState, boolean dozing); + } } diff --git a/app/src/main/java/se/ajpanton/statusbartweak/runtime/notifications/NotificationActiveKeyStore.java b/app/src/main/java/se/ajpanton/statusbartweak/runtime/notifications/NotificationActiveKeyStore.java new file mode 100644 index 0000000..bddb2d5 --- /dev/null +++ b/app/src/main/java/se/ajpanton/statusbartweak/runtime/notifications/NotificationActiveKeyStore.java @@ -0,0 +1,68 @@ +package se.ajpanton.statusbartweak.runtime.notifications; + +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; + +public final class NotificationActiveKeyStore { + private static final HashSet ACTIVE_KEYS = new HashSet<>(); + private static int generation; + + private NotificationActiveKeyStore() { + } + + public static synchronized boolean replace(Collection keys) { + HashSet normalized = new HashSet<>(); + if (keys != null) { + for (String key : keys) { + addKey(normalized, key); + } + } + if (ACTIVE_KEYS.equals(normalized)) { + return false; + } + ACTIVE_KEYS.clear(); + ACTIVE_KEYS.addAll(normalized); + generation++; + return true; + } + + public static synchronized boolean hasSnapshot() { + return !ACTIVE_KEYS.isEmpty(); + } + + public static synchronized boolean isActive(String key) { + String normalized = normalizeKey(key); + return normalized != null && ACTIVE_KEYS.contains(normalized); + } + + public static synchronized int generation() { + return generation; + } + + public static synchronized Set snapshot() { + return new HashSet<>(ACTIVE_KEYS); + } + + private static void addKey(HashSet out, String key) { + String normalized = normalizeKey(key); + if (normalized != null) { + out.add(normalized); + } + } + + private static String normalizeKey(String key) { + if (key == null) { + return null; + } + String normalized = key.trim(); + if (normalized.isEmpty()) { + return null; + } + int identitySuffix = normalized.indexOf('@'); + if (identitySuffix >= 0) { + normalized = normalized.substring(0, identitySuffix); + } + return normalized.isEmpty() ? null : normalized; + } +} diff --git a/app/src/main/java/se/ajpanton/statusbartweak/runtime/notifications/NotificationUnreadTracker.java b/app/src/main/java/se/ajpanton/statusbartweak/runtime/notifications/NotificationUnreadTracker.java new file mode 100644 index 0000000..6fa6168 --- /dev/null +++ b/app/src/main/java/se/ajpanton/statusbartweak/runtime/notifications/NotificationUnreadTracker.java @@ -0,0 +1,137 @@ +package se.ajpanton.statusbartweak.runtime.notifications; + +import android.app.Notification; +import android.os.Bundle; +import android.service.notification.StatusBarNotification; + +import java.util.HashMap; +import java.util.Objects; +import java.util.Set; + +import se.ajpanton.statusbartweak.runtime.NotificationKeyReflection; +import se.ajpanton.statusbartweak.shell.settings.AppIconRules; + +public final class NotificationUnreadTracker { + private static final HashMap STATE_BY_KEY = new HashMap<>(); + private static final HashMap UPDATED_BY_PACKAGE = new HashMap<>(); + private static long lastSeenMs; + private static int generation; + + private NotificationUnreadTracker() { + } + + public static synchronized boolean markSeen() { + long now = System.currentTimeMillis(); + if (now <= lastSeenMs) { + return false; + } + lastSeenMs = now; + generation++; + return true; + } + + public static synchronized boolean record(StatusBarNotification sbn) { + if (sbn == null || !AppIconRules.isValidPackageName(sbn.getPackageName())) { + return false; + } + String key = sbn.getKey(); + if (key == null || key.isEmpty()) { + return false; + } + int signature = signature(sbn); + State previous = STATE_BY_KEY.get(key); + if (previous != null && previous.signature == signature) { + return false; + } + long updateTime = previous == null ? notificationTime(sbn) : System.currentTimeMillis(); + State state = new State(sbn.getPackageName(), signature, updateTime); + STATE_BY_KEY.put(key, state); + Long packageTime = UPDATED_BY_PACKAGE.get(state.packageName); + if (packageTime == null || updateTime > packageTime) { + UPDATED_BY_PACKAGE.put(state.packageName, updateTime); + } + generation++; + return updateTime > lastSeenMs; + } + + public static synchronized boolean retainActiveKeys(Set activeKeys) { + if (activeKeys == null) { + return false; + } + boolean changed = STATE_BY_KEY.keySet().removeIf(key -> !activeKeys.contains(key)); + if (changed) { + rebuildPackageTimes(); + generation++; + } + return changed; + } + + public static synchronized int generation() { + return generation; + } + + public static synchronized boolean isUnread(String key) { + if (key == null || key.isEmpty()) { + return false; + } + State state = STATE_BY_KEY.get(key); + if (state != null) { + return state.updatedMs > lastSeenMs; + } + String packageName = NotificationKeyReflection.packageFromNotificationKey(key); + Long packageTime = packageName != null ? UPDATED_BY_PACKAGE.get(packageName) : null; + return packageTime != null && packageTime > lastSeenMs; + } + + private static long notificationTime(StatusBarNotification sbn) { + long result = sbn.getPostTime(); + Notification notification = sbn.getNotification(); + if (notification != null && notification.when > result) { + result = notification.when; + } + return result > 0L ? result : System.currentTimeMillis(); + } + + private static int signature(StatusBarNotification sbn) { + Notification notification = sbn.getNotification(); + Bundle extras = notification != null ? notification.extras : null; + return Objects.hash( + sbn.getKey(), + sbn.getPostTime(), + notification != null ? notification.when : 0L, + notification != null ? notification.number : 0, + notification != null ? notification.flags : 0, + notification != null ? notification.category : null, + textExtra(extras, Notification.EXTRA_TITLE), + textExtra(extras, Notification.EXTRA_TEXT), + textExtra(extras, Notification.EXTRA_BIG_TEXT), + textExtra(extras, Notification.EXTRA_SUB_TEXT)); + } + + private static String textExtra(Bundle extras, String key) { + CharSequence value = extras != null ? extras.getCharSequence(key) : null; + return value != null ? value.toString() : null; + } + + private static void rebuildPackageTimes() { + UPDATED_BY_PACKAGE.clear(); + for (State state : STATE_BY_KEY.values()) { + Long previous = UPDATED_BY_PACKAGE.get(state.packageName); + if (previous == null || state.updatedMs > previous) { + UPDATED_BY_PACKAGE.put(state.packageName, state.updatedMs); + } + } + } + + private static final class State { + final String packageName; + final int signature; + final long updatedMs; + + State(String packageName, int signature, long updatedMs) { + this.packageName = packageName; + this.signature = signature; + this.updatedMs = updatedMs; + } + } +} diff --git a/app/src/main/java/se/ajpanton/statusbartweak/runtime/render/DebugBoundsOverlayController.java b/app/src/main/java/se/ajpanton/statusbartweak/runtime/render/DebugBoundsOverlayController.java index f95d863..c11a552 100644 --- a/app/src/main/java/se/ajpanton/statusbartweak/runtime/render/DebugBoundsOverlayController.java +++ b/app/src/main/java/se/ajpanton/statusbartweak/runtime/render/DebugBoundsOverlayController.java @@ -18,7 +18,7 @@ import java.util.List; import java.util.Objects; import se.ajpanton.statusbartweak.R; -import se.ajpanton.statusbartweak.runtime.layoutsolver.StatusBarLayoutSolver; +import se.ajpanton.statusbartweak.runtime.layoutsolver.StatusBarLayoutSolver.Bounds; import se.ajpanton.statusbartweak.runtime.mode.NotificationDisplayStyle; import se.ajpanton.statusbartweak.runtime.mode.SceneKey; import se.ajpanton.statusbartweak.shell.settings.SbtSettings; @@ -209,9 +209,9 @@ public final class DebugBoundsOverlayController { Bounds notificationBounds = aodNotificationBounds(root, scene); Bounds statusBounds = liveAodStatusIconsBounds(root); if (!isUsableAodAnchor(root, statusBounds)) { - statusBounds = overlayBounds(AodStatusbarSourceStore.statusBoundsForRoot( + statusBounds = AodStatusbarSourceStore.statusBoundsForRoot( root, - notificationContainer)); + notificationContainer); } boolean hasNotification = isUsableAodAnchor(root, notificationBounds); boolean hasStatus = isUsableAodAnchor(root, statusBounds); @@ -238,8 +238,7 @@ public final class DebugBoundsOverlayController { && scene.notificationDisplayStyle() == NotificationDisplayStyle.CARDS) { return null; } - return overlayBounds( - LockscreenCardsNotificationIconSourceStore.sourceContainerBoundsForAodIconsRoot(root)); + return LockscreenCardsNotificationIconSourceStore.sourceContainerBoundsForAodIconsRoot(root); } private ViewGroup aodNotificationContainer(View root, SceneKey scene) { @@ -266,16 +265,8 @@ public final class DebugBoundsOverlayController { return bounds != null ? bounds.signature() : 0; } - private Bounds overlayBounds(StatusBarLayoutSolver.Bounds bounds) { - if (bounds == null) { - return null; - } - return new Bounds(bounds.left, bounds.top, bounds.width, bounds.height); - } - private Bounds liveAodStatusIconsBounds(View root) { - StatusBarLayoutSolver.Bounds bounds = AodLiveStatusbarSource.boundsForRoot(root); - return bounds != null ? new Bounds(bounds.left, bounds.top, bounds.width, bounds.height) : null; + return AodLiveStatusbarSource.boundsForRoot(root); } private void addCutoutSpecs(View root, ArrayList specs) { @@ -352,8 +343,8 @@ public final class DebugBoundsOverlayController { } ArrayList out = new ArrayList<>(); for (Object value : values) { - if (value instanceof StatusBarLayoutSolver.Bounds bounds) { - out.add(new Bounds(bounds.left, bounds.top, bounds.width, bounds.height)); + if (value instanceof Bounds bounds) { + out.add(bounds); } } return out; @@ -606,25 +597,6 @@ public final class DebugBoundsOverlayController { } } - private record Bounds(int left, int top, int width, int height) { - Bounds union(Bounds other) { - int right = Math.max(left + width, other.left + other.width); - int bottom = Math.max(top + height, other.top + other.height); - int newLeft = Math.min(left, other.left); - int newTop = Math.min(top, other.top); - return new Bounds(newLeft, newTop, right - newLeft, bottom - newTop); - } - - int signature() { - int result = 17; - result = 31 * result + left; - result = 31 * result + top; - result = 31 * result + width; - result = 31 * result + height; - return result; - } - } - private static final class OverlayView extends View { private final Paint paint = new Paint(); private ArrayList specs = new ArrayList<>(); diff --git a/app/src/main/java/se/ajpanton/statusbartweak/runtime/render/LockscreenCardsNotificationIconSourceStore.java b/app/src/main/java/se/ajpanton/statusbartweak/runtime/render/LockscreenCardsNotificationIconSourceStore.java index 9c6274c..a7ca057 100644 --- a/app/src/main/java/se/ajpanton/statusbartweak/runtime/render/LockscreenCardsNotificationIconSourceStore.java +++ b/app/src/main/java/se/ajpanton/statusbartweak/runtime/render/LockscreenCardsNotificationIconSourceStore.java @@ -25,6 +25,7 @@ public final class LockscreenCardsNotificationIconSourceStore { new WeakHashMap<>(); private static final WeakHashMap> AOD_DRAWABLES_BY_CONTAINER = new WeakHashMap<>(); + private static final ArrayList AOD_NOTIFICATION_PACKAGES = new ArrayList<>(); private static final int VIRTUAL_ICON_SIZE_PX = 39; private LockscreenCardsNotificationIconSourceStore() { @@ -113,6 +114,7 @@ public final class LockscreenCardsNotificationIconSourceStore { public static void clearAodSources() { PACKAGES_BY_CONTAINER.clear(); AOD_DRAWABLES_BY_CONTAINER.clear(); + AOD_NOTIFICATION_PACKAGES.clear(); } public static void clearAodSources(ViewGroup container) { @@ -123,6 +125,18 @@ public final class LockscreenCardsNotificationIconSourceStore { AOD_DRAWABLES_BY_CONTAINER.remove(container); } + public static void putAodNotificationPackages(ArrayList 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); + } + } + } + private static boolean sameViews(ArrayList previous, ArrayList current) { if (previous == current) { return true; @@ -252,6 +266,25 @@ public final class LockscreenCardsNotificationIconSourceStore { return result; } + static ArrayList snapshotAodNotificationPackageSources(View root) { + ArrayList result = new ArrayList<>(); + if (AOD_NOTIFICATION_PACKAGES.isEmpty()) { + return result; + } + Bounds bounds = sourceContainerBoundsForAodIconsRoot(root); + int top = bounds != null ? bounds.top : 0; + int size = VIRTUAL_ICON_SIZE_PX; + for (int i = 0; i < AOD_NOTIFICATION_PACKAGES.size(); i++) { + String pkg = AOD_NOTIFICATION_PACKAGES.get(i); + result.add(new SnapshotSource( + null, + SnapshotMode.APP_ICON, + pkg + "@aodUnread" + i, + new Bounds(0, top, size, size))); + } + return result; + } + static ViewGroup sourceContainerForRoot(View root) { ViewGroup container = sourceContainerForRoot(root, AOD_DRAWABLES_BY_CONTAINER.keySet()); if (container != null) { @@ -284,6 +317,22 @@ public final class LockscreenCardsNotificationIconSourceStore { return bounds; } + public static boolean sourceContainerHasHiddenAncestorForRoot(View root) { + ViewGroup container = sourceContainerForRoot(root); + if (container == null) { + return false; + } + View current = container; + while (current != null && current != root) { + if (current.getVisibility() != View.VISIBLE) { + return true; + } + Object parent = current.getParent(); + current = parent instanceof View ? (View) parent : null; + } + return current != root; + } + public static Bounds sourceContainerBoundsForAodIconsRoot(View root) { ViewGroup container = sourceContainerForAodIconsRoot(root); Bounds bounds = sourceBoundsRelativeTo(root, container); @@ -294,7 +343,11 @@ public final class LockscreenCardsNotificationIconSourceStore { } private static Bounds sourceBoundsRelativeTo(View root, ViewGroup container) { - Bounds bounds = container != null ? ViewGeometry.boundsRelativeTo(root, container) : null; + Bounds bounds = rawSourceBoundsRelativeTo(root, container); + return normalizeSourceBounds(container, bounds); + } + + private static Bounds normalizeSourceBounds(ViewGroup container, Bounds bounds) { if (bounds == null || isZeroSizeDotContainer(container, bounds)) { return bounds; } @@ -308,6 +361,10 @@ public final class LockscreenCardsNotificationIconSourceStore { return new Bounds(bounds.left, top, bounds.width, VIRTUAL_ICON_SIZE_PX); } + private static Bounds rawSourceBoundsRelativeTo(View root, ViewGroup container) { + return container != null ? ViewGeometry.boundsRelativeTo(root, container) : null; + } + private static boolean hasAodSources(ViewGroup container) { return container != null && (AOD_DRAWABLES_BY_CONTAINER.containsKey(container) diff --git a/app/src/main/java/se/ajpanton/statusbartweak/runtime/render/SnapshotModels.java b/app/src/main/java/se/ajpanton/statusbartweak/runtime/render/SnapshotModels.java index fa9c2c7..c9400f7 100644 --- a/app/src/main/java/se/ajpanton/statusbartweak/runtime/render/SnapshotModels.java +++ b/app/src/main/java/se/ajpanton/statusbartweak/runtime/render/SnapshotModels.java @@ -460,15 +460,6 @@ final class LayoutPlan { final ArrayList notificationPlacements; final ClockPlacement carrierPlacement; - LayoutPlan( - ClockPlacement clockPlacement, - ArrayList chipPlacements, - ArrayList statusPlacements, - ArrayList notificationPlacements - ) { - this(clockPlacement, chipPlacements, statusPlacements, notificationPlacements, null); - } - LayoutPlan( ClockPlacement clockPlacement, ArrayList chipPlacements, diff --git a/app/src/main/java/se/ajpanton/statusbartweak/runtime/render/UnlockedIconSnapshotRenderController.java b/app/src/main/java/se/ajpanton/statusbartweak/runtime/render/UnlockedIconSnapshotRenderController.java index 8b67fab..c27305a 100644 --- a/app/src/main/java/se/ajpanton/statusbartweak/runtime/render/UnlockedIconSnapshotRenderController.java +++ b/app/src/main/java/se/ajpanton/statusbartweak/runtime/render/UnlockedIconSnapshotRenderController.java @@ -65,13 +65,14 @@ public final class UnlockedIconSnapshotRenderController { ViewGroup statusHost, ViewGroup notificationHost, SceneKey scene, + boolean forceStockRefresh, TextView externalCarrierView ) { if (scene == null || (!scene.isUnlocked() && !scene.isLockscreen() && !scene.isAod()) || !root.isAttachedToWindow()) { clearAll(); - return new RenderResult(true, true); + return new RenderResult(true, true, true); } SbtSettings settings = RuntimeSettingsCache.get(root.getContext()); layoutHostToRoot(root, clockHost); @@ -139,7 +140,7 @@ public final class UnlockedIconSnapshotRenderController { lastLayoutPlanByRoot.put(root, updatedPlan); lastClockSourceGeometryByRoot.put(root, currentClockSourceGeometry); clockRenderer.render(clockHost, updatedClock); - return new RenderResult(false, false); + return new RenderResult(false, false, false); } } currentClockLayout = buildClockLayout(root, anchors, settings); @@ -166,16 +167,16 @@ public final class UnlockedIconSnapshotRenderController { LayoutPlan updatedPlan = previousPlan.withClockPlacement(updatedClock); lastLayoutPlanByRoot.put(root, updatedPlan); clockRenderer.render(clockHost, updatedClock); - return new RenderResult(false, false); + return new RenderResult(false, false, false); } } CollectedIcons collectedIcons = previousIcons; - if (forceChipRefresh && collectedIcons != null) { - collectedIcons = sourceCollector.collectChips(root, anchors, collectedIcons); - lastCollectedIconsByRoot.put(root, collectedIcons); - } else if (sceneChanged || stockSourcesChanged || collectedIcons == null) { + if (forceStockRefresh || sceneChanged || stockSourcesChanged || collectedIcons == null) { collectedIcons = sourceCollector.collect(root, anchors, scene); lastCollectedIconsByRoot.put(root, collectedIcons); + } else if (forceChipRefresh && collectedIcons != null) { + collectedIcons = sourceCollector.collectChips(root, anchors, collectedIcons); + lastCollectedIconsByRoot.put(root, collectedIcons); } else if (chipSourcesChanged) { collectedIcons = sourceCollector.collectChips(root, anchors, collectedIcons); lastCollectedIconsByRoot.put(root, collectedIcons); @@ -993,10 +994,6 @@ public final class UnlockedIconSnapshotRenderController { boolean chipSourcesChanged, boolean shouldOwnLockscreen ) { - public RenderResult(boolean layoutChanged, boolean stockSourcesChanged) { - this(layoutChanged, stockSourcesChanged, stockSourcesChanged, true); - } - public RenderResult(boolean layoutChanged, boolean stockSourcesChanged, boolean chipSourcesChanged) { this(layoutChanged, stockSourcesChanged, chipSourcesChanged, true); } diff --git a/app/src/main/java/se/ajpanton/statusbartweak/runtime/render/UnlockedLayoutBand.java b/app/src/main/java/se/ajpanton/statusbartweak/runtime/render/UnlockedLayoutBand.java index 179e63b..e6f08cd 100644 --- a/app/src/main/java/se/ajpanton/statusbartweak/runtime/render/UnlockedLayoutBand.java +++ b/app/src/main/java/se/ajpanton/statusbartweak/runtime/render/UnlockedLayoutBand.java @@ -6,21 +6,21 @@ import java.util.ArrayList; import java.util.Collections; import java.util.Locale; -import se.ajpanton.statusbartweak.runtime.layoutsolver.StatusBarLayoutSolver; import se.ajpanton.statusbartweak.runtime.layoutsolver.StatusBarLayoutSolver.AnchorSide; import se.ajpanton.statusbartweak.runtime.layoutsolver.StatusBarLayoutSolver.Bounds; import se.ajpanton.statusbartweak.runtime.layoutsolver.StatusBarLayoutSolver.LayoutItemKind; import se.ajpanton.statusbartweak.runtime.layoutsolver.StatusBarLayoutSolver.LayoutPosition; import se.ajpanton.statusbartweak.runtime.layoutsolver.StatusBarLayoutSolver.SplitRegion; -import se.ajpanton.statusbartweak.shell.settings.SbtSettings; -final class UnlockedLayoutBand extends StatusBarLayoutSolver.LayoutBand { +final class UnlockedLayoutBand { + final LayoutItemKind kind; + final LayoutPosition position; + final AnchorSide middleSide; + final SplitRegion splitRegion; final ViewGroup host; final SnapshotRenderer renderer; final ArrayList rawPlacements; - final boolean showDotIfTruncated; final boolean forceOverflowDotOnly; - final Bounds reservedBounds; final ClockLayout clockLayout; ArrayList placements; @@ -37,21 +37,19 @@ final class UnlockedLayoutBand extends StatusBarLayoutSolver.LayoutBand { SnapshotRenderer renderer, ArrayList rawPlacements, LayoutPosition position, - boolean middleAutoNearestSide, AnchorSide middleSide, - boolean showDotIfTruncated, boolean forceOverflowDotOnly, - Bounds reservedBounds, ClockLayout clockLayout, SplitRegion splitRegion ) { - super(kind, position, middleAutoNearestSide, middleSide, splitRegion); + this.kind = kind; + this.position = position; + this.middleSide = middleSide; + this.splitRegion = splitRegion != null ? splitRegion : SplitRegion.NONE; this.host = host; this.renderer = renderer; this.rawPlacements = rawPlacements; - this.showDotIfTruncated = showDotIfTruncated; this.forceOverflowDotOnly = forceOverflowDotOnly; - this.reservedBounds = reservedBounds; this.clockLayout = clockLayout; } @@ -59,7 +57,7 @@ final class UnlockedLayoutBand extends StatusBarLayoutSolver.LayoutBand { ViewGroup host, ClockLayout clockLayout, LayoutPosition position, - SbtSettings settings + AnchorSide middleSide ) { return new UnlockedLayoutBand( LayoutItemKind.CLOCK, @@ -67,11 +65,8 @@ final class UnlockedLayoutBand extends StatusBarLayoutSolver.LayoutBand { null, null, position, - settings.clockMiddleAutoNearestSide, - sideFor(settings.clockMiddleCutoutSide), + middleSide, false, - false, - null, clockLayout, SplitRegion.NONE); } @@ -80,7 +75,7 @@ final class UnlockedLayoutBand extends StatusBarLayoutSolver.LayoutBand { ViewGroup host, ClockLayout clockLayout, SplitRegion splitRegion, - SbtSettings settings + AnchorSide middleSide ) { return new UnlockedLayoutBand( LayoutItemKind.CLOCK, @@ -88,11 +83,8 @@ final class UnlockedLayoutBand extends StatusBarLayoutSolver.LayoutBand { null, null, LayoutPosition.MIDDLE, - settings.clockMiddleAutoNearestSide, - sideFor(settings.clockMiddleCutoutSide), + middleSide, false, - false, - null, clockLayout, splitRegion); } @@ -101,7 +93,6 @@ final class UnlockedLayoutBand extends StatusBarLayoutSolver.LayoutBand { ViewGroup host, ClockLayout carrierLayout, LayoutPosition position, - boolean middleAutoNearestSide, AnchorSide middleSide ) { return new UnlockedLayoutBand( @@ -110,11 +101,8 @@ final class UnlockedLayoutBand extends StatusBarLayoutSolver.LayoutBand { null, null, position, - middleAutoNearestSide, middleSide, false, - false, - null, carrierLayout, SplitRegion.NONE); } @@ -125,9 +113,7 @@ final class UnlockedLayoutBand extends StatusBarLayoutSolver.LayoutBand { SnapshotRenderer renderer, ArrayList rawPlacements, LayoutPosition position, - boolean middleAutoNearestSide, - AnchorSide middleSide, - boolean showDotIfTruncated + AnchorSide middleSide ) { return new UnlockedLayoutBand( kind, @@ -135,12 +121,9 @@ final class UnlockedLayoutBand extends StatusBarLayoutSolver.LayoutBand { renderer, rawPlacements, position, - middleAutoNearestSide, middleSide, - showDotIfTruncated, false, null, - null, SplitRegion.NONE); } @@ -156,7 +139,6 @@ final class UnlockedLayoutBand extends StatusBarLayoutSolver.LayoutBand { SnapshotRenderer renderer, ArrayList rawPlacements, LayoutPosition position, - boolean middleAutoNearestSide, AnchorSide middleSide ) { return new UnlockedLayoutBand( @@ -165,20 +147,16 @@ final class UnlockedLayoutBand extends StatusBarLayoutSolver.LayoutBand { renderer, rawPlacements, position, - middleAutoNearestSide, middleSide, true, - true, - null, null, SplitRegion.NONE); } - @Override - protected void prepareForSide(AnchorSide side, String sortOrder) { + void prepareForSide(AnchorSide side, String sortOrder) { if (isTextKind()) { placements = null; - placedBounds = clockLayout != null ? clockLayout.bounds() : reservedBounds; + placedBounds = clockLayout != null ? clockLayout.bounds() : null; return; } placements = new ArrayList<>(activePlacements()); @@ -189,8 +167,7 @@ final class UnlockedLayoutBand extends StatusBarLayoutSolver.LayoutBand { placedBounds = null; } - @Override - protected int width() { + int width() { return Math.max(0, naturalWidth() - clipStartPx - clipEndPx); } @@ -199,19 +176,17 @@ final class UnlockedLayoutBand extends StatusBarLayoutSolver.LayoutBand { if (clockLayout != null) { return clockLayout.width(); } - return reservedBounds != null ? reservedBounds.width : 0; + return 0; } return sumWidths(activePlacements()); } - @Override - protected boolean canClipContinuously() { + boolean canClipContinuously() { return (kind == LayoutItemKind.CHIP || isTextKind()) && naturalWidth() > clipStartPx + clipEndPx; } - @Override - protected boolean clipContinuous(AnchorSide wallSide, int amountPx) { + boolean clipContinuous(AnchorSide wallSide, int amountPx) { int remaining = naturalWidth() - clipStartPx - clipEndPx; if (amountPx <= 0 || remaining <= 0 || !canClipContinuously()) { return false; @@ -261,23 +236,12 @@ final class UnlockedLayoutBand extends StatusBarLayoutSolver.LayoutBand { } } - @Override - protected int wallDotSlack(AnchorSide side) { - SnapshotPlacement placement = wallPlacement(side); - if (placement == null || !placement.overflowDot) { - return 0; - } - int collisionWidth = relativeCollisionBounds(placement).width; - int dotWidth = overflowDotVisualWidth(placement); - return Math.max(0, (collisionWidth - dotWidth) / 2); - } - int height() { if (isTextKind()) { if (clockLayout != null) { return clockLayout.height(); } - return reservedBounds != null ? reservedBounds.height : 0; + return 0; } int height = 0; for (SnapshotPlacement placement : activePlacements()) { @@ -291,7 +255,7 @@ final class UnlockedLayoutBand extends StatusBarLayoutSolver.LayoutBand { if (clockLayout != null) { return clockLayout.top(); } - return reservedBounds != null ? reservedBounds.top : 0; + return 0; } int top = Integer.MAX_VALUE; for (SnapshotPlacement placement : activePlacements()) { @@ -300,41 +264,6 @@ final class UnlockedLayoutBand extends StatusBarLayoutSolver.LayoutBand { return top == Integer.MAX_VALUE ? 0 : top; } - @Override - protected boolean shrinkOneIcon() { - if (kind == LayoutItemKind.NOTIFICATIONS) { - return shrinkIcon(false); - } - if (kind == LayoutItemKind.STATUS) { - return shrinkIcon(true); - } - return false; - } - - @Override - protected boolean removeOverflowDot() { - if (placements == null || placements.isEmpty()) { - return false; - } - ArrayList withoutDot = new ArrayList<>(); - boolean removed = false; - for (SnapshotPlacement placement : placements) { - if (placement.overflowDot) { - removed = true; - } else { - withoutDot.add(placement); - } - } - if (!removed) { - return false; - } - if (withoutDot.isEmpty()) { - withoutDot.add(emptyIconContainerPlacement()); - } - placements = withoutDot; - return true; - } - private void replaceOverflowDot(int width, int height) { if (placements == null) { placements = new ArrayList<>(); @@ -354,29 +283,7 @@ final class UnlockedLayoutBand extends StatusBarLayoutSolver.LayoutBand { placements = withoutDot; } - @Override - protected Object captureState() { - return new LayoutBandState(placements == null, new ArrayList<>(activePlacements())); - } - - @Override - protected void restoreState(Object state) { - if (!(state instanceof LayoutBandState bandState)) { - return; - } - placements = bandState.placementsWereNull ? null : new ArrayList<>(bandState.placements); - } - - @Override - protected boolean createdOverflowDotSince(Object state) { - if (!(state instanceof LayoutBandState bandState)) { - return hasOverflowDot(activePlacements()); - } - return !hasOverflowDot(bandState.placements) && hasOverflowDot(activePlacements()); - } - - @Override - protected void place(int left) { + void place(int left) { if (isTextKind()) { placedBounds = clockLayout != null ? clockLayout.place(left) @@ -441,8 +348,7 @@ final class UnlockedLayoutBand extends StatusBarLayoutSolver.LayoutBand { return union; } - @Override - protected ArrayList collisionBoxes() { + ArrayList collisionBoxes() { ArrayList boxes = new ArrayList<>(); if (isTextKind()) { if (clockLayout != null) { @@ -455,8 +361,6 @@ final class UnlockedLayoutBand extends StatusBarLayoutSolver.LayoutBand { boxes.add(new Bounds(left - clipStartPx, box.top, right - left, box.height)); } } - } else if (reservedBounds != null) { - boxes.add(new Bounds(0, reservedBounds.top, width(), reservedBounds.height)); } return boxes; } @@ -486,47 +390,6 @@ final class UnlockedLayoutBand extends StatusBarLayoutSolver.LayoutBand { return solverBoxes; } - @Override - protected ArrayList placedCollisionBounds() { - ArrayList boxes = new ArrayList<>(); - int left = isTextKind() && placedBounds != null - ? placedBounds.left - : 0; - for (Bounds box : collisionBoxes()) { - boxes.add(new Bounds(left + box.left, box.top, box.width, box.height)); - } - if (kind != LayoutItemKind.CLOCK && placedBounds != null) { - boxes.clear(); - boxes.add(placedBounds); - } - return boxes; - } - - private SnapshotPlacement wallPlacement(AnchorSide side) { - if (isTextKind()) { - return null; - } - ArrayList icons = activePlacements(); - if (icons.isEmpty()) { - return null; - } - boolean wallAtStart = side == AnchorSide.RIGHT; - int index; - if (wallAtStart) { - index = reverseForPlacement ? icons.size() - 1 : 0; - } else { - index = reverseForPlacement ? 0 : icons.size() - 1; - } - return icons.get(index); - } - - private int overflowDotVisualWidth(SnapshotPlacement placement) { - Bounds bounds = placement.bounds; - int base = Math.max(1, Math.min(bounds.width, bounds.height)); - int radius = Math.max(1, Math.round(base * 0.125f)); - return Math.min(bounds.width, radius * 2); - } - private Bounds collisionBounds(SnapshotPlacement placement) { Bounds relative = relativeCollisionBounds(placement); Bounds bounds = placement.bounds; @@ -547,38 +410,6 @@ final class UnlockedLayoutBand extends StatusBarLayoutSolver.LayoutBand { return new Bounds(0, 0, bounds.width, bounds.height); } - private boolean shrinkIcon(boolean fromStart) { - ArrayList icons = new ArrayList<>(activePlacements()); - int removeIndex = nonDotIndex(icons, fromStart); - if (removeIndex < 0) { - return false; - } - boolean hadDot = hasOverflowDot(icons); - icons.remove(removeIndex); - if (showDotIfTruncated && !hadDot) { - SnapshotPlacement dot = dotPlacement(dotWidth(icons), dotHeight(icons), rowTop(icons)); - if (fromStart) { - icons.add(0, dot); - } else { - icons.add(dot); - } - } - placements = icons; - return true; - } - - private int nonDotIndex(ArrayList icons, boolean fromStart) { - int start = fromStart ? 0 : icons.size() - 1; - int end = fromStart ? icons.size() : -1; - int step = fromStart ? 1 : -1; - for (int i = start; i != end; i += step) { - if (isShrinkableIcon(icons.get(i))) { - return i; - } - } - return -1; - } - private boolean isShrinkableIcon(SnapshotPlacement placement) { return placement != null && !placement.overflowDot @@ -612,15 +443,6 @@ final class UnlockedLayoutBand extends StatusBarLayoutSolver.LayoutBand { return result; } - private boolean hasOverflowDot(ArrayList icons) { - for (SnapshotPlacement icon : icons) { - if (icon.overflowDot) { - return true; - } - } - return false; - } - private ArrayList activePlacements() { if (placements != null) { return placements; @@ -884,10 +706,4 @@ final class UnlockedLayoutBand extends StatusBarLayoutSolver.LayoutBand { return kind == LayoutItemKind.CLOCK || kind == LayoutItemKind.CARRIER; } - private static AnchorSide sideFor(String value) { - return "right".equals(value) ? AnchorSide.RIGHT : AnchorSide.LEFT; - } - - private record LayoutBandState(boolean placementsWereNull, ArrayList placements) { - } } diff --git a/app/src/main/java/se/ajpanton/statusbartweak/runtime/render/UnlockedLayoutPlanner.java b/app/src/main/java/se/ajpanton/statusbartweak/runtime/render/UnlockedLayoutPlanner.java index 6b1dba3..8007cc8 100644 --- a/app/src/main/java/se/ajpanton/statusbartweak/runtime/render/UnlockedLayoutPlanner.java +++ b/app/src/main/java/se/ajpanton/statusbartweak/runtime/render/UnlockedLayoutPlanner.java @@ -12,16 +12,15 @@ import java.util.Map; import java.util.WeakHashMap; import se.ajpanton.statusbartweak.R; -import se.ajpanton.statusbartweak.runtime.layoutsolver.StatusBarLayoutSolver; import se.ajpanton.statusbartweak.runtime.layoutsolver.StatusBarLayoutSolver.AnchorSide; import se.ajpanton.statusbartweak.runtime.layoutsolver.StatusBarLayoutSolver.Bounds; -import se.ajpanton.statusbartweak.runtime.layoutsolver.StatusBarLayoutSolver.LayoutEdges; import se.ajpanton.statusbartweak.runtime.layoutsolver.StatusBarLayoutSolver.LayoutItemKind; import se.ajpanton.statusbartweak.runtime.layoutsolver.StatusBarLayoutSolver.LayoutPosition; import se.ajpanton.statusbartweak.runtime.layoutsolver.StatusBarLayoutSolver.SplitRegion; import se.ajpanton.statusbartweak.runtime.layoutsolver.PackedStatusBarLayoutSolver; import se.ajpanton.statusbartweak.runtime.mode.NotificationDisplayStyle; import se.ajpanton.statusbartweak.runtime.mode.SceneKey; +import se.ajpanton.statusbartweak.runtime.notifications.NotificationUnreadTracker; import se.ajpanton.statusbartweak.shell.settings.SbtSettings; final class UnlockedLayoutPlanner { @@ -83,7 +82,7 @@ final class UnlockedLayoutPlanner { ? aodStatusContentBounds(root, aodStatusAnchorBounds) : null; Bounds aodNotificationBounds = scene != null && scene.isAod() - ? aodNotificationBounds(root, anchors, scene) + ? aodNotificationBounds(root, scene) : null; Bounds aodStatusbarBounds = scene != null && scene.isAod() ? aodStatusbarBounds(root, settings, aodNotificationBounds, aodStatusAnchorBounds) @@ -94,7 +93,7 @@ final class UnlockedLayoutPlanner { clockHost, clockLayout, positionFor(settings.clockPosition), - settings)); + sideFor(settings.clockMiddleCutoutSide))); } ClockLayout carrierLayout = carrierLayout(root, collectedIcons, settings, scene); if (carrierLayout != null && carrierLayout.width() > 0) { @@ -102,7 +101,6 @@ final class UnlockedLayoutPlanner { carrierHost, carrierLayout, positionFor(settings.layoutCarrierPosition), - settings.layoutCarrierMiddleAutoNearestSide, sideFor(settings.layoutCarrierMiddleSide))); } int statusCount = statusCountForScene(settings, scene); @@ -123,7 +121,6 @@ final class UnlockedLayoutPlanner { iconHeightPx(statusbarHeight, statusIconHeightSteps(settings, scene))); String[] positions = statusPositionsForScene(settings, scene); String[] middleSides = statusMiddleSidesForScene(settings, scene); - boolean[] autoNearest = statusAutoNearestForScene(settings, scene); int[] verticalOffsets = statusVerticalOffsetsForScene(settings, scene); int statusHeightSteps = statusIconHeightSteps(settings, scene); for (int i = 0; i < statusCount; i++) { @@ -148,12 +145,7 @@ final class UnlockedLayoutPlanner { statusRenderer, placements, positionFor(stringAt(positions, i, settings.layoutStatusPosition)), - booleanAt( - autoNearest, - i, - settings.layoutStatusMiddleAutoNearestSide), - sideFor(stringAt(middleSides, i, settings.layoutStatusMiddleSide)), - true) + sideFor(stringAt(middleSides, i, settings.layoutStatusMiddleSide))) .withSolverCollision( logicalRowTop(statusHeightSteps, verticalOffsetSteps), statusHeightSteps)); @@ -168,15 +160,19 @@ final class UnlockedLayoutPlanner { notificationSeenAppReporter.report( root != null ? root.getContext() : null, unfilteredPlacements); + ArrayList filteredPlacements = + SnapshotIconFilter.notificationPlacements(unfilteredPlacements, settings, scene); + if (isDotNotificationScene(scene)) { + filteredPlacements = unreadNotificationPlacements(filteredPlacements); + } ArrayList rawPlacements = resizePlacementsToHeight( - SnapshotIconFilter.notificationPlacements(unfilteredPlacements, settings, scene), + filteredPlacements, iconHeightPx(statusbarHeight, notificationIconHeightSteps(settings, scene))); notificationRowBounds = placementBounds(rawPlacements); boolean dotNotificationScene = isDotNotificationScene(scene); notificationCount = dotNotificationScene && !rawPlacements.isEmpty() ? 1 : notificationCount; String[] positions = notificationPositionsForScene(settings, scene); String[] middleSides = notificationMiddleSidesForScene(settings, scene); - boolean[] autoNearest = notificationAutoNearestForScene(settings, scene); int[] verticalOffsets = notificationVerticalOffsetsForScene(settings, scene); int notificationHeightSteps = notificationIconHeightSteps(settings, scene); for (int i = 0; i < notificationCount; i++) { @@ -195,10 +191,6 @@ final class UnlockedLayoutPlanner { stepsToPx(verticalOffsetSteps, statusbarHeight)); if (!placements.isEmpty()) { LayoutPosition position = positionFor(stringAt(positions, i, settings.layoutNotifPosition)); - boolean middleAutoNearest = booleanAt( - autoNearest, - i, - settings.layoutNotifMiddleAutoNearestSide); AnchorSide middleSide = sideFor(stringAt(middleSides, i, settings.layoutNotifMiddleSide)); bands.add(dotNotificationScene ? UnlockedLayoutBand.dotIcons( @@ -207,7 +199,6 @@ final class UnlockedLayoutPlanner { notificationRenderer, placements, position, - middleAutoNearest, middleSide) .withSolverCollision( logicalRowTop(notificationHeightSteps, verticalOffsetSteps), @@ -218,9 +209,7 @@ final class UnlockedLayoutPlanner { notificationRenderer, placements, position, - middleAutoNearest, - middleSide, - true) + middleSide) .withSolverCollision( logicalRowTop(notificationHeightSteps, verticalOffsetSteps), notificationHeightSteps)); @@ -254,9 +243,7 @@ final class UnlockedLayoutPlanner { chipRenderer, placements, positionFor(settings.layoutChipPosition), - settings.layoutChipMiddleAutoNearestSide, - sideFor(settings.layoutChipMiddleSide), - false) + sideFor(settings.layoutChipMiddleSide)) .withSolverCollision( logicalRowTop( settings.layoutChipHeightSteps, @@ -265,7 +252,7 @@ final class UnlockedLayoutPlanner { } } if (bands.isEmpty()) { - return new LayoutPlan(null, new ArrayList<>(), new ArrayList<>(), new ArrayList<>()); + return new LayoutPlan(null, new ArrayList<>(), new ArrayList<>(), new ArrayList<>(), null); } ArrayList itemOrder = orderedKinds(settings.layoutItemOrder); splitClockIfNeeded(root, bands, itemOrder, clockCutoutBounds, settings); @@ -540,10 +527,6 @@ final class UnlockedLayoutPlanner { : fallback; } - private boolean booleanAt(boolean[] values, int index, boolean fallback) { - return values != null && index >= 0 && index < values.length ? values[index] : fallback; - } - private int intAt(int[] values, int index, int fallback) { return values != null && index >= 0 && index < values.length ? values[index] : fallback; } @@ -726,6 +709,21 @@ final class UnlockedLayoutPlanner { && scene.notificationDisplayStyle() == NotificationDisplayStyle.DOT; } + private ArrayList unreadNotificationPlacements( + ArrayList placements + ) { + if (placements == null || placements.isEmpty()) { + return placements != null ? placements : new ArrayList<>(); + } + ArrayList unread = new ArrayList<>(placements.size()); + for (SnapshotPlacement placement : placements) { + if (placement != null && NotificationUnreadTracker.isUnread(placement.key)) { + unread.add(placement); + } + } + return unread; + } + private String[] statusPositionsForScene(SbtSettings settings, SceneKey scene) { if (scene != null && scene.isLockscreen()) { return settings.layoutStatusLockPositions; @@ -746,16 +744,6 @@ final class UnlockedLayoutPlanner { return settings.layoutStatusMiddleSides; } - private boolean[] statusAutoNearestForScene(SbtSettings settings, SceneKey scene) { - if (scene != null && scene.isLockscreen()) { - return settings.layoutStatusLockMiddleAutoNearestSides; - } - if (scene != null && scene.isAod()) { - return settings.layoutStatusAodMiddleAutoNearestSides; - } - return settings.layoutStatusMiddleAutoNearestSides; - } - private int[] statusVerticalOffsetsForScene(SbtSettings settings, SceneKey scene) { if (scene != null && scene.isLockscreen()) { return settings.layoutStatusLockVerticalOffsetsPx; @@ -786,16 +774,6 @@ final class UnlockedLayoutPlanner { return settings.layoutNotifMiddleSides; } - private boolean[] notificationAutoNearestForScene(SbtSettings settings, SceneKey scene) { - if (scene != null && scene.isLockscreen()) { - return settings.layoutNotifLockMiddleAutoNearestSides; - } - if (scene != null && scene.isAod()) { - return settings.layoutNotifAodMiddleAutoNearestSides; - } - return settings.layoutNotifMiddleAutoNearestSides; - } - private int[] notificationVerticalOffsetsForScene(SbtSettings settings, SceneKey scene) { if (scene != null && scene.isLockscreen()) { return settings.layoutNotifLockVerticalOffsetsPx; @@ -1119,21 +1097,11 @@ final class UnlockedLayoutPlanner { private ArrayList bottomAlignAodPlacements( ArrayList placements, Bounds aodStatusbarBounds - ) { - return bottomAlignAodPlacements(placements, aodStatusbarBounds, 0); - } - - private ArrayList bottomAlignAodPlacements( - ArrayList placements, - Bounds aodStatusbarBounds, - int bottomInsetPx ) { if (placements == null || placements.isEmpty() || aodStatusbarBounds == null) { return placements; } - int bottom = aodStatusbarBounds.top - + aodStatusbarBounds.height - - Math.max(0, bottomInsetPx); + int bottom = aodStatusbarBounds.top + aodStatusbarBounds.height; ArrayList result = new ArrayList<>(); for (SnapshotPlacement placement : placements) { Bounds bounds = placement.bounds; @@ -1198,7 +1166,7 @@ final class UnlockedLayoutPlanner { if (root == null || cutoutBounds == null || bands == null || settings == null) { return; } - ArrayList middleBands = StatusBarLayoutSolver.bandsForPosition( + ArrayList middleBands = bandsForPosition( bands, LayoutPosition.MIDDLE, itemOrder); @@ -1215,7 +1183,7 @@ final class UnlockedLayoutPlanner { root.getWidth(), cutoutBounds, settings.clockMiddleAutoNearestSide, - sideFor(settings.clockMiddleCutoutSide)); + clockBand.middleSide); if (splitLayouts.size() < 2) { return; } @@ -1224,8 +1192,34 @@ final class UnlockedLayoutPlanner { return; } bands.remove(index); - bands.add(index, UnlockedLayoutBand.fixedClock(clockBand.host, splitLayouts.get(1), SplitRegion.RIGHT, settings)); - bands.add(index, UnlockedLayoutBand.fixedClock(clockBand.host, splitLayouts.get(0), SplitRegion.LEFT, settings)); + bands.add(index, UnlockedLayoutBand.fixedClock( + clockBand.host, + splitLayouts.get(1), + SplitRegion.RIGHT, + clockBand.middleSide)); + bands.add(index, UnlockedLayoutBand.fixedClock( + clockBand.host, + splitLayouts.get(0), + SplitRegion.LEFT, + clockBand.middleSide)); + } + + private ArrayList bandsForPosition( + ArrayList bands, + LayoutPosition position, + ArrayList itemOrder + ) { + ArrayList result = new ArrayList<>(); + for (LayoutItemKind kind : itemOrder) { + for (UnlockedLayoutBand band : bands) { + if (band.kind == kind + && band.position == position + && band.splitRegion == SplitRegion.NONE) { + result.add(band); + } + } + } + return result; } private LayoutEdges layoutEdges( @@ -1240,7 +1234,6 @@ final class UnlockedLayoutPlanner { LayoutEdges aodEdges = aodBurnInEdges( root, settings, - anchors, scene, rootWidth, aodStatusAnchorBounds); @@ -1295,7 +1288,6 @@ final class UnlockedLayoutPlanner { private LayoutEdges aodBurnInEdges( View root, SbtSettings settings, - RootAnchors anchors, SceneKey scene, int rootWidth, Bounds statusBounds @@ -1303,7 +1295,7 @@ final class UnlockedLayoutPlanner { if (root == null || settings == null || rootWidth <= 0) { return null; } - Bounds notificationBounds = aodNotificationBounds(root, anchors, scene); + Bounds notificationBounds = aodNotificationBounds(root, scene); Bounds bounds = aodStatusbarBounds(root, settings, notificationBounds, statusBounds); if (bounds == null) { return null; @@ -1350,7 +1342,7 @@ final class UnlockedLayoutPlanner { if (root == null || root.getWidth() <= 0) { return null; } - Bounds notificationBounds = aodNotificationBounds(root, anchors, scene); + Bounds notificationBounds = aodNotificationBounds(root, scene); Bounds liveMovingStatusBounds = AodLiveStatusbarSource.movingBoundsForRoot(root); Bounds storedStatusBounds = AodStatusbarSourceStore.statusBoundsForRoot( root, @@ -1404,7 +1396,7 @@ final class UnlockedLayoutPlanner { liveMovingStatusBounds.height); } - private Bounds aodNotificationBounds(View root, RootAnchors anchors, SceneKey scene) { + private Bounds aodNotificationBounds(View root, SceneKey scene) { if (scene != null && scene.notificationDisplayStyle() == NotificationDisplayStyle.CARDS) { return null; @@ -1626,6 +1618,9 @@ final class UnlockedLayoutPlanner { return null; } + private record LayoutEdges(int left, int right) { + } + private record StockInsets(int left, int right) { } } diff --git a/app/src/main/java/se/ajpanton/statusbartweak/runtime/render/UnlockedStockSourceCollector.java b/app/src/main/java/se/ajpanton/statusbartweak/runtime/render/UnlockedStockSourceCollector.java index eca574c..ebed5a7 100644 --- a/app/src/main/java/se/ajpanton/statusbartweak/runtime/render/UnlockedStockSourceCollector.java +++ b/app/src/main/java/se/ajpanton/statusbartweak/runtime/render/UnlockedStockSourceCollector.java @@ -15,11 +15,14 @@ import java.util.Locale; import java.util.Objects; import java.util.WeakHashMap; +import se.ajpanton.statusbartweak.runtime.NotificationKeyReflection; import se.ajpanton.statusbartweak.runtime.ViewIdNames; import se.ajpanton.statusbartweak.runtime.hooks.ReflectionSupport; import se.ajpanton.statusbartweak.runtime.layoutsolver.StatusBarLayoutSolver.Bounds; import se.ajpanton.statusbartweak.runtime.mode.NotificationDisplayStyle; import se.ajpanton.statusbartweak.runtime.mode.SceneKey; +import se.ajpanton.statusbartweak.runtime.notifications.NotificationActiveKeyStore; +import se.ajpanton.statusbartweak.runtime.notifications.NotificationUnreadTracker; import se.ajpanton.statusbartweak.shell.settings.SbtSettings; final class UnlockedStockSourceCollector { @@ -76,6 +79,12 @@ final class UnlockedStockSourceCollector { || scene.notificationDisplayStyle() == NotificationDisplayStyle.DOT) { notificationIcons.addAll( LockscreenCardsNotificationIconSourceStore.snapshotSourcesForAodIconsRoot(root)); + if (notificationIcons.isEmpty() + && scene.notificationDisplayStyle() == NotificationDisplayStyle.DOT) { + notificationIcons.addAll( + LockscreenCardsNotificationIconSourceStore + .snapshotAodNotificationPackageSources(root)); + } } } else if (anchors.notificationRoot != null) { collectNotificationSnapshotViews(anchors.notificationRoot, notificationIcons); @@ -178,6 +187,16 @@ final class UnlockedStockSourceCollector { statusSourceSignature = 31 * statusSourceSignature + aodLayoutAnchorSignature(root, anchors, scene); } + int notificationSourceSignature = sourceLayoutListSignature( + previousIcons != null ? previousIcons.notificationIcons : null); + notificationSourceSignature = 31 * notificationSourceSignature + + NotificationActiveKeyStore.generation(); + if (scene != null + && (scene.isAod() || scene.isLockscreen()) + && scene.notificationDisplayStyle() == NotificationDisplayStyle.DOT) { + notificationSourceSignature = 31 * notificationSourceSignature + + NotificationUnreadTracker.generation(); + } return new LayoutInputSignature( scene != null ? scene.toString() : "", root.getWidth(), @@ -188,7 +207,7 @@ final class UnlockedStockSourceCollector { cutout != null ? cutout.top : Integer.MIN_VALUE, cutout != null ? cutout.right : Integer.MIN_VALUE, cutout != null ? cutout.bottom : Integer.MIN_VALUE, - loggingAwareSettingsSignature(root, settings), + layoutSettingsSignature(settings), clockTimeSignature(settings), viewSignatureOrZero(anchors != null ? anchors.clockView : null), shallowTreeSignatureExcluding(anchors != null ? anchors.clockContainer : null, null), @@ -207,7 +226,7 @@ final class UnlockedStockSourceCollector { notificationRootSignature(anchors != null ? anchors.notificationRoot : null), viewSignatureOrZero(anchors != null ? anchors.carrierView : null), statusSourceSignature, - sourceLayoutListSignature(previousIcons != null ? previousIcons.notificationIcons : null), + notificationSourceSignature, chipSourceSignature); } @@ -682,7 +701,13 @@ final class UnlockedStockSourceCollector { private void collectNotificationSnapshotViews(View source, ArrayList out) { if (isNotificationSnapshotCandidate(source)) { - out.add(new SnapshotSource(source, SnapshotMode.NOTIFICATION_DRAWABLE)); + String key = NotificationKeyReflection.keyForIconView(source); + if (key != null + && NotificationActiveKeyStore.hasSnapshot() + && !NotificationActiveKeyStore.isActive(key)) { + return; + } + out.add(new SnapshotSource(source, SnapshotMode.NOTIFICATION_DRAWABLE, key)); return; } if (source instanceof ViewGroup group) { @@ -967,22 +992,7 @@ final class UnlockedStockSourceCollector { if (view == null) { 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(); - if (view instanceof ViewGroup group) { - result = 31 * result + group.getChildCount(); - for (int i = 0; i < group.getChildCount(); i++) { - View child = group.getChildAt(i); - result = 31 * result + System.identityHashCode(child); - result = 31 * result + child.getClass().getName().hashCode(); - result = 31 * result + child.getId(); - result = 31 * result + child.getVisibility(); - } - } - return result; + return sourceLayoutSignature(view); } private static int sourceLayoutListSignature(ArrayList sources) { @@ -1007,6 +1017,7 @@ final class UnlockedStockSourceCollector { int result = 17; result = 31 * result + System.identityHashCode(view); result = 31 * result + view.getClass().getName().hashCode(); + result = 31 * result + (view.isAttachedToWindow() ? 1 : 0); result = 31 * result + view.getId(); result = 31 * result + view.getVisibility(); result = 31 * result + width; @@ -1207,12 +1218,10 @@ final class UnlockedStockSourceCollector { settings.layoutCarrierPosition, settings.layoutCarrierEnabledLockscreen, settings.layoutCarrierMiddleSide, - settings.layoutCarrierMiddleAutoNearestSide, settings.layoutCarrierVerticalOffsetPx, settings.layoutChipPosition, settings.layoutChipEnabledUnlocked, settings.layoutChipMiddleSide, - settings.layoutChipMiddleAutoNearestSide, settings.layoutChipVerticalOffsetPx, settings.layoutChipHeightSteps, settings.layoutNotifPosition, @@ -1221,44 +1230,36 @@ final class UnlockedStockSourceCollector { settings.layoutNotifUnlockedCount, Arrays.hashCode(settings.layoutNotifPositions), Arrays.hashCode(settings.layoutNotifMiddleSides), - Arrays.hashCode(settings.layoutNotifMiddleAutoNearestSides), Arrays.hashCode(settings.layoutNotifVerticalOffsetsPx), settings.layoutNotifEnabledLockscreen, settings.layoutNotifLockCount, Arrays.hashCode(settings.layoutNotifLockPositions), Arrays.hashCode(settings.layoutNotifLockMiddleSides), - Arrays.hashCode(settings.layoutNotifLockMiddleAutoNearestSides), Arrays.hashCode(settings.layoutNotifLockVerticalOffsetsPx), settings.layoutNotifEnabledAod, settings.layoutNotifAodCount, Arrays.hashCode(settings.layoutNotifAodPositions), Arrays.hashCode(settings.layoutNotifAodMiddleSides), - Arrays.hashCode(settings.layoutNotifAodMiddleAutoNearestSides), Arrays.hashCode(settings.layoutNotifAodVerticalOffsetsPx), settings.layoutNotifMiddleSide, - settings.layoutNotifMiddleAutoNearestSide, settings.layoutNotifVerticalOffsetPx, settings.layoutStatusPosition, settings.layoutStatusEnabledUnlocked, settings.layoutStatusUnlockedCount, Arrays.hashCode(settings.layoutStatusPositions), Arrays.hashCode(settings.layoutStatusMiddleSides), - Arrays.hashCode(settings.layoutStatusMiddleAutoNearestSides), Arrays.hashCode(settings.layoutStatusVerticalOffsetsPx), settings.layoutStatusEnabledLockscreen, settings.layoutStatusLockCount, Arrays.hashCode(settings.layoutStatusLockPositions), Arrays.hashCode(settings.layoutStatusLockMiddleSides), - Arrays.hashCode(settings.layoutStatusLockMiddleAutoNearestSides), Arrays.hashCode(settings.layoutStatusLockVerticalOffsetsPx), settings.layoutStatusEnabledAod, settings.layoutStatusAodCount, Arrays.hashCode(settings.layoutStatusAodPositions), Arrays.hashCode(settings.layoutStatusAodMiddleSides), - Arrays.hashCode(settings.layoutStatusAodMiddleAutoNearestSides), Arrays.hashCode(settings.layoutStatusAodVerticalOffsetsPx), settings.layoutStatusMiddleSide, - settings.layoutStatusMiddleAutoNearestSide, settings.layoutStatusVerticalOffsetPx, settings.systemIconBlockedModes, settings.appIconBlockedModes, @@ -1269,11 +1270,4 @@ final class UnlockedStockSourceCollector { settings.statusChipsHideCallUnlocked); } - private int loggingAwareSettingsSignature(View root, SbtSettings settings) { - int result = layoutSettingsSignature(settings); - boolean logsEnabled = root != null - && root.getContext() != null - && SbtSettings.isDebugLogWritingEnabled(root.getContext()); - return 31 * result + (logsEnabled ? 1 : 0); - } } diff --git a/app/src/main/java/se/ajpanton/statusbartweak/shell/settings/SbtDefaults.java b/app/src/main/java/se/ajpanton/statusbartweak/shell/settings/SbtDefaults.java index fbaf5f8..5637c3e 100644 --- a/app/src/main/java/se/ajpanton/statusbartweak/shell/settings/SbtDefaults.java +++ b/app/src/main/java/se/ajpanton/statusbartweak/shell/settings/SbtDefaults.java @@ -107,24 +107,19 @@ public final class SbtDefaults { public static final String LAYOUT_CARRIER_POSITION_DEFAULT = "left"; public static final boolean LAYOUT_CARRIER_ENABLED_LOCKSCREEN_DEFAULT = true; public static final String LAYOUT_CARRIER_MIDDLE_SIDE_DEFAULT = "left"; - public static final boolean LAYOUT_CARRIER_MIDDLE_AUTO_NEAREST_SIDE_DEFAULT = true; public static final int LAYOUT_CARRIER_VERTICAL_OFFSET_PX_DEFAULT = 0; public static final String LAYOUT_CHIP_POSITION_DEFAULT = "left"; - public static final boolean LAYOUT_CHIP_ENABLED_LOCKSCREEN_DEFAULT = true; public static final boolean LAYOUT_CHIP_ENABLED_UNLOCKED_DEFAULT = true; public static final String LAYOUT_CHIP_MIDDLE_SIDE_DEFAULT = "left"; - public static final boolean LAYOUT_CHIP_MIDDLE_AUTO_NEAREST_SIDE_DEFAULT = true; public static final int LAYOUT_CHIP_VERTICAL_OFFSET_PX_DEFAULT = 0; public static final int LAYOUT_CHIP_HEIGHT_STEPS_DEFAULT = 52; public static final String LAYOUT_NOTIF_POSITION_DEFAULT = "left"; public static final String LAYOUT_NOTIF_SORT_ORDER_DEFAULT = "automatic"; - public static final boolean LAYOUT_NOTIF_SHOW_DOT_IF_TRUNCATED_DEFAULT = true; public static final boolean LAYOUT_NOTIF_ENABLED_AOD_DEFAULT = true; public static final boolean LAYOUT_NOTIF_ENABLED_LOCKSCREEN_DEFAULT = true; public static final boolean LAYOUT_NOTIF_ENABLED_UNLOCKED_DEFAULT = true; public static final int LAYOUT_NOTIF_UNLOCKED_COUNT_DEFAULT = 1; public static final String LAYOUT_NOTIF_MIDDLE_SIDE_DEFAULT = "left"; - public static final boolean LAYOUT_NOTIF_MIDDLE_AUTO_NEAREST_SIDE_DEFAULT = true; public static final int LAYOUT_NOTIF_VERTICAL_OFFSET_PX_DEFAULT = 0; public static final int LAYOUT_NOTIF_ICON_HEIGHT_STEPS_DEFAULT = 46; public static final int LAYOUT_NOTIF_LOCK_ICON_HEIGHT_STEPS_DEFAULT = 46; @@ -136,9 +131,7 @@ public final class SbtDefaults { public static final boolean LAYOUT_STATUS_ENABLED_LOCKSCREEN_DEFAULT = true; public static final boolean LAYOUT_STATUS_ENABLED_UNLOCKED_DEFAULT = true; public static final int LAYOUT_STATUS_UNLOCKED_COUNT_DEFAULT = 1; - public static final boolean LAYOUT_STATUS_SHOW_DOT_IF_TRUNCATED_DEFAULT = true; public static final String LAYOUT_STATUS_MIDDLE_SIDE_DEFAULT = "left"; - public static final boolean LAYOUT_STATUS_MIDDLE_AUTO_NEAREST_SIDE_DEFAULT = true; public static final int LAYOUT_STATUS_VERTICAL_OFFSET_PX_DEFAULT = 0; public static final int LAYOUT_STATUS_ICON_HEIGHT_STEPS_DEFAULT = 38; public static final int LAYOUT_ICON_HEIGHT_STEPS_MIN = 10; diff --git a/app/src/main/java/se/ajpanton/statusbartweak/shell/settings/SbtSettings.java b/app/src/main/java/se/ajpanton/statusbartweak/shell/settings/SbtSettings.java index 848cfe0..f023f30 100644 --- a/app/src/main/java/se/ajpanton/statusbartweak/shell/settings/SbtSettings.java +++ b/app/src/main/java/se/ajpanton/statusbartweak/shell/settings/SbtSettings.java @@ -103,18 +103,14 @@ public final class SbtSettings { public static final String KEY_LAYOUT_CARRIER_POSITION = "layout_carrier_position"; public static final String KEY_LAYOUT_CARRIER_ENABLED_LOCKSCREEN = "layout_carrier_enabled_lockscreen"; public static final String KEY_LAYOUT_CARRIER_MIDDLE_SIDE = "layout_carrier_middle_side"; - public static final String KEY_LAYOUT_CARRIER_MIDDLE_AUTO_NEAREST_SIDE = "layout_carrier_middle_auto_nearest_side"; public static final String KEY_LAYOUT_CARRIER_VERTICAL_OFFSET_PX = "layout_carrier_vertical_offset_px"; public static final String KEY_LAYOUT_CHIP_POSITION = "layout_chip_position"; - public static final String KEY_LAYOUT_CHIP_ENABLED_LOCKSCREEN = "layout_chip_enabled_lockscreen"; public static final String KEY_LAYOUT_CHIP_ENABLED_UNLOCKED = "layout_chip_enabled_unlocked"; public static final String KEY_LAYOUT_CHIP_MIDDLE_SIDE = "layout_chip_middle_side"; - public static final String KEY_LAYOUT_CHIP_MIDDLE_AUTO_NEAREST_SIDE = "layout_chip_middle_auto_nearest_side"; public static final String KEY_LAYOUT_CHIP_VERTICAL_OFFSET_PX = "layout_chip_vertical_offset_px"; public static final String KEY_LAYOUT_CHIP_HEIGHT_STEPS = "layout_chip_height_steps"; public static final String KEY_LAYOUT_NOTIF_POSITION = "layout_notif_position"; public static final String KEY_LAYOUT_NOTIF_SORT_ORDER = "layout_notif_sort_order"; - public static final String KEY_LAYOUT_NOTIF_SHOW_DOT_IF_TRUNCATED = "layout_notif_show_dot_if_truncated"; public static final String KEY_LAYOUT_NOTIF_ENABLED_AOD = "layout_notif_enabled_aod"; public static final String KEY_LAYOUT_NOTIF_ENABLED_LOCKSCREEN = "layout_notif_enabled_lockscreen"; public static final String KEY_LAYOUT_NOTIF_ENABLED_UNLOCKED = "layout_notif_enabled_unlocked"; @@ -123,22 +119,17 @@ public final class SbtSettings { public static final String KEY_LAYOUT_NOTIF_AOD_COUNT = "layout_aod_notifications_count"; public static final String KEY_LAYOUT_NOTIF_LOCK_POSITION = "layout_lock_notifications_position"; public static final String KEY_LAYOUT_NOTIF_LOCK_MIDDLE_SIDE = "layout_lock_notifications_middle_side"; - public static final String KEY_LAYOUT_NOTIF_LOCK_MIDDLE_AUTO_NEAREST_SIDE = - "layout_lock_notifications_middle_auto_nearest_side"; public static final String KEY_LAYOUT_NOTIF_LOCK_VERTICAL_OFFSET_PX = "layout_lock_notifications_vertical_offset_px"; public static final String KEY_LAYOUT_NOTIF_LOCK_ICON_HEIGHT_STEPS = "layout_lock_notifications_icon_height_steps"; public static final String KEY_LAYOUT_NOTIF_AOD_POSITION = "layout_aod_notifications_position"; public static final String KEY_LAYOUT_NOTIF_AOD_MIDDLE_SIDE = "layout_aod_notifications_middle_side"; - public static final String KEY_LAYOUT_NOTIF_AOD_MIDDLE_AUTO_NEAREST_SIDE = - "layout_aod_notifications_middle_auto_nearest_side"; public static final String KEY_LAYOUT_NOTIF_AOD_VERTICAL_OFFSET_PX = "layout_aod_notifications_vertical_offset_px"; public static final String KEY_LAYOUT_NOTIF_AOD_ICON_HEIGHT_STEPS = "layout_aod_notifications_icon_height_steps"; public static final String KEY_LAYOUT_NOTIF_MIDDLE_SIDE = "layout_notif_middle_side"; - public static final String KEY_LAYOUT_NOTIF_MIDDLE_AUTO_NEAREST_SIDE = "layout_notif_middle_auto_nearest_side"; public static final String KEY_LAYOUT_NOTIF_VERTICAL_OFFSET_PX = "layout_notif_vertical_offset_px"; public static final String KEY_LAYOUT_NOTIF_ICON_HEIGHT_STEPS = "layout_notif_icon_height_steps"; public static final String KEY_LAYOUT_STATUS_POSITION = "layout_status_position"; @@ -150,23 +141,17 @@ public final class SbtSettings { public static final String KEY_LAYOUT_STATUS_AOD_COUNT = "layout_aod_status_count"; public static final String KEY_LAYOUT_STATUS_LOCK_POSITION = "layout_lock_status_position"; public static final String KEY_LAYOUT_STATUS_LOCK_MIDDLE_SIDE = "layout_lock_status_middle_side"; - public static final String KEY_LAYOUT_STATUS_LOCK_MIDDLE_AUTO_NEAREST_SIDE = - "layout_lock_status_middle_auto_nearest_side"; public static final String KEY_LAYOUT_STATUS_LOCK_VERTICAL_OFFSET_PX = "layout_lock_status_vertical_offset_px"; public static final String KEY_LAYOUT_STATUS_LOCK_ICON_HEIGHT_STEPS = "layout_lock_status_icon_height_steps"; public static final String KEY_LAYOUT_STATUS_AOD_POSITION = "layout_aod_status_position"; public static final String KEY_LAYOUT_STATUS_AOD_MIDDLE_SIDE = "layout_aod_status_middle_side"; - public static final String KEY_LAYOUT_STATUS_AOD_MIDDLE_AUTO_NEAREST_SIDE = - "layout_aod_status_middle_auto_nearest_side"; public static final String KEY_LAYOUT_STATUS_AOD_VERTICAL_OFFSET_PX = "layout_aod_status_vertical_offset_px"; public static final String KEY_LAYOUT_STATUS_AOD_ICON_HEIGHT_STEPS = "layout_aod_status_icon_height_steps"; - public static final String KEY_LAYOUT_STATUS_SHOW_DOT_IF_TRUNCATED = "layout_status_show_dot_if_truncated"; public static final String KEY_LAYOUT_STATUS_MIDDLE_SIDE = "layout_status_middle_side"; - public static final String KEY_LAYOUT_STATUS_MIDDLE_AUTO_NEAREST_SIDE = "layout_status_middle_auto_nearest_side"; public static final String KEY_LAYOUT_STATUS_VERTICAL_OFFSET_PX = "layout_status_vertical_offset_px"; public static final String KEY_LAYOUT_STATUS_ICON_HEIGHT_STEPS = "layout_status_icon_height_steps"; public static final String KEY_SYSTEM_ICON_BLOCKED_MODES = SystemIconRules.PREF_KEY_BLOCKED_MODES; @@ -182,10 +167,6 @@ public final class SbtSettings { return suffixedKey(KEY_LAYOUT_NOTIF_MIDDLE_SIDE, index); } - public static String layoutNotifMiddleAutoNearestSideKey(int index) { - return suffixedKey(KEY_LAYOUT_NOTIF_MIDDLE_AUTO_NEAREST_SIDE, index); - } - public static String layoutNotifVerticalOffsetKey(int index) { return suffixedKey(KEY_LAYOUT_NOTIF_VERTICAL_OFFSET_PX, index); } @@ -198,10 +179,6 @@ public final class SbtSettings { return suffixedKey(KEY_LAYOUT_STATUS_MIDDLE_SIDE, index); } - public static String layoutStatusMiddleAutoNearestSideKey(int index) { - return suffixedKey(KEY_LAYOUT_STATUS_MIDDLE_AUTO_NEAREST_SIDE, index); - } - public static String layoutStatusVerticalOffsetKey(int index) { return suffixedKey(KEY_LAYOUT_STATUS_VERTICAL_OFFSET_PX, index); } @@ -214,10 +191,6 @@ public final class SbtSettings { return suffixedKey(KEY_LAYOUT_NOTIF_LOCK_MIDDLE_SIDE, index); } - public static String layoutLockNotifMiddleAutoNearestSideKey(int index) { - return suffixedKey(KEY_LAYOUT_NOTIF_LOCK_MIDDLE_AUTO_NEAREST_SIDE, index); - } - public static String layoutLockNotifVerticalOffsetKey(int index) { return suffixedKey(KEY_LAYOUT_NOTIF_LOCK_VERTICAL_OFFSET_PX, index); } @@ -234,10 +207,6 @@ public final class SbtSettings { return suffixedKey(KEY_LAYOUT_NOTIF_AOD_MIDDLE_SIDE, index); } - public static String layoutAodNotifMiddleAutoNearestSideKey(int index) { - return suffixedKey(KEY_LAYOUT_NOTIF_AOD_MIDDLE_AUTO_NEAREST_SIDE, index); - } - public static String layoutAodNotifVerticalOffsetKey(int index) { return suffixedKey(KEY_LAYOUT_NOTIF_AOD_VERTICAL_OFFSET_PX, index); } @@ -254,10 +223,6 @@ public final class SbtSettings { return suffixedKey(KEY_LAYOUT_STATUS_LOCK_MIDDLE_SIDE, index); } - public static String layoutLockStatusMiddleAutoNearestSideKey(int index) { - return suffixedKey(KEY_LAYOUT_STATUS_LOCK_MIDDLE_AUTO_NEAREST_SIDE, index); - } - public static String layoutLockStatusVerticalOffsetKey(int index) { return suffixedKey(KEY_LAYOUT_STATUS_LOCK_VERTICAL_OFFSET_PX, index); } @@ -274,10 +239,6 @@ public final class SbtSettings { return suffixedKey(KEY_LAYOUT_STATUS_AOD_MIDDLE_SIDE, index); } - public static String layoutAodStatusMiddleAutoNearestSideKey(int index) { - return suffixedKey(KEY_LAYOUT_STATUS_AOD_MIDDLE_AUTO_NEAREST_SIDE, index); - } - public static String layoutAodStatusVerticalOffsetKey(int index) { return suffixedKey(KEY_LAYOUT_STATUS_AOD_VERTICAL_OFFSET_PX, index); } @@ -350,38 +311,30 @@ public final class SbtSettings { public final String layoutCarrierPosition; public final boolean layoutCarrierEnabledLockscreen; public final String layoutCarrierMiddleSide; - public final boolean layoutCarrierMiddleAutoNearestSide; public final int layoutCarrierVerticalOffsetPx; public final String layoutChipPosition; - public final boolean layoutChipEnabledLockscreen; public final boolean layoutChipEnabledUnlocked; public final String layoutChipMiddleSide; - public final boolean layoutChipMiddleAutoNearestSide; public final int layoutChipVerticalOffsetPx; public final int layoutChipHeightSteps; public final String layoutNotifPosition; public final String layoutNotifSortOrder; - public final boolean layoutNotifShowDotIfTruncated; public final boolean layoutNotifEnabledAod; public final boolean layoutNotifEnabledLockscreen; public final boolean layoutNotifEnabledUnlocked; public final int layoutNotifUnlockedCount; public final String[] layoutNotifPositions; public final String[] layoutNotifMiddleSides; - public final boolean[] layoutNotifMiddleAutoNearestSides; public final int[] layoutNotifVerticalOffsetsPx; public final int layoutNotifLockCount; public final String[] layoutNotifLockPositions; public final String[] layoutNotifLockMiddleSides; - public final boolean[] layoutNotifLockMiddleAutoNearestSides; public final int[] layoutNotifLockVerticalOffsetsPx; public final int layoutNotifAodCount; public final String[] layoutNotifAodPositions; public final String[] layoutNotifAodMiddleSides; - public final boolean[] layoutNotifAodMiddleAutoNearestSides; public final int[] layoutNotifAodVerticalOffsetsPx; public final String layoutNotifMiddleSide; - public final boolean layoutNotifMiddleAutoNearestSide; public final int layoutNotifVerticalOffsetPx; public final int layoutNotifIconHeightSteps; public final int layoutNotifLockIconHeightSteps; @@ -393,21 +346,16 @@ public final class SbtSettings { public final int layoutStatusUnlockedCount; public final String[] layoutStatusPositions; public final String[] layoutStatusMiddleSides; - public final boolean[] layoutStatusMiddleAutoNearestSides; public final int[] layoutStatusVerticalOffsetsPx; public final int layoutStatusLockCount; public final String[] layoutStatusLockPositions; public final String[] layoutStatusLockMiddleSides; - public final boolean[] layoutStatusLockMiddleAutoNearestSides; public final int[] layoutStatusLockVerticalOffsetsPx; public final int layoutStatusAodCount; public final String[] layoutStatusAodPositions; public final String[] layoutStatusAodMiddleSides; - public final boolean[] layoutStatusAodMiddleAutoNearestSides; public final int[] layoutStatusAodVerticalOffsetsPx; - public final boolean layoutStatusShowDotIfTruncated; public final String layoutStatusMiddleSide; - public final boolean layoutStatusMiddleAutoNearestSide; public final int layoutStatusVerticalOffsetPx; public final int layoutStatusIconHeightSteps; public final int layoutStatusLockIconHeightSteps; @@ -485,23 +433,18 @@ public final class SbtSettings { String layoutCarrierPosition, boolean layoutCarrierEnabledLockscreen, String layoutCarrierMiddleSide, - boolean layoutCarrierMiddleAutoNearestSide, int layoutCarrierVerticalOffsetPx, String layoutChipPosition, - boolean layoutChipEnabledLockscreen, boolean layoutChipEnabledUnlocked, String layoutChipMiddleSide, - boolean layoutChipMiddleAutoNearestSide, int layoutChipVerticalOffsetPx, int layoutChipHeightSteps, String layoutNotifPosition, String layoutNotifSortOrder, - boolean layoutNotifShowDotIfTruncated, boolean layoutNotifEnabledAod, boolean layoutNotifEnabledLockscreen, boolean layoutNotifEnabledUnlocked, String layoutNotifMiddleSide, - boolean layoutNotifMiddleAutoNearestSide, int layoutNotifVerticalOffsetPx, int layoutNotifIconHeightSteps, int layoutNotifLockIconHeightSteps, @@ -509,25 +452,20 @@ public final class SbtSettings { int layoutNotifUnlockedCount, String[] layoutNotifPositions, String[] layoutNotifMiddleSides, - boolean[] layoutNotifMiddleAutoNearestSides, int[] layoutNotifVerticalOffsetsPx, int layoutNotifLockCount, String[] layoutNotifLockPositions, String[] layoutNotifLockMiddleSides, - boolean[] layoutNotifLockMiddleAutoNearestSides, int[] layoutNotifLockVerticalOffsetsPx, int layoutNotifAodCount, String[] layoutNotifAodPositions, String[] layoutNotifAodMiddleSides, - boolean[] layoutNotifAodMiddleAutoNearestSides, int[] layoutNotifAodVerticalOffsetsPx, String layoutStatusPosition, boolean layoutStatusEnabledAod, boolean layoutStatusEnabledLockscreen, boolean layoutStatusEnabledUnlocked, - boolean layoutStatusShowDotIfTruncated, String layoutStatusMiddleSide, - boolean layoutStatusMiddleAutoNearestSide, int layoutStatusVerticalOffsetPx, int layoutStatusIconHeightSteps, int layoutStatusLockIconHeightSteps, @@ -535,17 +473,14 @@ public final class SbtSettings { int layoutStatusUnlockedCount, String[] layoutStatusPositions, String[] layoutStatusMiddleSides, - boolean[] layoutStatusMiddleAutoNearestSides, int[] layoutStatusVerticalOffsetsPx, int layoutStatusLockCount, String[] layoutStatusLockPositions, String[] layoutStatusLockMiddleSides, - boolean[] layoutStatusLockMiddleAutoNearestSides, int[] layoutStatusLockVerticalOffsetsPx, int layoutStatusAodCount, String[] layoutStatusAodPositions, String[] layoutStatusAodMiddleSides, - boolean[] layoutStatusAodMiddleAutoNearestSides, int[] layoutStatusAodVerticalOffsetsPx, Map clockCameraTypeOverrides, Map systemIconBlockedModes, @@ -671,7 +606,6 @@ public final class SbtSettings { this.layoutCarrierMiddleSide = layoutCarrierMiddleSide != null ? layoutCarrierMiddleSide : SbtDefaults.LAYOUT_CARRIER_MIDDLE_SIDE_DEFAULT; - this.layoutCarrierMiddleAutoNearestSide = layoutCarrierMiddleAutoNearestSide; this.layoutCarrierVerticalOffsetPx = clampInt( layoutCarrierVerticalOffsetPx, SbtDefaults.CLOCK_VERTICAL_OFFSET_PX_MIN, @@ -679,12 +613,10 @@ public final class SbtSettings { this.layoutChipPosition = layoutChipPosition != null ? layoutChipPosition : SbtDefaults.LAYOUT_CHIP_POSITION_DEFAULT; - this.layoutChipEnabledLockscreen = layoutChipEnabledLockscreen; this.layoutChipEnabledUnlocked = layoutChipEnabledUnlocked; this.layoutChipMiddleSide = layoutChipMiddleSide != null ? layoutChipMiddleSide : SbtDefaults.LAYOUT_CHIP_MIDDLE_SIDE_DEFAULT; - this.layoutChipMiddleAutoNearestSide = layoutChipMiddleAutoNearestSide; this.layoutChipVerticalOffsetPx = clampInt( layoutChipVerticalOffsetPx, SbtDefaults.CLOCK_VERTICAL_OFFSET_PX_MIN, @@ -696,14 +628,12 @@ public final class SbtSettings { this.layoutNotifSortOrder = layoutNotifSortOrder != null ? layoutNotifSortOrder : SbtDefaults.LAYOUT_NOTIF_SORT_ORDER_DEFAULT; - this.layoutNotifShowDotIfTruncated = layoutNotifShowDotIfTruncated; this.layoutNotifEnabledAod = layoutNotifEnabledAod; this.layoutNotifEnabledLockscreen = layoutNotifEnabledLockscreen; this.layoutNotifEnabledUnlocked = layoutNotifEnabledUnlocked; this.layoutNotifMiddleSide = layoutNotifMiddleSide != null ? layoutNotifMiddleSide : SbtDefaults.LAYOUT_NOTIF_MIDDLE_SIDE_DEFAULT; - this.layoutNotifMiddleAutoNearestSide = layoutNotifMiddleAutoNearestSide; this.layoutNotifVerticalOffsetPx = clampInt( layoutNotifVerticalOffsetPx, SbtDefaults.CLOCK_VERTICAL_OFFSET_PX_MIN, @@ -720,10 +650,6 @@ public final class SbtSettings { layoutNotifMiddleSides, this.layoutNotifMiddleSide, SbtDefaults.LAYOUT_ICON_CONTAINER_COUNT_MAX); - this.layoutNotifMiddleAutoNearestSides = sanitizeBooleanArray( - layoutNotifMiddleAutoNearestSides, - this.layoutNotifMiddleAutoNearestSide, - SbtDefaults.LAYOUT_ICON_CONTAINER_COUNT_MAX); this.layoutNotifVerticalOffsetsPx = sanitizeIntArray( layoutNotifVerticalOffsetsPx, this.layoutNotifVerticalOffsetPx, @@ -739,10 +665,6 @@ public final class SbtSettings { layoutNotifLockMiddleSides, this.layoutNotifMiddleSide, SbtDefaults.LAYOUT_ICON_CONTAINER_COUNT_MAX); - this.layoutNotifLockMiddleAutoNearestSides = sanitizeBooleanArray( - layoutNotifLockMiddleAutoNearestSides, - this.layoutNotifMiddleAutoNearestSide, - SbtDefaults.LAYOUT_ICON_CONTAINER_COUNT_MAX); this.layoutNotifLockVerticalOffsetsPx = sanitizeIntArray( layoutNotifLockVerticalOffsetsPx, this.layoutNotifVerticalOffsetPx, @@ -758,10 +680,6 @@ public final class SbtSettings { layoutNotifAodMiddleSides, this.layoutNotifMiddleSide, SbtDefaults.LAYOUT_ICON_CONTAINER_COUNT_MAX); - this.layoutNotifAodMiddleAutoNearestSides = sanitizeBooleanArray( - layoutNotifAodMiddleAutoNearestSides, - this.layoutNotifMiddleAutoNearestSide, - SbtDefaults.LAYOUT_ICON_CONTAINER_COUNT_MAX); this.layoutNotifAodVerticalOffsetsPx = sanitizeIntArray( layoutNotifAodVerticalOffsetsPx, this.layoutNotifVerticalOffsetPx, @@ -774,11 +692,9 @@ public final class SbtSettings { this.layoutStatusEnabledAod = layoutStatusEnabledAod; this.layoutStatusEnabledLockscreen = layoutStatusEnabledLockscreen; this.layoutStatusEnabledUnlocked = layoutStatusEnabledUnlocked; - this.layoutStatusShowDotIfTruncated = layoutStatusShowDotIfTruncated; this.layoutStatusMiddleSide = layoutStatusMiddleSide != null ? layoutStatusMiddleSide : SbtDefaults.LAYOUT_STATUS_MIDDLE_SIDE_DEFAULT; - this.layoutStatusMiddleAutoNearestSide = layoutStatusMiddleAutoNearestSide; this.layoutStatusVerticalOffsetPx = clampInt( layoutStatusVerticalOffsetPx, SbtDefaults.CLOCK_VERTICAL_OFFSET_PX_MIN, @@ -795,10 +711,6 @@ public final class SbtSettings { layoutStatusMiddleSides, this.layoutStatusMiddleSide, SbtDefaults.LAYOUT_ICON_CONTAINER_COUNT_MAX); - this.layoutStatusMiddleAutoNearestSides = sanitizeBooleanArray( - layoutStatusMiddleAutoNearestSides, - this.layoutStatusMiddleAutoNearestSide, - SbtDefaults.LAYOUT_ICON_CONTAINER_COUNT_MAX); this.layoutStatusVerticalOffsetsPx = sanitizeIntArray( layoutStatusVerticalOffsetsPx, this.layoutStatusVerticalOffsetPx, @@ -814,10 +726,6 @@ public final class SbtSettings { layoutStatusLockMiddleSides, this.layoutStatusMiddleSide, SbtDefaults.LAYOUT_ICON_CONTAINER_COUNT_MAX); - this.layoutStatusLockMiddleAutoNearestSides = sanitizeBooleanArray( - layoutStatusLockMiddleAutoNearestSides, - this.layoutStatusMiddleAutoNearestSide, - SbtDefaults.LAYOUT_ICON_CONTAINER_COUNT_MAX); this.layoutStatusLockVerticalOffsetsPx = sanitizeIntArray( layoutStatusLockVerticalOffsetsPx, this.layoutStatusVerticalOffsetPx, @@ -833,10 +741,6 @@ public final class SbtSettings { layoutStatusAodMiddleSides, this.layoutStatusMiddleSide, SbtDefaults.LAYOUT_ICON_CONTAINER_COUNT_MAX); - this.layoutStatusAodMiddleAutoNearestSides = sanitizeBooleanArray( - layoutStatusAodMiddleAutoNearestSides, - this.layoutStatusMiddleAutoNearestSide, - SbtDefaults.LAYOUT_ICON_CONTAINER_COUNT_MAX); this.layoutStatusAodVerticalOffsetsPx = sanitizeIntArray( layoutStatusAodVerticalOffsetsPx, this.layoutStatusVerticalOffsetPx, @@ -936,23 +840,18 @@ public final class SbtSettings { SbtDefaults.LAYOUT_CARRIER_POSITION_DEFAULT, SbtDefaults.LAYOUT_CARRIER_ENABLED_LOCKSCREEN_DEFAULT, SbtDefaults.LAYOUT_CARRIER_MIDDLE_SIDE_DEFAULT, - SbtDefaults.LAYOUT_CARRIER_MIDDLE_AUTO_NEAREST_SIDE_DEFAULT, SbtDefaults.LAYOUT_CARRIER_VERTICAL_OFFSET_PX_DEFAULT, SbtDefaults.LAYOUT_CHIP_POSITION_DEFAULT, - SbtDefaults.LAYOUT_CHIP_ENABLED_LOCKSCREEN_DEFAULT, SbtDefaults.LAYOUT_CHIP_ENABLED_UNLOCKED_DEFAULT, SbtDefaults.LAYOUT_CHIP_MIDDLE_SIDE_DEFAULT, - SbtDefaults.LAYOUT_CHIP_MIDDLE_AUTO_NEAREST_SIDE_DEFAULT, SbtDefaults.LAYOUT_CHIP_VERTICAL_OFFSET_PX_DEFAULT, SbtDefaults.LAYOUT_CHIP_HEIGHT_STEPS_DEFAULT, SbtDefaults.LAYOUT_NOTIF_POSITION_DEFAULT, SbtDefaults.LAYOUT_NOTIF_SORT_ORDER_DEFAULT, - SbtDefaults.LAYOUT_NOTIF_SHOW_DOT_IF_TRUNCATED_DEFAULT, SbtDefaults.LAYOUT_NOTIF_ENABLED_AOD_DEFAULT, SbtDefaults.LAYOUT_NOTIF_ENABLED_LOCKSCREEN_DEFAULT, SbtDefaults.LAYOUT_NOTIF_ENABLED_UNLOCKED_DEFAULT, SbtDefaults.LAYOUT_NOTIF_MIDDLE_SIDE_DEFAULT, - SbtDefaults.LAYOUT_NOTIF_MIDDLE_AUTO_NEAREST_SIDE_DEFAULT, SbtDefaults.LAYOUT_NOTIF_VERTICAL_OFFSET_PX_DEFAULT, SbtDefaults.LAYOUT_NOTIF_ICON_HEIGHT_STEPS_DEFAULT, SbtDefaults.LAYOUT_NOTIF_LOCK_ICON_HEIGHT_STEPS_DEFAULT, @@ -961,24 +860,19 @@ public final class SbtSettings { null, null, null, - null, SbtDefaults.LAYOUT_NOTIF_UNLOCKED_COUNT_DEFAULT, null, null, null, - null, SbtDefaults.LAYOUT_NOTIF_UNLOCKED_COUNT_DEFAULT, null, null, null, - null, SbtDefaults.LAYOUT_STATUS_POSITION_DEFAULT, SbtDefaults.LAYOUT_STATUS_ENABLED_AOD_DEFAULT, SbtDefaults.LAYOUT_STATUS_ENABLED_LOCKSCREEN_DEFAULT, SbtDefaults.LAYOUT_STATUS_ENABLED_UNLOCKED_DEFAULT, - SbtDefaults.LAYOUT_STATUS_SHOW_DOT_IF_TRUNCATED_DEFAULT, SbtDefaults.LAYOUT_STATUS_MIDDLE_SIDE_DEFAULT, - SbtDefaults.LAYOUT_STATUS_MIDDLE_AUTO_NEAREST_SIDE_DEFAULT, SbtDefaults.LAYOUT_STATUS_VERTICAL_OFFSET_PX_DEFAULT, SbtDefaults.LAYOUT_STATUS_ICON_HEIGHT_STEPS_DEFAULT, SbtDefaults.LAYOUT_STATUS_ICON_HEIGHT_STEPS_DEFAULT, @@ -987,17 +881,14 @@ public final class SbtSettings { null, null, null, - null, SbtDefaults.LAYOUT_STATUS_UNLOCKED_COUNT_DEFAULT, null, null, null, - null, SbtDefaults.LAYOUT_STATUS_UNLOCKED_COUNT_DEFAULT, null, null, null, - null, Collections.emptyMap(), Collections.emptyMap(), false, @@ -1208,13 +1099,10 @@ public final class SbtSettings { prefs.getString(KEY_LAYOUT_CARRIER_POSITION, SbtDefaults.LAYOUT_CARRIER_POSITION_DEFAULT), prefs.getBoolean(KEY_LAYOUT_CARRIER_ENABLED_LOCKSCREEN, SbtDefaults.LAYOUT_CARRIER_ENABLED_LOCKSCREEN_DEFAULT), prefs.getString(KEY_LAYOUT_CARRIER_MIDDLE_SIDE, SbtDefaults.LAYOUT_CARRIER_MIDDLE_SIDE_DEFAULT), - prefs.getBoolean(KEY_LAYOUT_CARRIER_MIDDLE_AUTO_NEAREST_SIDE, SbtDefaults.LAYOUT_CARRIER_MIDDLE_AUTO_NEAREST_SIDE_DEFAULT), prefs.getInt(KEY_LAYOUT_CARRIER_VERTICAL_OFFSET_PX, SbtDefaults.LAYOUT_CARRIER_VERTICAL_OFFSET_PX_DEFAULT), prefs.getString(KEY_LAYOUT_CHIP_POSITION, SbtDefaults.LAYOUT_CHIP_POSITION_DEFAULT), - prefs.getBoolean(KEY_LAYOUT_CHIP_ENABLED_LOCKSCREEN, SbtDefaults.LAYOUT_CHIP_ENABLED_LOCKSCREEN_DEFAULT), prefs.getBoolean(KEY_LAYOUT_CHIP_ENABLED_UNLOCKED, SbtDefaults.LAYOUT_CHIP_ENABLED_UNLOCKED_DEFAULT), prefs.getString(KEY_LAYOUT_CHIP_MIDDLE_SIDE, SbtDefaults.LAYOUT_CHIP_MIDDLE_SIDE_DEFAULT), - prefs.getBoolean(KEY_LAYOUT_CHIP_MIDDLE_AUTO_NEAREST_SIDE, SbtDefaults.LAYOUT_CHIP_MIDDLE_AUTO_NEAREST_SIDE_DEFAULT), clampInt(prefs.getInt(KEY_LAYOUT_CHIP_VERTICAL_OFFSET_PX, SbtDefaults.LAYOUT_CHIP_VERTICAL_OFFSET_PX_DEFAULT), SbtDefaults.CLOCK_VERTICAL_OFFSET_PX_MIN, @@ -1223,12 +1111,10 @@ public final class SbtSettings { SbtDefaults.LAYOUT_CHIP_HEIGHT_STEPS_DEFAULT)), prefs.getString(KEY_LAYOUT_NOTIF_POSITION, SbtDefaults.LAYOUT_NOTIF_POSITION_DEFAULT), prefs.getString(KEY_LAYOUT_NOTIF_SORT_ORDER, SbtDefaults.LAYOUT_NOTIF_SORT_ORDER_DEFAULT), - prefs.getBoolean(KEY_LAYOUT_NOTIF_SHOW_DOT_IF_TRUNCATED, SbtDefaults.LAYOUT_NOTIF_SHOW_DOT_IF_TRUNCATED_DEFAULT), prefs.getBoolean(KEY_LAYOUT_NOTIF_ENABLED_AOD, SbtDefaults.LAYOUT_NOTIF_ENABLED_AOD_DEFAULT), prefs.getBoolean(KEY_LAYOUT_NOTIF_ENABLED_LOCKSCREEN, SbtDefaults.LAYOUT_NOTIF_ENABLED_LOCKSCREEN_DEFAULT), prefs.getBoolean(KEY_LAYOUT_NOTIF_ENABLED_UNLOCKED, SbtDefaults.LAYOUT_NOTIF_ENABLED_UNLOCKED_DEFAULT), prefs.getString(KEY_LAYOUT_NOTIF_MIDDLE_SIDE, SbtDefaults.LAYOUT_NOTIF_MIDDLE_SIDE_DEFAULT), - prefs.getBoolean(KEY_LAYOUT_NOTIF_MIDDLE_AUTO_NEAREST_SIDE, SbtDefaults.LAYOUT_NOTIF_MIDDLE_AUTO_NEAREST_SIDE_DEFAULT), clampInt(prefs.getInt(KEY_LAYOUT_NOTIF_VERTICAL_OFFSET_PX, SbtDefaults.LAYOUT_NOTIF_VERTICAL_OFFSET_PX_DEFAULT), SbtDefaults.CLOCK_VERTICAL_OFFSET_PX_MIN, @@ -1259,10 +1145,6 @@ public final class SbtSettings { prefs, SbtSettings::layoutNotifMiddleSideKey, SbtDefaults.LAYOUT_NOTIF_MIDDLE_SIDE_DEFAULT), - readBooleanArrayFromPrefs( - prefs, - SbtSettings::layoutNotifMiddleAutoNearestSideKey, - SbtDefaults.LAYOUT_NOTIF_MIDDLE_AUTO_NEAREST_SIDE_DEFAULT), readIntArrayFromPrefs( prefs, SbtSettings::layoutNotifVerticalOffsetKey, @@ -1281,10 +1163,6 @@ public final class SbtSettings { prefs, SbtSettings::layoutLockNotifMiddleSideKey, SbtDefaults.LAYOUT_NOTIF_MIDDLE_SIDE_DEFAULT), - readBooleanArrayFromPrefs( - prefs, - SbtSettings::layoutLockNotifMiddleAutoNearestSideKey, - SbtDefaults.LAYOUT_NOTIF_MIDDLE_AUTO_NEAREST_SIDE_DEFAULT), readIntArrayFromPrefs( prefs, SbtSettings::layoutLockNotifVerticalOffsetKey, @@ -1303,10 +1181,6 @@ public final class SbtSettings { prefs, SbtSettings::layoutAodNotifMiddleSideKey, SbtDefaults.LAYOUT_NOTIF_MIDDLE_SIDE_DEFAULT), - readBooleanArrayFromPrefs( - prefs, - SbtSettings::layoutAodNotifMiddleAutoNearestSideKey, - SbtDefaults.LAYOUT_NOTIF_MIDDLE_AUTO_NEAREST_SIDE_DEFAULT), readIntArrayFromPrefs( prefs, SbtSettings::layoutAodNotifVerticalOffsetKey, @@ -1315,9 +1189,7 @@ public final class SbtSettings { prefs.getBoolean(KEY_LAYOUT_STATUS_ENABLED_AOD, SbtDefaults.LAYOUT_STATUS_ENABLED_AOD_DEFAULT), prefs.getBoolean(KEY_LAYOUT_STATUS_ENABLED_LOCKSCREEN, SbtDefaults.LAYOUT_STATUS_ENABLED_LOCKSCREEN_DEFAULT), prefs.getBoolean(KEY_LAYOUT_STATUS_ENABLED_UNLOCKED, SbtDefaults.LAYOUT_STATUS_ENABLED_UNLOCKED_DEFAULT), - prefs.getBoolean(KEY_LAYOUT_STATUS_SHOW_DOT_IF_TRUNCATED, SbtDefaults.LAYOUT_STATUS_SHOW_DOT_IF_TRUNCATED_DEFAULT), prefs.getString(KEY_LAYOUT_STATUS_MIDDLE_SIDE, SbtDefaults.LAYOUT_STATUS_MIDDLE_SIDE_DEFAULT), - prefs.getBoolean(KEY_LAYOUT_STATUS_MIDDLE_AUTO_NEAREST_SIDE, SbtDefaults.LAYOUT_STATUS_MIDDLE_AUTO_NEAREST_SIDE_DEFAULT), clampInt(prefs.getInt(KEY_LAYOUT_STATUS_VERTICAL_OFFSET_PX, SbtDefaults.LAYOUT_STATUS_VERTICAL_OFFSET_PX_DEFAULT), SbtDefaults.CLOCK_VERTICAL_OFFSET_PX_MIN, @@ -1348,10 +1220,6 @@ public final class SbtSettings { prefs, SbtSettings::layoutStatusMiddleSideKey, SbtDefaults.LAYOUT_STATUS_MIDDLE_SIDE_DEFAULT), - readBooleanArrayFromPrefs( - prefs, - SbtSettings::layoutStatusMiddleAutoNearestSideKey, - SbtDefaults.LAYOUT_STATUS_MIDDLE_AUTO_NEAREST_SIDE_DEFAULT), readIntArrayFromPrefs( prefs, SbtSettings::layoutStatusVerticalOffsetKey, @@ -1370,10 +1238,6 @@ public final class SbtSettings { prefs, SbtSettings::layoutLockStatusMiddleSideKey, SbtDefaults.LAYOUT_STATUS_MIDDLE_SIDE_DEFAULT), - readBooleanArrayFromPrefs( - prefs, - SbtSettings::layoutLockStatusMiddleAutoNearestSideKey, - SbtDefaults.LAYOUT_STATUS_MIDDLE_AUTO_NEAREST_SIDE_DEFAULT), readIntArrayFromPrefs( prefs, SbtSettings::layoutLockStatusVerticalOffsetKey, @@ -1392,10 +1256,6 @@ public final class SbtSettings { prefs, SbtSettings::layoutAodStatusMiddleSideKey, SbtDefaults.LAYOUT_STATUS_MIDDLE_SIDE_DEFAULT), - readBooleanArrayFromPrefs( - prefs, - SbtSettings::layoutAodStatusMiddleAutoNearestSideKey, - SbtDefaults.LAYOUT_STATUS_MIDDLE_AUTO_NEAREST_SIDE_DEFAULT), readIntArrayFromPrefs( prefs, SbtSettings::layoutAodStatusVerticalOffsetKey, @@ -1537,13 +1397,10 @@ public final class SbtSettings { bundle.getString(KEY_LAYOUT_CARRIER_POSITION, SbtDefaults.LAYOUT_CARRIER_POSITION_DEFAULT), bundle.getBoolean(KEY_LAYOUT_CARRIER_ENABLED_LOCKSCREEN, SbtDefaults.LAYOUT_CARRIER_ENABLED_LOCKSCREEN_DEFAULT), bundle.getString(KEY_LAYOUT_CARRIER_MIDDLE_SIDE, SbtDefaults.LAYOUT_CARRIER_MIDDLE_SIDE_DEFAULT), - bundle.getBoolean(KEY_LAYOUT_CARRIER_MIDDLE_AUTO_NEAREST_SIDE, SbtDefaults.LAYOUT_CARRIER_MIDDLE_AUTO_NEAREST_SIDE_DEFAULT), bundle.getInt(KEY_LAYOUT_CARRIER_VERTICAL_OFFSET_PX, SbtDefaults.LAYOUT_CARRIER_VERTICAL_OFFSET_PX_DEFAULT), bundle.getString(KEY_LAYOUT_CHIP_POSITION, SbtDefaults.LAYOUT_CHIP_POSITION_DEFAULT), - bundle.getBoolean(KEY_LAYOUT_CHIP_ENABLED_LOCKSCREEN, SbtDefaults.LAYOUT_CHIP_ENABLED_LOCKSCREEN_DEFAULT), bundle.getBoolean(KEY_LAYOUT_CHIP_ENABLED_UNLOCKED, SbtDefaults.LAYOUT_CHIP_ENABLED_UNLOCKED_DEFAULT), bundle.getString(KEY_LAYOUT_CHIP_MIDDLE_SIDE, SbtDefaults.LAYOUT_CHIP_MIDDLE_SIDE_DEFAULT), - bundle.getBoolean(KEY_LAYOUT_CHIP_MIDDLE_AUTO_NEAREST_SIDE, SbtDefaults.LAYOUT_CHIP_MIDDLE_AUTO_NEAREST_SIDE_DEFAULT), clampInt(bundle.getInt(KEY_LAYOUT_CHIP_VERTICAL_OFFSET_PX, SbtDefaults.LAYOUT_CHIP_VERTICAL_OFFSET_PX_DEFAULT), SbtDefaults.CLOCK_VERTICAL_OFFSET_PX_MIN, @@ -1552,12 +1409,10 @@ public final class SbtSettings { SbtDefaults.LAYOUT_CHIP_HEIGHT_STEPS_DEFAULT)), bundle.getString(KEY_LAYOUT_NOTIF_POSITION, SbtDefaults.LAYOUT_NOTIF_POSITION_DEFAULT), bundle.getString(KEY_LAYOUT_NOTIF_SORT_ORDER, SbtDefaults.LAYOUT_NOTIF_SORT_ORDER_DEFAULT), - bundle.getBoolean(KEY_LAYOUT_NOTIF_SHOW_DOT_IF_TRUNCATED, SbtDefaults.LAYOUT_NOTIF_SHOW_DOT_IF_TRUNCATED_DEFAULT), bundle.getBoolean(KEY_LAYOUT_NOTIF_ENABLED_AOD, SbtDefaults.LAYOUT_NOTIF_ENABLED_AOD_DEFAULT), bundle.getBoolean(KEY_LAYOUT_NOTIF_ENABLED_LOCKSCREEN, SbtDefaults.LAYOUT_NOTIF_ENABLED_LOCKSCREEN_DEFAULT), bundle.getBoolean(KEY_LAYOUT_NOTIF_ENABLED_UNLOCKED, SbtDefaults.LAYOUT_NOTIF_ENABLED_UNLOCKED_DEFAULT), bundle.getString(KEY_LAYOUT_NOTIF_MIDDLE_SIDE, SbtDefaults.LAYOUT_NOTIF_MIDDLE_SIDE_DEFAULT), - bundle.getBoolean(KEY_LAYOUT_NOTIF_MIDDLE_AUTO_NEAREST_SIDE, SbtDefaults.LAYOUT_NOTIF_MIDDLE_AUTO_NEAREST_SIDE_DEFAULT), clampInt(bundle.getInt(KEY_LAYOUT_NOTIF_VERTICAL_OFFSET_PX, SbtDefaults.LAYOUT_NOTIF_VERTICAL_OFFSET_PX_DEFAULT), SbtDefaults.CLOCK_VERTICAL_OFFSET_PX_MIN, @@ -1588,10 +1443,6 @@ public final class SbtSettings { bundle, SbtSettings::layoutNotifMiddleSideKey, SbtDefaults.LAYOUT_NOTIF_MIDDLE_SIDE_DEFAULT), - readBooleanArrayFromBundle( - bundle, - SbtSettings::layoutNotifMiddleAutoNearestSideKey, - SbtDefaults.LAYOUT_NOTIF_MIDDLE_AUTO_NEAREST_SIDE_DEFAULT), readIntArrayFromBundle( bundle, SbtSettings::layoutNotifVerticalOffsetKey, @@ -1610,10 +1461,6 @@ public final class SbtSettings { bundle, SbtSettings::layoutLockNotifMiddleSideKey, SbtDefaults.LAYOUT_NOTIF_MIDDLE_SIDE_DEFAULT), - readBooleanArrayFromBundle( - bundle, - SbtSettings::layoutLockNotifMiddleAutoNearestSideKey, - SbtDefaults.LAYOUT_NOTIF_MIDDLE_AUTO_NEAREST_SIDE_DEFAULT), readIntArrayFromBundle( bundle, SbtSettings::layoutLockNotifVerticalOffsetKey, @@ -1632,10 +1479,6 @@ public final class SbtSettings { bundle, SbtSettings::layoutAodNotifMiddleSideKey, SbtDefaults.LAYOUT_NOTIF_MIDDLE_SIDE_DEFAULT), - readBooleanArrayFromBundle( - bundle, - SbtSettings::layoutAodNotifMiddleAutoNearestSideKey, - SbtDefaults.LAYOUT_NOTIF_MIDDLE_AUTO_NEAREST_SIDE_DEFAULT), readIntArrayFromBundle( bundle, SbtSettings::layoutAodNotifVerticalOffsetKey, @@ -1644,9 +1487,7 @@ public final class SbtSettings { bundle.getBoolean(KEY_LAYOUT_STATUS_ENABLED_AOD, SbtDefaults.LAYOUT_STATUS_ENABLED_AOD_DEFAULT), bundle.getBoolean(KEY_LAYOUT_STATUS_ENABLED_LOCKSCREEN, SbtDefaults.LAYOUT_STATUS_ENABLED_LOCKSCREEN_DEFAULT), bundle.getBoolean(KEY_LAYOUT_STATUS_ENABLED_UNLOCKED, SbtDefaults.LAYOUT_STATUS_ENABLED_UNLOCKED_DEFAULT), - bundle.getBoolean(KEY_LAYOUT_STATUS_SHOW_DOT_IF_TRUNCATED, SbtDefaults.LAYOUT_STATUS_SHOW_DOT_IF_TRUNCATED_DEFAULT), bundle.getString(KEY_LAYOUT_STATUS_MIDDLE_SIDE, SbtDefaults.LAYOUT_STATUS_MIDDLE_SIDE_DEFAULT), - bundle.getBoolean(KEY_LAYOUT_STATUS_MIDDLE_AUTO_NEAREST_SIDE, SbtDefaults.LAYOUT_STATUS_MIDDLE_AUTO_NEAREST_SIDE_DEFAULT), clampInt(bundle.getInt(KEY_LAYOUT_STATUS_VERTICAL_OFFSET_PX, SbtDefaults.LAYOUT_STATUS_VERTICAL_OFFSET_PX_DEFAULT), SbtDefaults.CLOCK_VERTICAL_OFFSET_PX_MIN, @@ -1677,10 +1518,6 @@ public final class SbtSettings { bundle, SbtSettings::layoutStatusMiddleSideKey, SbtDefaults.LAYOUT_STATUS_MIDDLE_SIDE_DEFAULT), - readBooleanArrayFromBundle( - bundle, - SbtSettings::layoutStatusMiddleAutoNearestSideKey, - SbtDefaults.LAYOUT_STATUS_MIDDLE_AUTO_NEAREST_SIDE_DEFAULT), readIntArrayFromBundle( bundle, SbtSettings::layoutStatusVerticalOffsetKey, @@ -1699,10 +1536,6 @@ public final class SbtSettings { bundle, SbtSettings::layoutLockStatusMiddleSideKey, SbtDefaults.LAYOUT_STATUS_MIDDLE_SIDE_DEFAULT), - readBooleanArrayFromBundle( - bundle, - SbtSettings::layoutLockStatusMiddleAutoNearestSideKey, - SbtDefaults.LAYOUT_STATUS_MIDDLE_AUTO_NEAREST_SIDE_DEFAULT), readIntArrayFromBundle( bundle, SbtSettings::layoutLockStatusVerticalOffsetKey, @@ -1721,10 +1554,6 @@ public final class SbtSettings { bundle, SbtSettings::layoutAodStatusMiddleSideKey, SbtDefaults.LAYOUT_STATUS_MIDDLE_SIDE_DEFAULT), - readBooleanArrayFromBundle( - bundle, - SbtSettings::layoutAodStatusMiddleAutoNearestSideKey, - SbtDefaults.LAYOUT_STATUS_MIDDLE_AUTO_NEAREST_SIDE_DEFAULT), readIntArrayFromBundle( bundle, SbtSettings::layoutAodStatusVerticalOffsetKey, @@ -1829,20 +1658,6 @@ public final class SbtSettings { return result; } - private static boolean[] readBooleanArrayFromPrefs( - SharedPreferences prefs, - IndexedKey key, - boolean fallback - ) { - boolean[] result = new boolean[SbtDefaults.LAYOUT_ICON_CONTAINER_COUNT_MAX]; - boolean previous = fallback; - for (int i = 0; i < result.length; i++) { - previous = prefs.contains(key.key(i)) ? prefs.getBoolean(key.key(i), previous) : previous; - result[i] = previous; - } - return result; - } - private static int[] readIntArrayFromPrefs(SharedPreferences prefs, IndexedKey key, int fallback) { int[] result = new int[SbtDefaults.LAYOUT_ICON_CONTAINER_COUNT_MAX]; int previous = fallback; @@ -1863,16 +1678,6 @@ public final class SbtSettings { return result; } - private static boolean[] readBooleanArrayFromBundle(Bundle bundle, IndexedKey key, boolean fallback) { - boolean[] result = new boolean[SbtDefaults.LAYOUT_ICON_CONTAINER_COUNT_MAX]; - boolean previous = fallback; - for (int i = 0; i < result.length; i++) { - previous = bundle.containsKey(key.key(i)) ? bundle.getBoolean(key.key(i), previous) : previous; - result[i] = previous; - } - return result; - } - private static int[] readIntArrayFromBundle(Bundle bundle, IndexedKey key, int fallback) { int[] result = new int[SbtDefaults.LAYOUT_ICON_CONTAINER_COUNT_MAX]; int previous = fallback; @@ -1892,14 +1697,6 @@ public final class SbtSettings { return result; } - private static boolean[] sanitizeBooleanArray(boolean[] source, boolean fallback, int length) { - boolean[] result = new boolean[Math.max(0, length)]; - for (int i = 0; i < result.length; i++) { - result[i] = source != null && i < source.length ? source[i] : fallback; - } - return result; - } - private static int[] sanitizeIntArray(int[] source, int fallback, int length, int min, int max) { int[] result = new int[Math.max(0, length)]; for (int i = 0; i < result.length; i++) { diff --git a/app/src/main/java/se/ajpanton/statusbartweak/shell/settings/SbtSettingsProvider.java b/app/src/main/java/se/ajpanton/statusbartweak/shell/settings/SbtSettingsProvider.java index 79ffab0..bda1b1c 100644 --- a/app/src/main/java/se/ajpanton/statusbartweak/shell/settings/SbtSettingsProvider.java +++ b/app/src/main/java/se/ajpanton/statusbartweak/shell/settings/SbtSettingsProvider.java @@ -195,27 +195,18 @@ public class SbtSettingsProvider extends ContentProvider { out.putString(SbtSettings.KEY_LAYOUT_CARRIER_MIDDLE_SIDE, prefs.getString(SbtSettings.KEY_LAYOUT_CARRIER_MIDDLE_SIDE, SbtDefaults.LAYOUT_CARRIER_MIDDLE_SIDE_DEFAULT)); - out.putBoolean(SbtSettings.KEY_LAYOUT_CARRIER_MIDDLE_AUTO_NEAREST_SIDE, - prefs.getBoolean(SbtSettings.KEY_LAYOUT_CARRIER_MIDDLE_AUTO_NEAREST_SIDE, - SbtDefaults.LAYOUT_CARRIER_MIDDLE_AUTO_NEAREST_SIDE_DEFAULT)); out.putInt(SbtSettings.KEY_LAYOUT_CARRIER_VERTICAL_OFFSET_PX, prefs.getInt(SbtSettings.KEY_LAYOUT_CARRIER_VERTICAL_OFFSET_PX, SbtDefaults.LAYOUT_CARRIER_VERTICAL_OFFSET_PX_DEFAULT)); out.putString(SbtSettings.KEY_LAYOUT_CHIP_POSITION, prefs.getString(SbtSettings.KEY_LAYOUT_CHIP_POSITION, SbtDefaults.LAYOUT_CHIP_POSITION_DEFAULT)); - out.putBoolean(SbtSettings.KEY_LAYOUT_CHIP_ENABLED_LOCKSCREEN, - prefs.getBoolean(SbtSettings.KEY_LAYOUT_CHIP_ENABLED_LOCKSCREEN, - SbtDefaults.LAYOUT_CHIP_ENABLED_LOCKSCREEN_DEFAULT)); out.putBoolean(SbtSettings.KEY_LAYOUT_CHIP_ENABLED_UNLOCKED, prefs.getBoolean(SbtSettings.KEY_LAYOUT_CHIP_ENABLED_UNLOCKED, SbtDefaults.LAYOUT_CHIP_ENABLED_UNLOCKED_DEFAULT)); out.putString(SbtSettings.KEY_LAYOUT_CHIP_MIDDLE_SIDE, prefs.getString(SbtSettings.KEY_LAYOUT_CHIP_MIDDLE_SIDE, SbtDefaults.LAYOUT_CHIP_MIDDLE_SIDE_DEFAULT)); - out.putBoolean(SbtSettings.KEY_LAYOUT_CHIP_MIDDLE_AUTO_NEAREST_SIDE, - prefs.getBoolean(SbtSettings.KEY_LAYOUT_CHIP_MIDDLE_AUTO_NEAREST_SIDE, - SbtDefaults.LAYOUT_CHIP_MIDDLE_AUTO_NEAREST_SIDE_DEFAULT)); out.putInt(SbtSettings.KEY_LAYOUT_CHIP_VERTICAL_OFFSET_PX, prefs.getInt(SbtSettings.KEY_LAYOUT_CHIP_VERTICAL_OFFSET_PX, SbtDefaults.LAYOUT_CHIP_VERTICAL_OFFSET_PX_DEFAULT)); @@ -228,9 +219,6 @@ public class SbtSettingsProvider extends ContentProvider { out.putString(SbtSettings.KEY_LAYOUT_NOTIF_SORT_ORDER, prefs.getString(SbtSettings.KEY_LAYOUT_NOTIF_SORT_ORDER, SbtDefaults.LAYOUT_NOTIF_SORT_ORDER_DEFAULT)); - out.putBoolean(SbtSettings.KEY_LAYOUT_NOTIF_SHOW_DOT_IF_TRUNCATED, - prefs.getBoolean(SbtSettings.KEY_LAYOUT_NOTIF_SHOW_DOT_IF_TRUNCATED, - SbtDefaults.LAYOUT_NOTIF_SHOW_DOT_IF_TRUNCATED_DEFAULT)); out.putBoolean(SbtSettings.KEY_LAYOUT_NOTIF_ENABLED_AOD, prefs.getBoolean(SbtSettings.KEY_LAYOUT_NOTIF_ENABLED_AOD, SbtDefaults.LAYOUT_NOTIF_ENABLED_AOD_DEFAULT)); @@ -250,9 +238,6 @@ public class SbtSettingsProvider extends ContentProvider { out.putString(SbtSettings.KEY_LAYOUT_NOTIF_MIDDLE_SIDE, prefs.getString(SbtSettings.KEY_LAYOUT_NOTIF_MIDDLE_SIDE, SbtDefaults.LAYOUT_NOTIF_MIDDLE_SIDE_DEFAULT)); - out.putBoolean(SbtSettings.KEY_LAYOUT_NOTIF_MIDDLE_AUTO_NEAREST_SIDE, - prefs.getBoolean(SbtSettings.KEY_LAYOUT_NOTIF_MIDDLE_AUTO_NEAREST_SIDE, - SbtDefaults.LAYOUT_NOTIF_MIDDLE_AUTO_NEAREST_SIDE_DEFAULT)); out.putInt(SbtSettings.KEY_LAYOUT_NOTIF_VERTICAL_OFFSET_PX, prefs.getInt(SbtSettings.KEY_LAYOUT_NOTIF_VERTICAL_OFFSET_PX, SbtDefaults.LAYOUT_NOTIF_VERTICAL_OFFSET_PX_DEFAULT)); @@ -266,8 +251,6 @@ public class SbtSettingsProvider extends ContentProvider { SbtDefaults.LAYOUT_NOTIF_POSITION_DEFAULT, SbtSettings::layoutNotifMiddleSideKey, SbtDefaults.LAYOUT_NOTIF_MIDDLE_SIDE_DEFAULT, - SbtSettings::layoutNotifMiddleAutoNearestSideKey, - SbtDefaults.LAYOUT_NOTIF_MIDDLE_AUTO_NEAREST_SIDE_DEFAULT, SbtSettings::layoutNotifVerticalOffsetKey, SbtDefaults.LAYOUT_NOTIF_VERTICAL_OFFSET_PX_DEFAULT); out.putInt(SbtSettings.KEY_LAYOUT_NOTIF_LOCK_COUNT, @@ -287,8 +270,6 @@ public class SbtSettingsProvider extends ContentProvider { SbtDefaults.LAYOUT_NOTIF_POSITION_DEFAULT, SbtSettings::layoutLockNotifMiddleSideKey, SbtDefaults.LAYOUT_NOTIF_MIDDLE_SIDE_DEFAULT, - SbtSettings::layoutLockNotifMiddleAutoNearestSideKey, - SbtDefaults.LAYOUT_NOTIF_MIDDLE_AUTO_NEAREST_SIDE_DEFAULT, SbtSettings::layoutLockNotifVerticalOffsetKey, SbtDefaults.LAYOUT_NOTIF_VERTICAL_OFFSET_PX_DEFAULT); out.putInt(SbtSettings.KEY_LAYOUT_NOTIF_AOD_COUNT, @@ -308,8 +289,6 @@ public class SbtSettingsProvider extends ContentProvider { SbtDefaults.LAYOUT_NOTIF_POSITION_DEFAULT, SbtSettings::layoutAodNotifMiddleSideKey, SbtDefaults.LAYOUT_NOTIF_MIDDLE_SIDE_DEFAULT, - SbtSettings::layoutAodNotifMiddleAutoNearestSideKey, - SbtDefaults.LAYOUT_NOTIF_MIDDLE_AUTO_NEAREST_SIDE_DEFAULT, SbtSettings::layoutAodNotifVerticalOffsetKey, SbtDefaults.LAYOUT_NOTIF_VERTICAL_OFFSET_PX_DEFAULT); out.putString(SbtSettings.KEY_LAYOUT_STATUS_POSITION, @@ -331,15 +310,9 @@ public class SbtSettingsProvider extends ContentProvider { SbtDefaults.LAYOUT_STATUS_ENABLED_UNLOCKED_DEFAULT) ? SbtDefaults.LAYOUT_STATUS_UNLOCKED_COUNT_DEFAULT : 0)); - out.putBoolean(SbtSettings.KEY_LAYOUT_STATUS_SHOW_DOT_IF_TRUNCATED, - prefs.getBoolean(SbtSettings.KEY_LAYOUT_STATUS_SHOW_DOT_IF_TRUNCATED, - SbtDefaults.LAYOUT_STATUS_SHOW_DOT_IF_TRUNCATED_DEFAULT)); out.putString(SbtSettings.KEY_LAYOUT_STATUS_MIDDLE_SIDE, prefs.getString(SbtSettings.KEY_LAYOUT_STATUS_MIDDLE_SIDE, SbtDefaults.LAYOUT_STATUS_MIDDLE_SIDE_DEFAULT)); - out.putBoolean(SbtSettings.KEY_LAYOUT_STATUS_MIDDLE_AUTO_NEAREST_SIDE, - prefs.getBoolean(SbtSettings.KEY_LAYOUT_STATUS_MIDDLE_AUTO_NEAREST_SIDE, - SbtDefaults.LAYOUT_STATUS_MIDDLE_AUTO_NEAREST_SIDE_DEFAULT)); out.putInt(SbtSettings.KEY_LAYOUT_STATUS_VERTICAL_OFFSET_PX, prefs.getInt(SbtSettings.KEY_LAYOUT_STATUS_VERTICAL_OFFSET_PX, SbtDefaults.LAYOUT_STATUS_VERTICAL_OFFSET_PX_DEFAULT)); @@ -353,8 +326,6 @@ public class SbtSettingsProvider extends ContentProvider { SbtDefaults.LAYOUT_STATUS_POSITION_DEFAULT, SbtSettings::layoutStatusMiddleSideKey, SbtDefaults.LAYOUT_STATUS_MIDDLE_SIDE_DEFAULT, - SbtSettings::layoutStatusMiddleAutoNearestSideKey, - SbtDefaults.LAYOUT_STATUS_MIDDLE_AUTO_NEAREST_SIDE_DEFAULT, SbtSettings::layoutStatusVerticalOffsetKey, SbtDefaults.LAYOUT_STATUS_VERTICAL_OFFSET_PX_DEFAULT); out.putInt(SbtSettings.KEY_LAYOUT_STATUS_LOCK_COUNT, @@ -374,8 +345,6 @@ public class SbtSettingsProvider extends ContentProvider { SbtDefaults.LAYOUT_STATUS_POSITION_DEFAULT, SbtSettings::layoutLockStatusMiddleSideKey, SbtDefaults.LAYOUT_STATUS_MIDDLE_SIDE_DEFAULT, - SbtSettings::layoutLockStatusMiddleAutoNearestSideKey, - SbtDefaults.LAYOUT_STATUS_MIDDLE_AUTO_NEAREST_SIDE_DEFAULT, SbtSettings::layoutLockStatusVerticalOffsetKey, SbtDefaults.LAYOUT_STATUS_VERTICAL_OFFSET_PX_DEFAULT); out.putInt(SbtSettings.KEY_LAYOUT_STATUS_AOD_COUNT, @@ -395,8 +364,6 @@ public class SbtSettingsProvider extends ContentProvider { SbtDefaults.LAYOUT_STATUS_POSITION_DEFAULT, SbtSettings::layoutAodStatusMiddleSideKey, SbtDefaults.LAYOUT_STATUS_MIDDLE_SIDE_DEFAULT, - SbtSettings::layoutAodStatusMiddleAutoNearestSideKey, - SbtDefaults.LAYOUT_STATUS_MIDDLE_AUTO_NEAREST_SIDE_DEFAULT, SbtSettings::layoutAodStatusVerticalOffsetKey, SbtDefaults.LAYOUT_STATUS_VERTICAL_OFFSET_PX_DEFAULT); putStringSetArrayList(out, prefs, SbtSettings.KEY_CLOCK_CAMERA_TYPE_OVERRIDES); @@ -465,14 +432,11 @@ public class SbtSettingsProvider extends ContentProvider { String positionDefault, SbtSettings.IndexedKey middleSideKey, String middleSideDefault, - SbtSettings.IndexedKey autoNearestKey, - boolean autoNearestDefault, SbtSettings.IndexedKey verticalOffsetKey, int verticalOffsetDefault ) { String position = positionDefault; String middleSide = middleSideDefault; - boolean autoNearest = autoNearestDefault; int verticalOffset = verticalOffsetDefault; for (int i = 0; i < SbtDefaults.LAYOUT_ICON_CONTAINER_COUNT_MAX; i++) { position = prefs.contains(positionKey.key(i)) @@ -481,15 +445,11 @@ public class SbtSettingsProvider extends ContentProvider { middleSide = prefs.contains(middleSideKey.key(i)) ? prefs.getString(middleSideKey.key(i), middleSide) : middleSide; - autoNearest = prefs.contains(autoNearestKey.key(i)) - ? prefs.getBoolean(autoNearestKey.key(i), autoNearest) - : autoNearest; verticalOffset = prefs.contains(verticalOffsetKey.key(i)) ? prefs.getInt(verticalOffsetKey.key(i), verticalOffset) : verticalOffset; out.putString(positionKey.key(i), position); out.putString(middleSideKey.key(i), middleSide); - out.putBoolean(autoNearestKey.key(i), autoNearest); out.putInt(verticalOffsetKey.key(i), verticalOffset); } } diff --git a/app/src/main/java/se/ajpanton/statusbartweak/shell/ui/LayoutFragment.java b/app/src/main/java/se/ajpanton/statusbartweak/shell/ui/LayoutFragment.java index 6b7d763..2fd8396 100644 --- a/app/src/main/java/se/ajpanton/statusbartweak/shell/ui/LayoutFragment.java +++ b/app/src/main/java/se/ajpanton/statusbartweak/shell/ui/LayoutFragment.java @@ -56,31 +56,31 @@ public final class LayoutFragment extends Fragment { prefs, R.id.notif_position_group, R.id.notif_position_middle_options_container, - R.id.notif_middle_auto_nearest, + View.NO_ID, R.id.notif_middle_side_prompt, SbtSettings.KEY_LAYOUT_NOTIF_POSITION, SbtDefaults.LAYOUT_NOTIF_POSITION_DEFAULT, - SbtSettings.KEY_LAYOUT_NOTIF_MIDDLE_AUTO_NEAREST_SIDE, + null, SbtSettings.KEY_LAYOUT_NOTIF_MIDDLE_SIDE); setupPositionSection(root, prefs, R.id.chip_position_group, R.id.chip_position_middle_options_container, - R.id.chip_middle_auto_nearest, + View.NO_ID, R.id.chip_middle_side_prompt, SbtSettings.KEY_LAYOUT_CHIP_POSITION, SbtDefaults.LAYOUT_CHIP_POSITION_DEFAULT, - SbtSettings.KEY_LAYOUT_CHIP_MIDDLE_AUTO_NEAREST_SIDE, + null, SbtSettings.KEY_LAYOUT_CHIP_MIDDLE_SIDE); setupPositionSection(root, prefs, R.id.status_position_group, R.id.status_position_middle_options_container, - R.id.status_middle_auto_nearest, + View.NO_ID, R.id.status_middle_side_prompt, SbtSettings.KEY_LAYOUT_STATUS_POSITION, SbtDefaults.LAYOUT_STATUS_POSITION_DEFAULT, - SbtSettings.KEY_LAYOUT_STATUS_MIDDLE_AUTO_NEAREST_SIDE, + null, SbtSettings.KEY_LAYOUT_STATUS_MIDDLE_SIDE); bindStepper(prefs, @@ -150,12 +150,10 @@ public final class LayoutFragment extends Fragment { SbtSettings.KEY_LAYOUT_NOTIF_ENABLED_UNLOCKED, SbtDefaults.LAYOUT_NOTIF_ENABLED_UNLOCKED_DEFAULT, SbtSettings::layoutNotifPositionKey, - SbtSettings::layoutNotifMiddleAutoNearestSideKey, SbtSettings::layoutNotifMiddleSideKey, SbtSettings::layoutNotifVerticalOffsetKey, SbtSettings.KEY_LAYOUT_NOTIF_ICON_HEIGHT_STEPS, SbtDefaults.LAYOUT_NOTIF_POSITION_DEFAULT, - SbtDefaults.LAYOUT_NOTIF_MIDDLE_AUTO_NEAREST_SIDE_DEFAULT, SbtDefaults.LAYOUT_NOTIF_MIDDLE_SIDE_DEFAULT, SbtDefaults.LAYOUT_NOTIF_VERTICAL_OFFSET_PX_DEFAULT, SbtDefaults.LAYOUT_NOTIF_ICON_HEIGHT_STEPS_DEFAULT, @@ -170,12 +168,10 @@ public final class LayoutFragment extends Fragment { SbtSettings.KEY_LAYOUT_STATUS_ENABLED_UNLOCKED, SbtDefaults.LAYOUT_STATUS_ENABLED_UNLOCKED_DEFAULT, SbtSettings::layoutStatusPositionKey, - SbtSettings::layoutStatusMiddleAutoNearestSideKey, SbtSettings::layoutStatusMiddleSideKey, SbtSettings::layoutStatusVerticalOffsetKey, SbtSettings.KEY_LAYOUT_STATUS_ICON_HEIGHT_STEPS, SbtDefaults.LAYOUT_STATUS_POSITION_DEFAULT, - SbtDefaults.LAYOUT_STATUS_MIDDLE_AUTO_NEAREST_SIDE_DEFAULT, SbtDefaults.LAYOUT_STATUS_MIDDLE_SIDE_DEFAULT, SbtDefaults.LAYOUT_STATUS_VERTICAL_OFFSET_PX_DEFAULT, SbtDefaults.LAYOUT_STATUS_ICON_HEIGHT_STEPS_DEFAULT, @@ -193,12 +189,10 @@ public final class LayoutFragment extends Fragment { String legacyEnabledKey, boolean legacyEnabledDefault, SbtSettings.IndexedKey positionKey, - SbtSettings.IndexedKey autoNearestKey, SbtSettings.IndexedKey middleSideKey, SbtSettings.IndexedKey verticalOffsetKey, String iconHeightKey, String positionDefault, - boolean autoNearestDefault, String middleSideDefault, int verticalOffsetDefault, int iconHeightDefault, @@ -225,7 +219,12 @@ public final class LayoutFragment extends Fragment { rebuild[0] = () -> { countContainer.removeAllViews(); removeGeneratedCopyCards(cardsParent, copyTag); - int count = iconContainerCount(prefs, countKey, countDefault, legacyEnabledKey, legacyEnabledDefault); + int count = ViewTreeSupport.iconContainerCount( + prefs, + countKey, + legacyEnabledKey, + countDefault, + legacyEnabledDefault); LayoutXmlCardSupport.setIndexedCardTitle(requireContext(), sourceCard, sectionTitleId, 0, count); boolean cardsMode = LockedNotificationModeUi.MODE_CARDS.equals( LockedNotificationModeUi.currentMode(requireContext())); @@ -238,11 +237,15 @@ public final class LayoutFragment extends Fragment { cardsMode, 0, this::refreshSelf); - countContainer.addView(iconContainerCountControl( - prefs, - countKey, + countContainer.addView(ViewTreeSupport.iconContainerCountControl( + requireContext(), count, - legacyEnabledKey, + value -> ViewTreeSupport.persistIconContainerCount( + requireContext(), + prefs, + countKey, + legacyEnabledKey, + value), () -> { if (rebuild[0] != null) { rebuild[0].run(); @@ -264,11 +267,9 @@ public final class LayoutFragment extends Fragment { sectionTitleId, i, positionKey, - autoNearestKey, middleSideKey, verticalOffsetKey, positionDefault, - autoNearestDefault, middleSideDefault, verticalOffsetDefault, copyTag); @@ -294,105 +295,28 @@ public final class LayoutFragment extends Fragment { }); } - private View iconContainerCountControl( - SharedPreferences prefs, - String countKey, - int current, - String legacyEnabledKey, - Runnable onChanged - ) { - Context context = requireContext(); - LinearLayout outer = ViewTreeSupport.verticalLayout(context); - TextView label = ViewTreeSupport.bodyText(context, R.string.layout_icon_container_count, 0); - outer.addView(label); - - LinearLayout row = new LinearLayout(context); - row.setOrientation(LinearLayout.HORIZONTAL); - row.setGravity(android.view.Gravity.CENTER_VERTICAL); - MaterialButton minus = ViewTreeSupport.outlinedStepperButton(context, "-"); - MaterialButton plus = ViewTreeSupport.outlinedStepperButton(context, "+"); - EditText input = ViewTreeSupport.numericInput(context, false, 1); - input.setText(String.valueOf(current)); - row.addView(minus, ViewTreeSupport.stepperButtonParams(context)); - row.addView(input, ViewTreeSupport.stepperInputParams(context)); - row.addView(plus, ViewTreeSupport.stepperButtonParams(context)); - outer.addView(row); - - View.OnClickListener listener = view -> { - int next = SbtSettings.clampIconContainerCount( - ViewTreeSupport.parseInt(input, current) + (view == minus ? -1 : 1)); - persistIconContainerCount(prefs, countKey, legacyEnabledKey, next); - onChanged.run(); - }; - minus.setOnClickListener(listener); - plus.setOnClickListener(listener); - input.setOnFocusChangeListener((v, hasFocus) -> { - if (!hasFocus) { - int next = SbtSettings.clampIconContainerCount(ViewTreeSupport.parseInt(input, current)); - persistIconContainerCount(prefs, countKey, legacyEnabledKey, next); - onChanged.run(); - } - }); - return outer; - } - private View iconHeightControl( SharedPreferences prefs, String key, int defaultValue, int labelRes ) { - Context context = requireContext(); - LinearLayout outer = ViewTreeSupport.verticalLayout(context); - TextView label = ViewTreeSupport.bodyText(context, labelRes, 0); - outer.addView(label); - - LinearLayout row = new LinearLayout(context); - row.setOrientation(LinearLayout.HORIZONTAL); - row.setGravity(android.view.Gravity.CENTER_VERTICAL); - MaterialButton minus = ViewTreeSupport.outlinedStepperButton(context, "-"); - MaterialButton plus = ViewTreeSupport.outlinedStepperButton(context, "+"); - MaterialButton reset = ViewTreeSupport.outlinedStepperButton(context, "D"); - EditText input = ViewTreeSupport.numericInput(context, false, 3); - int current = SbtSettings.clampIconHeightSteps(prefs.getInt(key, defaultValue)); - input.setText(String.valueOf(current)); - row.addView(minus, ViewTreeSupport.stepperButtonParams(context)); - row.addView(input, ViewTreeSupport.stepperInputParams(context)); - row.addView(plus, ViewTreeSupport.stepperButtonParams(context)); - LinearLayout.LayoutParams resetParams = ViewTreeSupport.stepperButtonParams(context); - resetParams.leftMargin = ViewTreeSupport.dp(context, 8); - row.addView(reset, resetParams); - outer.addView(row); - - View.OnClickListener listener = view -> { - int next = SbtSettings.clampIconHeightSteps( - ViewTreeSupport.parseInt(input, current) + (view == minus ? -1 : 1)); - persistIconHeight(prefs, key, input, next); - }; - minus.setOnClickListener(listener); - plus.setOnClickListener(listener); - reset.setOnClickListener(v -> { - int next = SbtSettings.clampIconHeightSteps(defaultValue); - persistIconHeight(prefs, key, input, next); - }); - input.setOnFocusChangeListener((v, hasFocus) -> { - if (!hasFocus) { - int next = SbtSettings.clampIconHeightSteps(ViewTreeSupport.parseInt(input, current)); - persistIconHeight(prefs, key, input, next); - } - }); - return outer; - } - - private void persistIconHeight( - SharedPreferences prefs, - String key, - EditText input, - int value - ) { - prefs.edit().putInt(key, value).apply(); - SbtSettings.ensureReadable(requireContext()); - input.setText(String.valueOf(value)); + return ViewTreeSupport.intPreferenceStepper( + requireContext(), + prefs, + labelRes, + key, + defaultValue, + SbtDefaults.LAYOUT_ICON_HEIGHT_STEPS_MIN, + SbtDefaults.LAYOUT_ICON_HEIGHT_STEPS_MAX, + false, + 3, + 0, + 0, + 0, + true, + true, + null); } private void addChipHeightControl(View root, SharedPreferences prefs) { @@ -424,11 +348,9 @@ public final class LayoutFragment extends Fragment { int titleId, int index, SbtSettings.IndexedKey positionKey, - SbtSettings.IndexedKey autoNearestKey, SbtSettings.IndexedKey middleSideKey, SbtSettings.IndexedKey verticalOffsetKey, String positionDefault, - boolean autoNearestDefault, String middleSideDefault, int verticalOffsetDefault, String copyTag @@ -447,11 +369,11 @@ public final class LayoutFragment extends Fragment { prefs, R.id.notif_position_group, R.id.notif_position_middle_options_container, - R.id.notif_middle_auto_nearest, + View.NO_ID, R.id.notif_middle_side_prompt, positionKey.key(index), positionDefault, - autoNearestKey.key(index), + null, middleSideKey.key(index)); bindStepper(prefs, verticalOffsetKey.key(index), @@ -467,11 +389,11 @@ public final class LayoutFragment extends Fragment { prefs, R.id.status_position_group, R.id.status_position_middle_options_container, - R.id.status_middle_auto_nearest, + View.NO_ID, R.id.status_middle_side_prompt, positionKey.key(index), positionDefault, - autoNearestKey.key(index), + null, middleSideKey.key(index)); bindStepper(prefs, verticalOffsetKey.key(index), @@ -563,30 +485,6 @@ public final class LayoutFragment extends Fragment { } } - private int iconContainerCount( - SharedPreferences prefs, - String countKey, - int countDefault, - String legacyEnabledKey, - boolean legacyEnabledDefault - ) { - int fallback = prefs.getBoolean(legacyEnabledKey, legacyEnabledDefault) ? countDefault : 0; - return SbtSettings.clampIconContainerCount(prefs.getInt(countKey, fallback)); - } - - private void persistIconContainerCount( - SharedPreferences prefs, - String countKey, - String legacyEnabledKey, - int count - ) { - prefs.edit() - .putInt(countKey, SbtSettings.clampIconContainerCount(count)) - .putBoolean(legacyEnabledKey, count > 0) - .apply(); - SbtSettings.ensureReadable(requireContext()); - } - private void hideUnlockedSubpageObsoleteControls(View root) { hide(root, R.id.clock_position_mode_lockscreen); hide(root, R.id.notif_position_mode_aod); @@ -620,59 +518,57 @@ public final class LayoutFragment extends Fragment { int middleOptionsId, int autoNearestId, int promptId, - @Nullable String positionKey, - @Nullable String positionDefault, + String positionKey, + String positionDefault, @Nullable String autoNearestKey, - @Nullable String middleSideKey) { + String middleSideKey) { RadioGroup group = root.findViewById(groupId); View middleOptions = root.findViewById(middleOptionsId); CheckBox autoNearest = root.findViewById(autoNearestId); TextView prompt = root.findViewById(promptId); - if (group == null || middleOptions == null || autoNearest == null || prompt == null) { + if (group == null || middleOptions == null || prompt == null) { return; } - if (positionKey != null && positionDefault != null) { - group.check(positionIdForValue(groupId, prefs.getString(positionKey, positionDefault))); - } - if (autoNearestKey != null) { + group.check(positionIdForValue(groupId, prefs.getString(positionKey, positionDefault))); + boolean autoNearestAvailable = autoNearestKey != null && autoNearest != null; + if (autoNearestAvailable) { autoNearest.setChecked(prefs.getBoolean(autoNearestKey, true)); + } else if (autoNearest != null) { + autoNearest.setChecked(false); + autoNearest.setVisibility(View.GONE); } updateMiddleOptions(middleOptions, autoNearest, prompt, group.getCheckedRadioButtonId()); group.setOnCheckedChangeListener((radioGroup, id) -> { updateMiddleOptions(middleOptions, autoNearest, prompt, id); - if (positionKey != null) { - prefs.edit().putString(positionKey, positionValueForId(id)).apply(); - SbtSettings.ensureReadable(requireContext()); - } + prefs.edit().putString(positionKey, positionValueForId(id)).apply(); + SbtSettings.ensureReadable(requireContext()); }); - autoNearest.setOnCheckedChangeListener((buttonView, isChecked) -> { - updateMiddlePrompt(prompt, isChecked); - if (autoNearestKey != null) { + if (autoNearestAvailable) { + autoNearest.setOnCheckedChangeListener((buttonView, isChecked) -> { + updateMiddlePrompt(prompt, isChecked); prefs.edit().putBoolean(autoNearestKey, isChecked).apply(); SbtSettings.ensureReadable(requireContext()); - } - }); + }); + } - if (middleSideKey != null) { - RadioGroup sideGroup = resolveMiddleSideGroup(root, groupId); - if (sideGroup != null) { - sideGroup.check(sideIdForValue(sideGroup, prefs.getString(middleSideKey, "left"))); - sideGroup.setOnCheckedChangeListener((g, checkedId) -> { - prefs.edit().putString(middleSideKey, checkedId == resolveRightSideId(g) ? "right" : "left").apply(); - SbtSettings.ensureReadable(requireContext()); - }); - } + RadioGroup sideGroup = resolveMiddleSideGroup(root, groupId); + if (sideGroup != null) { + sideGroup.check(sideIdForValue(sideGroup, prefs.getString(middleSideKey, "left"))); + sideGroup.setOnCheckedChangeListener((g, checkedId) -> { + prefs.edit().putString(middleSideKey, checkedId == resolveRightSideId(g) ? "right" : "left").apply(); + SbtSettings.ensureReadable(requireContext()); + }); } } private void updateMiddleOptions(View middleOptions, - CheckBox autoNearest, + @Nullable CheckBox autoNearest, TextView prompt, int checkedId) { - if (middleOptions == null || autoNearest == null || prompt == null) { + if (middleOptions == null || prompt == null) { return; } if (middleOptions.getVisibility() != View.VISIBLE) { @@ -681,7 +577,7 @@ public final class LayoutFragment extends Fragment { boolean enabled = isMiddleSelection(checkedId); ViewTreeSupport.setEnabledRecursive(middleOptions, enabled); middleOptions.setAlpha(enabled ? 1f : 0.45f); - updateMiddlePrompt(prompt, autoNearest.isChecked()); + updateMiddlePrompt(prompt, autoNearest != null && autoNearest.isChecked()); } private boolean isMiddleSelection(int checkedId) { @@ -700,37 +596,6 @@ public final class LayoutFragment extends Fragment { : R.string.layout_middle_side_prompt_attach_only); } - private void bindStepper(SharedPreferences prefs, - @Nullable String key, - @Nullable EditText input, - @Nullable MaterialButton minusButton, - @Nullable MaterialButton plusButton, - int initialValue) { - bindStepper(prefs, key, input, null, minusButton, plusButton, null, null, initialValue); - } - - private void bindStepper(SharedPreferences prefs, - @Nullable String key, - @Nullable EditText input, - @Nullable MaterialButton minusButton, - @Nullable MaterialButton plusButton, - int initialValue, - int minValue, - int maxValue) { - bindStepper( - prefs, - key, - input, - null, - minusButton, - plusButton, - null, - null, - initialValue, - minValue, - maxValue); - } - private void bindStepper(SharedPreferences prefs, @Nullable String key, @Nullable EditText input, @@ -880,8 +745,7 @@ public final class LayoutFragment extends Fragment { if (key == null) { return; } - prefs.edit().putInt(key, value).apply(); - SbtSettings.ensureReadable(requireContext()); + ViewTreeSupport.persistIntPreference(requireContext(), prefs, key, value); } private int positionIdForValue(int groupId, @Nullable String value) { diff --git a/app/src/main/java/se/ajpanton/statusbartweak/shell/ui/LayoutHomeFragment.java b/app/src/main/java/se/ajpanton/statusbartweak/shell/ui/LayoutHomeFragment.java index 20d6d91..3cca87b 100644 --- a/app/src/main/java/se/ajpanton/statusbartweak/shell/ui/LayoutHomeFragment.java +++ b/app/src/main/java/se/ajpanton/statusbartweak/shell/ui/LayoutHomeFragment.java @@ -6,7 +6,6 @@ import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.EditText; import android.widget.LinearLayout; import android.widget.RadioGroup; import android.widget.ScrollView; @@ -16,7 +15,6 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; -import com.google.android.material.button.MaterialButton; import com.google.android.material.switchmaterial.SwitchMaterial; import se.ajpanton.statusbartweak.R; @@ -38,7 +36,7 @@ public final class LayoutHomeFragment extends Fragment { Context context = requireContext(); SharedPreferences prefs = context.getSharedPreferences(SbtSettings.PREFS_NAME, Context.MODE_PRIVATE); ScrollView scroll = new ScrollView(context); - LinearLayout root = vertical(context); + LinearLayout root = ViewTreeSupport.verticalLayout(context); root.setPadding( ViewTreeSupport.dp(context, 20), ViewTreeSupport.dp(context, 20), @@ -46,23 +44,23 @@ public final class LayoutHomeFragment extends Fragment { ViewTreeSupport.dp(context, 20)); scroll.addView(root); - TextView title = title(context, R.string.layout_home_title); + TextView title = ViewTreeSupport.titleText(context, R.string.layout_home_title); root.addView(title); SwitchMaterial master = new SwitchMaterial(context); master.setText(R.string.layout_enabled); master.setChecked(prefs.getBoolean(SbtSettings.KEY_CLOCK_ENABLED, SbtDefaults.CLOCK_ENABLED_DEFAULT)); - root.addView(card(context, R.string.layout_master_toggle_title, master)); + root.addView(outlinedCard(context, R.string.layout_master_toggle_title, master)); lockedModeGroup = new RadioGroup(context); lockedModeGroup.setOrientation(RadioGroup.VERTICAL); - lockedModeHint = body(context, R.string.layout_locked_notifications_hint); - LinearLayout lockedContent = vertical(context); + lockedModeHint = ViewTreeSupport.bodyText(context, R.string.layout_locked_notifications_hint, 0); + LinearLayout lockedContent = ViewTreeSupport.verticalLayout(context); lockedContent.addView(lockedModeHint); lockedContent.addView(lockedModeGroup); - root.addView(card(context, R.string.layout_locked_notifications_title, lockedContent)); + root.addView(outlinedCard(context, R.string.layout_locked_notifications_title, lockedContent)); - layoutOnContainer = vertical(context); + layoutOnContainer = ViewTreeSupport.verticalLayout(context); layoutOnContainer.addView(paddingCard(context, prefs)); layoutOnContainer.addView(LayoutOrderingUi.createCard(context, prefs)); root.addView(layoutOnContainer); @@ -94,7 +92,7 @@ public final class LayoutHomeFragment extends Fragment { } private View paddingCard(Context context, SharedPreferences prefs) { - LinearLayout content = vertical(context); + LinearLayout content = ViewTreeSupport.verticalLayout(context); content.addView(stepper( context, prefs, @@ -141,12 +139,12 @@ public final class LayoutHomeFragment extends Fragment { SbtDefaults.LAYOUT_ITEM_PADDING_PX_DEFAULT, SbtDefaults.LAYOUT_ITEM_PADDING_PX_MIN, SbtDefaults.LAYOUT_ITEM_PADDING_PX_MAX)); - return card(context, R.string.layout_padding_title, content); + return outlinedCard(context, R.string.layout_padding_title, content); } private View miscCard(Context context, SharedPreferences prefs) { - LinearLayout content = vertical(context); - miscLayoutOnContainer = vertical(context); + LinearLayout content = ViewTreeSupport.verticalLayout(context); + miscLayoutOnContainer = ViewTreeSupport.verticalLayout(context); miscLayoutOnContainer.addView(ViewTreeSupport.boundCheckBox( context, prefs, @@ -155,7 +153,7 @@ public final class LayoutHomeFragment extends Fragment { SbtDefaults.LAYOUT_IGNORE_UNDER_DISPLAY_CAMERAS_DEFAULT, false)); content.addView(miscLayoutOnContainer); - miscUnlockedOffOnlyContainer = vertical(context); + miscUnlockedOffOnlyContainer = ViewTreeSupport.verticalLayout(context); miscUnlockedOffOnlyContainer.addView(stepper( context, prefs, @@ -165,7 +163,7 @@ public final class LayoutHomeFragment extends Fragment { SbtDefaults.UNLOCKED_MAX_ICONS_PER_ROW_MIN, SbtDefaults.UNLOCKED_MAX_ICONS_PER_ROW_MAX)); content.addView(miscUnlockedOffOnlyContainer); - return card(context, R.string.layout_misc_title, content); + return outlinedCard(context, R.string.layout_misc_title, content); } private View stepper( @@ -190,65 +188,28 @@ public final class LayoutHomeFragment extends Fragment { int max, @Nullable View trailingView ) { - LinearLayout outer = vertical(context); - TextView label = body(context, labelId); - outer.addView(label); - LinearLayout row = new LinearLayout(context); - row.setOrientation(LinearLayout.HORIZONTAL); - row.setGravity(android.view.Gravity.CENTER_VERTICAL); - row.setPadding(0, ViewTreeSupport.dp(context, 6), 0, ViewTreeSupport.dp(context, 8)); - MaterialButton minus = ViewTreeSupport.outlinedStepperButton(context, "-"); - MaterialButton plus = ViewTreeSupport.outlinedStepperButton(context, "+"); - EditText input = ViewTreeSupport.numericInput(context, true, 5); - input.setText(String.valueOf(ViewTreeSupport.clamp(prefs.getInt(key, defaultValue), min, max))); - row.addView(minus, ViewTreeSupport.stepperButtonParams(context)); - row.addView(input, ViewTreeSupport.stepperInputParams(context)); - row.addView(plus, ViewTreeSupport.stepperButtonParams(context)); - if (trailingView != null) { - LinearLayout.LayoutParams trailingParams = new LinearLayout.LayoutParams( - ViewGroup.LayoutParams.WRAP_CONTENT, - ViewGroup.LayoutParams.WRAP_CONTENT); - trailingParams.leftMargin = ViewTreeSupport.dp(context, 8); - row.addView(trailingView, trailingParams); - } - outer.addView(row); - View.OnClickListener listener = v -> { - int delta = v == minus ? -1 : 1; - int next = ViewTreeSupport.clamp(ViewTreeSupport.parseInt(input, defaultValue) + delta, min, max); - input.setText(String.valueOf(next)); - prefs.edit().putInt(key, next).apply(); - SbtSettings.ensureReadable(context); - }; - minus.setOnClickListener(listener); - plus.setOnClickListener(listener); - input.setOnFocusChangeListener((v, hasFocus) -> { - if (!hasFocus) { - int next = ViewTreeSupport.clamp(ViewTreeSupport.parseInt(input, defaultValue), min, max); - input.setText(String.valueOf(next)); - prefs.edit().putInt(key, next).apply(); - SbtSettings.ensureReadable(context); - } - }); - return outer; + return ViewTreeSupport.intPreferenceStepper( + context, + prefs, + labelId, + key, + defaultValue, + min, + max, + true, + 5, + 0, + 6, + 8, + false, + false, + trailingView); } - private View card(Context context, int titleId, View content) { - return ViewTreeSupport.outlinedCard(context, sectionTitle(context, titleId), content); - } - - private LinearLayout vertical(Context context) { - return ViewTreeSupport.verticalLayout(context); - } - - private TextView title(Context context, int stringId) { - return ViewTreeSupport.titleText(context, stringId); - } - - private TextView sectionTitle(Context context, int stringId) { - return ViewTreeSupport.sectionTitleText(context, stringId, true); - } - - private TextView body(Context context, int stringId) { - return ViewTreeSupport.bodyText(context, stringId, 0); + private View outlinedCard(Context context, int titleId, View content) { + return ViewTreeSupport.outlinedCard( + context, + ViewTreeSupport.sectionTitleText(context, titleId, true), + content); } } diff --git a/app/src/main/java/se/ajpanton/statusbartweak/shell/ui/LayoutOrderingUi.java b/app/src/main/java/se/ajpanton/statusbartweak/shell/ui/LayoutOrderingUi.java index 82d4302..66cae98 100644 --- a/app/src/main/java/se/ajpanton/statusbartweak/shell/ui/LayoutOrderingUi.java +++ b/app/src/main/java/se/ajpanton/statusbartweak/shell/ui/LayoutOrderingUi.java @@ -30,8 +30,8 @@ final class LayoutOrderingUi { } static View createCard(Context context, SharedPreferences prefs) { - LinearLayout content = vertical(context); - TextView hint = body(context, R.string.layout_ordering_hint); + LinearLayout content = ViewTreeSupport.verticalLayout(context); + TextView hint = bodyText(context, R.string.layout_ordering_hint); content.addView(hint); RecyclerView list = new RecyclerView(context); @@ -43,7 +43,7 @@ final class LayoutOrderingUi { content.addView(list, listParams); bindOrderingList(context, prefs, list); - TextView sortTitle = body(context, R.string.layout_sort_icons_title); + TextView sortTitle = bodyText(context, R.string.layout_sort_icons_title); sortTitle.setTypeface(sortTitle.getTypeface(), android.graphics.Typeface.BOLD); LinearLayout.LayoutParams sortTitleParams = new LinearLayout.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, @@ -71,7 +71,10 @@ final class LayoutOrderingUi { sortParams.topMargin = ViewTreeSupport.dp(context, 8); content.addView(sortGroup, sortParams); - return card(context, R.string.layout_ordering_title, content); + return ViewTreeSupport.outlinedCard( + context, + ViewTreeSupport.sectionTitleText(context, R.string.layout_ordering_title, true), + content); } static ArrayList orderedKeys(SharedPreferences prefs) { @@ -225,18 +228,7 @@ final class LayoutOrderingUi { return tag instanceof String value ? value : "automatic"; } - private static View card(Context context, int titleId, View content) { - return ViewTreeSupport.outlinedCard( - context, - ViewTreeSupport.sectionTitleText(context, titleId, true), - content); - } - - private static LinearLayout vertical(Context context) { - return ViewTreeSupport.verticalLayout(context); - } - - private static TextView body(Context context, int stringId) { + private static TextView bodyText(Context context, int stringId) { TextView view = new TextView(context); view.setText(stringId); view.setTextAppearance(com.google.android.material.R.style.TextAppearance_MaterialComponents_Body2); diff --git a/app/src/main/java/se/ajpanton/statusbartweak/shell/ui/LayoutSectionCopySupport.java b/app/src/main/java/se/ajpanton/statusbartweak/shell/ui/LayoutSectionCopySupport.java index d8d7f62..25f7dcc 100644 --- a/app/src/main/java/se/ajpanton/statusbartweak/shell/ui/LayoutSectionCopySupport.java +++ b/app/src/main/java/se/ajpanton/statusbartweak/shell/ui/LayoutSectionCopySupport.java @@ -197,7 +197,6 @@ final class LayoutSectionCopySupport { copyInt(editor, prefs, src.iconHeight, dst.iconHeight, src.iconHeightDefault); for (int i = 0; i < MAX_COPIES; i++) { copyString(editor, prefs, src.positionAt(i), dst.positionAt(i), src.positionDefault); - copyBoolean(editor, prefs, src.autoNearestAt(i), dst.autoNearestAt(i), src.autoNearestDefault); copyString(editor, prefs, src.middleSideAt(i), dst.middleSideAt(i), src.middleSideDefault); copyInt(editor, prefs, src.verticalOffsetAt(i), dst.verticalOffsetAt(i), src.verticalOffsetDefault); } @@ -276,14 +275,12 @@ final class LayoutSectionCopySupport { SbtSettings.KEY_LAYOUT_NOTIF_ENABLED_LOCKSCREEN, SbtSettings.KEY_LAYOUT_NOTIF_LOCK_COUNT, SbtSettings.KEY_LAYOUT_NOTIF_LOCK_POSITION, - SbtSettings.KEY_LAYOUT_NOTIF_LOCK_MIDDLE_AUTO_NEAREST_SIDE, SbtSettings.KEY_LAYOUT_NOTIF_LOCK_MIDDLE_SIDE, SbtSettings.KEY_LAYOUT_NOTIF_LOCK_VERTICAL_OFFSET_PX, SbtSettings.layoutLockNotifIconHeightKey(), SbtDefaults.LAYOUT_NOTIF_ENABLED_LOCKSCREEN_DEFAULT, SbtDefaults.LAYOUT_NOTIF_UNLOCKED_COUNT_DEFAULT, SbtDefaults.LAYOUT_NOTIF_POSITION_DEFAULT, - SbtDefaults.LAYOUT_NOTIF_MIDDLE_AUTO_NEAREST_SIDE_DEFAULT, SbtDefaults.LAYOUT_NOTIF_MIDDLE_SIDE_DEFAULT, SbtDefaults.LAYOUT_NOTIF_VERTICAL_OFFSET_PX_DEFAULT, SbtDefaults.LAYOUT_NOTIF_LOCK_ICON_HEIGHT_STEPS_DEFAULT); @@ -293,14 +290,12 @@ final class LayoutSectionCopySupport { SbtSettings.KEY_LAYOUT_NOTIF_ENABLED_AOD, SbtSettings.KEY_LAYOUT_NOTIF_AOD_COUNT, SbtSettings.KEY_LAYOUT_NOTIF_AOD_POSITION, - SbtSettings.KEY_LAYOUT_NOTIF_AOD_MIDDLE_AUTO_NEAREST_SIDE, SbtSettings.KEY_LAYOUT_NOTIF_AOD_MIDDLE_SIDE, SbtSettings.KEY_LAYOUT_NOTIF_AOD_VERTICAL_OFFSET_PX, SbtSettings.layoutAodNotifIconHeightKey(), SbtDefaults.LAYOUT_NOTIF_ENABLED_AOD_DEFAULT, SbtDefaults.LAYOUT_NOTIF_UNLOCKED_COUNT_DEFAULT, SbtDefaults.LAYOUT_NOTIF_POSITION_DEFAULT, - SbtDefaults.LAYOUT_NOTIF_MIDDLE_AUTO_NEAREST_SIDE_DEFAULT, SbtDefaults.LAYOUT_NOTIF_MIDDLE_SIDE_DEFAULT, SbtDefaults.LAYOUT_NOTIF_VERTICAL_OFFSET_PX_DEFAULT, SbtDefaults.LAYOUT_NOTIF_AOD_ICON_HEIGHT_STEPS_DEFAULT); @@ -309,14 +304,12 @@ final class LayoutSectionCopySupport { SbtSettings.KEY_LAYOUT_NOTIF_ENABLED_UNLOCKED, SbtSettings.KEY_LAYOUT_NOTIF_UNLOCKED_COUNT, SbtSettings.KEY_LAYOUT_NOTIF_POSITION, - SbtSettings.KEY_LAYOUT_NOTIF_MIDDLE_AUTO_NEAREST_SIDE, SbtSettings.KEY_LAYOUT_NOTIF_MIDDLE_SIDE, SbtSettings.KEY_LAYOUT_NOTIF_VERTICAL_OFFSET_PX, SbtSettings.KEY_LAYOUT_NOTIF_ICON_HEIGHT_STEPS, SbtDefaults.LAYOUT_NOTIF_ENABLED_UNLOCKED_DEFAULT, SbtDefaults.LAYOUT_NOTIF_UNLOCKED_COUNT_DEFAULT, SbtDefaults.LAYOUT_NOTIF_POSITION_DEFAULT, - SbtDefaults.LAYOUT_NOTIF_MIDDLE_AUTO_NEAREST_SIDE_DEFAULT, SbtDefaults.LAYOUT_NOTIF_MIDDLE_SIDE_DEFAULT, SbtDefaults.LAYOUT_NOTIF_VERTICAL_OFFSET_PX_DEFAULT, SbtDefaults.LAYOUT_NOTIF_ICON_HEIGHT_STEPS_DEFAULT); @@ -328,14 +321,12 @@ final class LayoutSectionCopySupport { SbtSettings.KEY_LAYOUT_STATUS_ENABLED_LOCKSCREEN, SbtSettings.KEY_LAYOUT_STATUS_LOCK_COUNT, SbtSettings.KEY_LAYOUT_STATUS_LOCK_POSITION, - SbtSettings.KEY_LAYOUT_STATUS_LOCK_MIDDLE_AUTO_NEAREST_SIDE, SbtSettings.KEY_LAYOUT_STATUS_LOCK_MIDDLE_SIDE, SbtSettings.KEY_LAYOUT_STATUS_LOCK_VERTICAL_OFFSET_PX, SbtSettings.layoutLockStatusIconHeightKey(), SbtDefaults.LAYOUT_STATUS_ENABLED_LOCKSCREEN_DEFAULT, SbtDefaults.LAYOUT_STATUS_UNLOCKED_COUNT_DEFAULT, SbtDefaults.LAYOUT_STATUS_POSITION_DEFAULT, - SbtDefaults.LAYOUT_STATUS_MIDDLE_AUTO_NEAREST_SIDE_DEFAULT, SbtDefaults.LAYOUT_STATUS_MIDDLE_SIDE_DEFAULT, SbtDefaults.LAYOUT_STATUS_VERTICAL_OFFSET_PX_DEFAULT, SbtDefaults.LAYOUT_STATUS_ICON_HEIGHT_STEPS_DEFAULT); @@ -345,14 +336,12 @@ final class LayoutSectionCopySupport { SbtSettings.KEY_LAYOUT_STATUS_ENABLED_AOD, SbtSettings.KEY_LAYOUT_STATUS_AOD_COUNT, SbtSettings.KEY_LAYOUT_STATUS_AOD_POSITION, - SbtSettings.KEY_LAYOUT_STATUS_AOD_MIDDLE_AUTO_NEAREST_SIDE, SbtSettings.KEY_LAYOUT_STATUS_AOD_MIDDLE_SIDE, SbtSettings.KEY_LAYOUT_STATUS_AOD_VERTICAL_OFFSET_PX, SbtSettings.layoutAodStatusIconHeightKey(), SbtDefaults.LAYOUT_STATUS_ENABLED_AOD_DEFAULT, SbtDefaults.LAYOUT_STATUS_UNLOCKED_COUNT_DEFAULT, SbtDefaults.LAYOUT_STATUS_POSITION_DEFAULT, - SbtDefaults.LAYOUT_STATUS_MIDDLE_AUTO_NEAREST_SIDE_DEFAULT, SbtDefaults.LAYOUT_STATUS_MIDDLE_SIDE_DEFAULT, SbtDefaults.LAYOUT_STATUS_VERTICAL_OFFSET_PX_DEFAULT, SbtDefaults.LAYOUT_STATUS_ICON_HEIGHT_STEPS_DEFAULT); @@ -361,14 +350,12 @@ final class LayoutSectionCopySupport { SbtSettings.KEY_LAYOUT_STATUS_ENABLED_UNLOCKED, SbtSettings.KEY_LAYOUT_STATUS_UNLOCKED_COUNT, SbtSettings.KEY_LAYOUT_STATUS_POSITION, - SbtSettings.KEY_LAYOUT_STATUS_MIDDLE_AUTO_NEAREST_SIDE, SbtSettings.KEY_LAYOUT_STATUS_MIDDLE_SIDE, SbtSettings.KEY_LAYOUT_STATUS_VERTICAL_OFFSET_PX, SbtSettings.KEY_LAYOUT_STATUS_ICON_HEIGHT_STEPS, SbtDefaults.LAYOUT_STATUS_ENABLED_UNLOCKED_DEFAULT, SbtDefaults.LAYOUT_STATUS_UNLOCKED_COUNT_DEFAULT, SbtDefaults.LAYOUT_STATUS_POSITION_DEFAULT, - SbtDefaults.LAYOUT_STATUS_MIDDLE_AUTO_NEAREST_SIDE_DEFAULT, SbtDefaults.LAYOUT_STATUS_MIDDLE_SIDE_DEFAULT, SbtDefaults.LAYOUT_STATUS_VERTICAL_OFFSET_PX_DEFAULT, SbtDefaults.LAYOUT_STATUS_ICON_HEIGHT_STEPS_DEFAULT); @@ -405,14 +392,12 @@ final class LayoutSectionCopySupport { String enabled, String count, String position, - String autoNearest, String middleSide, String verticalOffset, String iconHeight, boolean enabledDefault, int countDefault, String positionDefault, - boolean autoNearestDefault, String middleSideDefault, int verticalOffsetDefault, int iconHeightDefault @@ -420,14 +405,14 @@ final class LayoutSectionCopySupport { return new KeySet( enabled, position, - autoNearest, + null, middleSide, verticalOffset, iconHeight, count, enabledDefault, positionDefault, - autoNearestDefault, + false, middleSideDefault, verticalOffsetDefault, iconHeightDefault, @@ -701,10 +686,6 @@ final class LayoutSectionCopySupport { return suffixed(position, index); } - String autoNearestAt(int index) { - return suffixed(autoNearest, index); - } - String middleSideAt(int index) { return suffixed(middleSide, index); } diff --git a/app/src/main/java/se/ajpanton/statusbartweak/shell/ui/LockedSceneLayoutFragment.java b/app/src/main/java/se/ajpanton/statusbartweak/shell/ui/LockedSceneLayoutFragment.java index b838b8d..47e3183 100644 --- a/app/src/main/java/se/ajpanton/statusbartweak/shell/ui/LockedSceneLayoutFragment.java +++ b/app/src/main/java/se/ajpanton/statusbartweak/shell/ui/LockedSceneLayoutFragment.java @@ -4,7 +4,6 @@ import android.content.Context; import android.content.SharedPreferences; import android.os.Bundle; import android.text.InputFilter; -import android.view.Gravity; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -20,6 +19,7 @@ import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; import com.google.android.material.button.MaterialButton; + import java.util.LinkedHashMap; import se.ajpanton.statusbartweak.R; @@ -44,7 +44,7 @@ abstract class LockedSceneLayoutFragment extends Fragment { Context context = requireContext(); SharedPreferences prefs = context.getSharedPreferences(SbtSettings.PREFS_NAME, Context.MODE_PRIVATE); ScrollView scroll = new ScrollView(context); - LinearLayout root = vertical(context); + LinearLayout root = ViewTreeSupport.verticalLayout(context); root.setPadding( ViewTreeSupport.dp(context, 20), ViewTreeSupport.dp(context, 20), @@ -52,16 +52,18 @@ abstract class LockedSceneLayoutFragment extends Fragment { ViewTreeSupport.dp(context, 20)); scroll.addView(root); - root.addView(title(context, aod ? R.string.section_aod : R.string.section_lockscreen)); + root.addView(ViewTreeSupport.titleText( + context, + aod ? R.string.section_aod : R.string.section_lockscreen)); modeGroup = new RadioGroup(context); modeGroup.setOrientation(RadioGroup.VERTICAL); - modeHint = body(context, R.string.layout_locked_notifications_hint); - LinearLayout modeContent = vertical(context); + modeHint = ViewTreeSupport.bodyText(context, R.string.layout_locked_notifications_hint, 6); + LinearLayout modeContent = ViewTreeSupport.verticalLayout(context); modeContent.addView(modeHint); modeContent.addView(modeGroup); - root.addView(card(context, R.string.layout_locked_notifications_title, modeContent)); + root.addView(outlinedCard(context, R.string.layout_locked_notifications_title, modeContent)); - dynamicContent = vertical(context); + dynamicContent = ViewTreeSupport.verticalLayout(context); root.addView(dynamicContent); bindMode(context, prefs); return scroll; @@ -142,8 +144,8 @@ abstract class LockedSceneLayoutFragment extends Fragment { R.id.clock_vertical_offset_reset, SbtSettings.KEY_LAYOUT_CARRIER_POSITION, SbtDefaults.LAYOUT_CARRIER_POSITION_DEFAULT, - SbtSettings.KEY_LAYOUT_CARRIER_MIDDLE_AUTO_NEAREST_SIDE, - SbtDefaults.LAYOUT_CARRIER_MIDDLE_AUTO_NEAREST_SIDE_DEFAULT, + null, + false, SbtSettings.KEY_LAYOUT_CARRIER_MIDDLE_SIDE, SbtDefaults.LAYOUT_CARRIER_MIDDLE_SIDE_DEFAULT, SbtSettings.KEY_LAYOUT_CARRIER_VERTICAL_OFFSET_PX, @@ -159,7 +161,7 @@ abstract class LockedSceneLayoutFragment extends Fragment { aod ? R.id.status_position_mode_aod : R.id.status_position_mode_lockscreen, R.id.status_position_group, R.id.status_position_middle_options_container, - R.id.status_middle_auto_nearest, + View.NO_ID, R.id.status_middle_side_prompt, R.id.status_middle_side_group, R.id.status_middle_side_right, @@ -173,7 +175,6 @@ abstract class LockedSceneLayoutFragment extends Fragment { aod ? SbtSettings.KEY_LAYOUT_STATUS_ENABLED_AOD : SbtSettings.KEY_LAYOUT_STATUS_ENABLED_LOCKSCREEN, aod ? SbtDefaults.LAYOUT_STATUS_ENABLED_AOD_DEFAULT : SbtDefaults.LAYOUT_STATUS_ENABLED_LOCKSCREEN_DEFAULT, SbtDefaults.LAYOUT_STATUS_POSITION_DEFAULT, - SbtDefaults.LAYOUT_STATUS_MIDDLE_AUTO_NEAREST_SIDE_DEFAULT, SbtDefaults.LAYOUT_STATUS_MIDDLE_SIDE_DEFAULT, SbtDefaults.LAYOUT_STATUS_VERTICAL_OFFSET_PX_DEFAULT, aod ? SbtSettings.layoutAodStatusIconHeightKey() : SbtSettings.layoutLockStatusIconHeightKey(), @@ -192,7 +193,7 @@ abstract class LockedSceneLayoutFragment extends Fragment { aod ? R.id.notif_position_mode_aod : R.id.notif_position_mode_lockscreen, R.id.notif_position_group, R.id.notif_position_middle_options_container, - R.id.notif_middle_auto_nearest, + View.NO_ID, R.id.notif_middle_side_prompt, R.id.notif_middle_side_group, R.id.notif_middle_side_right, @@ -206,7 +207,6 @@ abstract class LockedSceneLayoutFragment extends Fragment { aod ? SbtSettings.KEY_LAYOUT_NOTIF_ENABLED_AOD : SbtSettings.KEY_LAYOUT_NOTIF_ENABLED_LOCKSCREEN, aod ? SbtDefaults.LAYOUT_NOTIF_ENABLED_AOD_DEFAULT : SbtDefaults.LAYOUT_NOTIF_ENABLED_LOCKSCREEN_DEFAULT, SbtDefaults.LAYOUT_NOTIF_POSITION_DEFAULT, - SbtDefaults.LAYOUT_NOTIF_MIDDLE_AUTO_NEAREST_SIDE_DEFAULT, SbtDefaults.LAYOUT_NOTIF_MIDDLE_SIDE_DEFAULT, SbtDefaults.LAYOUT_NOTIF_VERTICAL_OFFSET_PX_DEFAULT, aod ? SbtSettings.layoutAodNotifIconHeightKey() : SbtSettings.layoutLockNotifIconHeightKey(), @@ -307,7 +307,6 @@ abstract class LockedSceneLayoutFragment extends Fragment { String legacyEnabledKey, boolean legacyEnabledDefault, String positionDefault, - boolean autoNearestDefault, String middleSideDefault, int verticalOffsetDefault, String iconHeightKey, @@ -316,12 +315,17 @@ abstract class LockedSceneLayoutFragment extends Fragment { boolean cardsMode, @Nullable Runnable refresh ) { - LinearLayout wrapper = vertical(context); + LinearLayout wrapper = ViewTreeSupport.verticalLayout(context); String countKey = sceneKey(base + "_count"); Runnable[] rebuild = new Runnable[1]; rebuild[0] = () -> { wrapper.removeAllViews(); - int count = iconContainerCount(prefs, countKey, legacyEnabledKey, legacyEnabledDefault); + int count = ViewTreeSupport.iconContainerCount( + prefs, + countKey, + legacyEnabledKey, + 1, + legacyEnabledDefault); View primary = configuredIconContainerCard( context, prefs, @@ -343,8 +347,6 @@ abstract class LockedSceneLayoutFragment extends Fragment { 0, indexedSceneKey(base + "_position", 0), positionDefault, - indexedSceneKey(base + "_middle_auto_nearest_side", 0), - autoNearestDefault, indexedSceneKey(base + "_middle_side", 0), middleSideDefault, indexedSceneKey(base + "_vertical_offset_px", 0), @@ -379,8 +381,6 @@ abstract class LockedSceneLayoutFragment extends Fragment { i, indexedSceneKey(base + "_position", i), positionDefault, - indexedSceneKey(base + "_middle_auto_nearest_side", i), - autoNearestDefault, indexedSceneKey(base + "_middle_side", i), middleSideDefault, indexedSceneKey(base + "_vertical_offset_px", i), @@ -441,8 +441,6 @@ abstract class LockedSceneLayoutFragment extends Fragment { int index, String positionKey, String positionDefault, - String autoNearestKey, - boolean autoNearestDefault, String middleSideKey, String middleSideDefault, String verticalOffsetKey, @@ -460,7 +458,16 @@ abstract class LockedSceneLayoutFragment extends Fragment { if (sectionContent != null && countKey != null && onCountChanged != null) { int insertIndex = Math.min(1, sectionContent.getChildCount()); sectionContent.addView( - iconContainerCountControl(context, prefs, countKey, legacyEnabledKey, count, onCountChanged), + ViewTreeSupport.iconContainerCountControl( + context, + count, + value -> ViewTreeSupport.persistIconContainerCount( + context, + prefs, + countKey, + legacyEnabledKey, + value), + onCountChanged), insertIndex); if (iconHeightKey != null) { sectionContent.addView( @@ -487,8 +494,8 @@ abstract class LockedSceneLayoutFragment extends Fragment { middleSideRightId, positionKey, positionDefault, - autoNearestKey, - autoNearestDefault, + null, + false, middleSideKey, middleSideDefault); bindXmlStepper( @@ -544,7 +551,7 @@ abstract class LockedSceneLayoutFragment extends Fragment { } private View cardsNotificationCard(Context context, SharedPreferences prefs, @Nullable Runnable refresh) { - LinearLayout content = vertical(context); + LinearLayout content = ViewTreeSupport.verticalLayout(context); LayoutSectionCopySupport.addCardsDropdown(context, prefs, content, copyMode(), refresh); content.addView(stepper( context, @@ -586,48 +593,7 @@ abstract class LockedSceneLayoutFragment extends Fragment { : SbtDefaults.LAYOUT_CARDS_NOTIF_LOCK_ICON_HEIGHT_STEPS_DEFAULT, SbtDefaults.LAYOUT_ICON_HEIGHT_STEPS_MIN, SbtDefaults.LAYOUT_ICON_HEIGHT_STEPS_MAX)); - return card(context, R.string.layout_notification_position_title, content); - } - - private View iconContainerCountControl( - Context context, - SharedPreferences prefs, - String countKey, - String legacyEnabledKey, - int current, - Runnable onChanged - ) { - LinearLayout outer = vertical(context); - outer.addView(body(context, R.string.layout_icon_container_count)); - LinearLayout row = new LinearLayout(context); - row.setOrientation(LinearLayout.HORIZONTAL); - row.setGravity(Gravity.CENTER_VERTICAL); - MaterialButton minus = ViewTreeSupport.outlinedStepperButton(context, "-"); - MaterialButton plus = ViewTreeSupport.outlinedStepperButton(context, "+"); - EditText input = ViewTreeSupport.numericInput(context, false, 4); - input.setFilters(new InputFilter[]{new InputFilter.LengthFilter(1)}); - input.setText(String.valueOf(current)); - row.addView(minus, ViewTreeSupport.stepperButtonParams(context)); - row.addView(input, ViewTreeSupport.stepperInputParams(context)); - row.addView(plus, ViewTreeSupport.stepperButtonParams(context)); - outer.addView(row); - - View.OnClickListener listener = view -> { - int next = SbtSettings.clampIconContainerCount( - ViewTreeSupport.parseInt(input, current) + (view == minus ? -1 : 1)); - persistIconContainerCount(prefs, countKey, legacyEnabledKey, next); - onChanged.run(); - }; - minus.setOnClickListener(listener); - plus.setOnClickListener(listener); - input.setOnFocusChangeListener((v, hasFocus) -> { - if (!hasFocus) { - int next = SbtSettings.clampIconContainerCount(ViewTreeSupport.parseInt(input, current)); - persistIconContainerCount(prefs, countKey, legacyEnabledKey, next); - onChanged.run(); - } - }); - return outer; + return outlinedCard(context, R.string.layout_notification_position_title, content); } private void bindXmlPositionSection( @@ -641,7 +607,7 @@ abstract class LockedSceneLayoutFragment extends Fragment { int middleSideRightId, String positionKey, String positionDefault, - String autoNearestKey, + @Nullable String autoNearestKey, boolean autoNearestDefault, String middleSideKey, String middleSideDefault @@ -651,17 +617,23 @@ abstract class LockedSceneLayoutFragment extends Fragment { CheckBox autoNearest = root.findViewById(autoNearestId); TextView prompt = root.findViewById(promptId); RadioGroup side = root.findViewById(middleSideGroupId); - if (position == null || middleOptions == null || autoNearest == null || prompt == null || side == null) { + if (position == null || middleOptions == null || prompt == null || side == null) { return; } position.check(positionIdForValue(groupId, prefs.getString(positionKey, positionDefault))); - autoNearest.setChecked(prefs.getBoolean(autoNearestKey, autoNearestDefault)); + boolean autoNearestAvailable = autoNearestKey != null && autoNearest != null; + if (autoNearestAvailable) { + autoNearest.setChecked(prefs.getBoolean(autoNearestKey, autoNearestDefault)); + } else if (autoNearest != null) { + autoNearest.setChecked(false); + autoNearest.setVisibility(View.GONE); + } side.check("right".equals(prefs.getString(middleSideKey, middleSideDefault)) ? middleSideRightId : firstSideId(side, middleSideRightId)); updateMiddleOptions(middleOptions, "middle".equals(positionValueForId(position.getCheckedRadioButtonId()))); - prompt.setText(autoNearest.isChecked() + prompt.setText(autoNearest != null && autoNearest.isChecked() ? R.string.layout_middle_side_prompt_centred : R.string.layout_middle_side_prompt_attach_only); @@ -670,13 +642,15 @@ abstract class LockedSceneLayoutFragment extends Fragment { updateMiddleOptions(middleOptions, "middle".equals(positionValueForId(checkedId))); SbtSettings.ensureReadable(requireContext()); }); - autoNearest.setOnCheckedChangeListener((buttonView, isChecked) -> { - prefs.edit().putBoolean(autoNearestKey, isChecked).apply(); - prompt.setText(isChecked - ? R.string.layout_middle_side_prompt_centred - : R.string.layout_middle_side_prompt_attach_only); - SbtSettings.ensureReadable(requireContext()); - }); + if (autoNearestAvailable) { + autoNearest.setOnCheckedChangeListener((buttonView, isChecked) -> { + prefs.edit().putBoolean(autoNearestKey, isChecked).apply(); + prompt.setText(isChecked + ? R.string.layout_middle_side_prompt_centred + : R.string.layout_middle_side_prompt_attach_only); + SbtSettings.ensureReadable(requireContext()); + }); + } side.setOnCheckedChangeListener((group, checkedId) -> { prefs.edit().putString(middleSideKey, checkedId == middleSideRightId ? "right" : "left").apply(); SbtSettings.ensureReadable(requireContext()); @@ -709,14 +683,14 @@ abstract class LockedSceneLayoutFragment extends Fragment { if (reset != null) { reset.setOnClickListener(v -> { input.setText(String.valueOf(defaultValue)); - persistIntPref(prefs, key, defaultValue); + ViewTreeSupport.persistIntPreference(requireContext(), prefs, key, defaultValue); }); } input.setOnFocusChangeListener((v, hasFocus) -> { if (!hasFocus) { int next = ViewTreeSupport.clamp(ViewTreeSupport.parseInt(input, defaultValue), min, max); input.setText(String.valueOf(next)); - persistIntPref(prefs, key, next); + ViewTreeSupport.persistIntPreference(requireContext(), prefs, key, next); } }); } @@ -736,7 +710,7 @@ abstract class LockedSceneLayoutFragment extends Fragment { button.setOnClickListener(v -> { int next = ViewTreeSupport.clamp(ViewTreeSupport.parseInt(input, 0) + delta, min, max); input.setText(String.valueOf(next)); - persistIntPref(prefs, key, next); + ViewTreeSupport.persistIntPreference(requireContext(), prefs, key, next); }); } @@ -822,79 +796,22 @@ abstract class LockedSceneLayoutFragment extends Fragment { int max, boolean showDefaultButton ) { - LinearLayout outer = vertical(context); - outer.addView(body(context, label)); - LinearLayout row = new LinearLayout(context); - row.setOrientation(LinearLayout.HORIZONTAL); - row.setGravity(Gravity.CENTER_VERTICAL); - MaterialButton minus = ViewTreeSupport.outlinedStepperButton(context, "-"); - MaterialButton plus = ViewTreeSupport.outlinedStepperButton(context, "+"); - MaterialButton reset = showDefaultButton - ? ViewTreeSupport.outlinedStepperButton(context, "D") - : null; - EditText input = ViewTreeSupport.numericInput(context, true, 4); - input.setText(String.valueOf(ViewTreeSupport.clamp(prefs.getInt(key, def), min, max))); - row.addView(minus, ViewTreeSupport.stepperButtonParams(context)); - row.addView(input, ViewTreeSupport.stepperInputParams(context)); - row.addView(plus, ViewTreeSupport.stepperButtonParams(context)); - if (reset != null) { - LinearLayout.LayoutParams resetParams = ViewTreeSupport.stepperButtonParams(context); - resetParams.leftMargin = ViewTreeSupport.dp(context, 8); - row.addView(reset, resetParams); - } - outer.addView(row); - View.OnClickListener listener = view -> { - int delta = view == minus ? -1 : 1; - int next = ViewTreeSupport.clamp(ViewTreeSupport.parseInt(input, def) + delta, min, max); - input.setText(String.valueOf(next)); - persistIntPref(prefs, key, next); - }; - minus.setOnClickListener(listener); - plus.setOnClickListener(listener); - if (reset != null) { - reset.setOnClickListener(v -> { - int next = ViewTreeSupport.clamp(def, min, max); - input.setText(String.valueOf(next)); - persistIntPref(prefs, key, next); - }); - } - input.setOnFocusChangeListener((v, hasFocus) -> { - if (!hasFocus) { - int next = ViewTreeSupport.clamp(ViewTreeSupport.parseInt(input, def), min, max); - input.setText(String.valueOf(next)); - persistIntPref(prefs, key, next); - } - }); - return outer; - } - - private void persistIntPref(SharedPreferences prefs, String key, int value) { - prefs.edit().putInt(key, value).apply(); - SbtSettings.ensureReadable(requireContext()); - } - - private int iconContainerCount( - SharedPreferences prefs, - String countKey, - String legacyEnabledKey, - boolean legacyEnabledDefault - ) { - int fallback = prefs.getBoolean(legacyEnabledKey, legacyEnabledDefault) ? 1 : 0; - return SbtSettings.clampIconContainerCount(prefs.getInt(countKey, fallback)); - } - - private void persistIconContainerCount( - SharedPreferences prefs, - String countKey, - String legacyEnabledKey, - int count - ) { - int clamped = SbtSettings.clampIconContainerCount(count); - prefs.edit() - .putInt(countKey, clamped) - .putBoolean(legacyEnabledKey, clamped > 0) - .apply(); - SbtSettings.ensureReadable(requireContext()); + return ViewTreeSupport.intPreferenceStepper( + context, + prefs, + label, + key, + def, + min, + max, + true, + 4, + 6, + 0, + 0, + showDefaultButton, + false, + null); } private String sceneKey(String suffix) { @@ -922,23 +839,10 @@ abstract class LockedSceneLayoutFragment extends Fragment { return content instanceof LinearLayout layout ? layout : null; } - private View card(Context context, int titleId, View content) { - return ViewTreeSupport.outlinedCard(context, sectionTitle(context, titleId), content); - } - - private LinearLayout vertical(Context context) { - return ViewTreeSupport.verticalLayout(context); - } - - private TextView title(Context context, int text) { - return ViewTreeSupport.titleText(context, text); - } - - private TextView sectionTitle(Context context, int text) { - return ViewTreeSupport.sectionTitleText(context, text, false); - } - - private TextView body(Context context, int text) { - return ViewTreeSupport.bodyText(context, text, 6); + private View outlinedCard(Context context, int titleId, View content) { + return ViewTreeSupport.outlinedCard( + context, + ViewTreeSupport.sectionTitleText(context, titleId, false), + content); } } diff --git a/app/src/main/java/se/ajpanton/statusbartweak/shell/ui/ViewTreeSupport.java b/app/src/main/java/se/ajpanton/statusbartweak/shell/ui/ViewTreeSupport.java index b307f0b..6f8dad3 100644 --- a/app/src/main/java/se/ajpanton/statusbartweak/shell/ui/ViewTreeSupport.java +++ b/app/src/main/java/se/ajpanton/statusbartweak/shell/ui/ViewTreeSupport.java @@ -14,8 +14,9 @@ import android.widget.TextView; import com.google.android.material.button.MaterialButton; import com.google.android.material.card.MaterialCardView; -import se.ajpanton.statusbartweak.R; +import java.util.function.IntConsumer; +import se.ajpanton.statusbartweak.R; import se.ajpanton.statusbartweak.shell.settings.SbtSettings; final class ViewTreeSupport { @@ -149,6 +150,160 @@ final class ViewTreeSupport { return input; } + static int iconContainerCount( + SharedPreferences prefs, + String countKey, + String legacyEnabledKey, + int defaultCount, + boolean legacyEnabledDefault + ) { + int fallback = prefs.getBoolean(legacyEnabledKey, legacyEnabledDefault) ? defaultCount : 0; + return SbtSettings.clampIconContainerCount(prefs.getInt(countKey, fallback)); + } + + static void persistIconContainerCount( + Context context, + SharedPreferences prefs, + String countKey, + String legacyEnabledKey, + int count + ) { + int clamped = SbtSettings.clampIconContainerCount(count); + prefs.edit() + .putInt(countKey, clamped) + .putBoolean(legacyEnabledKey, clamped > 0) + .apply(); + SbtSettings.ensureReadable(context); + } + + static View iconContainerCountControl( + Context context, + int current, + IntConsumer countPersister, + Runnable onChanged + ) { + LinearLayout outer = verticalLayout(context); + outer.addView(bodyText(context, R.string.layout_icon_container_count, 0)); + LinearLayout row = new LinearLayout(context); + row.setOrientation(LinearLayout.HORIZONTAL); + row.setGravity(android.view.Gravity.CENTER_VERTICAL); + MaterialButton minus = outlinedStepperButton(context, "-"); + MaterialButton plus = outlinedStepperButton(context, "+"); + EditText input = numericInput(context, false, 1); + input.setText(String.valueOf(current)); + row.addView(minus, stepperButtonParams(context)); + row.addView(input, stepperInputParams(context)); + row.addView(plus, stepperButtonParams(context)); + outer.addView(row); + + View.OnClickListener listener = view -> { + int next = SbtSettings.clampIconContainerCount( + parseInt(input, current) + (view == minus ? -1 : 1)); + countPersister.accept(next); + onChanged.run(); + }; + minus.setOnClickListener(listener); + plus.setOnClickListener(listener); + input.setOnFocusChangeListener((v, hasFocus) -> { + if (!hasFocus) { + int next = SbtSettings.clampIconContainerCount(parseInt(input, current)); + countPersister.accept(next); + onChanged.run(); + } + }); + return outer; + } + + static View intPreferenceStepper( + Context context, + SharedPreferences prefs, + int labelRes, + String key, + int defaultValue, + int min, + int max, + boolean signed, + int inputMaxLength, + int labelBottomPaddingDp, + int rowTopPaddingDp, + int rowBottomPaddingDp, + boolean showDefaultButton, + boolean useCurrentAsParseFallback, + View trailingView + ) { + LinearLayout outer = verticalLayout(context); + outer.addView(bodyText(context, labelRes, labelBottomPaddingDp)); + + LinearLayout row = new LinearLayout(context); + row.setOrientation(LinearLayout.HORIZONTAL); + row.setGravity(android.view.Gravity.CENTER_VERTICAL); + row.setPadding(0, dp(context, rowTopPaddingDp), 0, dp(context, rowBottomPaddingDp)); + + MaterialButton minus = outlinedStepperButton(context, "-"); + MaterialButton plus = outlinedStepperButton(context, "+"); + MaterialButton reset = showDefaultButton ? outlinedStepperButton(context, "D") : null; + EditText input = numericInput(context, signed, inputMaxLength); + int current = clamp(prefs.getInt(key, defaultValue), min, max); + int parseFallback = useCurrentAsParseFallback ? current : defaultValue; + input.setText(String.valueOf(current)); + + row.addView(minus, stepperButtonParams(context)); + row.addView(input, stepperInputParams(context)); + row.addView(plus, stepperButtonParams(context)); + if (reset != null) { + LinearLayout.LayoutParams resetParams = stepperButtonParams(context); + resetParams.leftMargin = dp(context, 8); + row.addView(reset, resetParams); + } + if (trailingView != null) { + LinearLayout.LayoutParams trailingParams = new LinearLayout.LayoutParams( + ViewGroup.LayoutParams.WRAP_CONTENT, + ViewGroup.LayoutParams.WRAP_CONTENT); + trailingParams.leftMargin = dp(context, 8); + row.addView(trailingView, trailingParams); + } + outer.addView(row); + + View.OnClickListener listener = view -> { + int delta = view == minus ? -1 : 1; + int next = clamp(parseInt(input, parseFallback) + delta, min, max); + persistIntPreference(context, prefs, key, input, next); + }; + minus.setOnClickListener(listener); + plus.setOnClickListener(listener); + if (reset != null) { + reset.setOnClickListener(v -> persistIntPreference( + context, + prefs, + key, + input, + clamp(defaultValue, min, max))); + } + input.setOnFocusChangeListener((v, hasFocus) -> { + if (!hasFocus) { + int next = clamp(parseInt(input, parseFallback), min, max); + persistIntPreference(context, prefs, key, input, next); + } + }); + return outer; + } + + static void persistIntPreference( + Context context, + SharedPreferences prefs, + String key, + EditText input, + int value + ) { + input.setText(String.valueOf(value)); + persistIntPreference(context, prefs, key, value); + } + + static void persistIntPreference(Context context, SharedPreferences prefs, String key, int value) { + prefs.edit().putInt(key, value).apply(); + SbtSettings.ensureReadable(context); + } + static LinearLayout verticalLayout(Context context) { LinearLayout layout = new LinearLayout(context); layout.setOrientation(LinearLayout.VERTICAL); diff --git a/app/src/main/res/layout/fragment_layout.xml b/app/src/main/res/layout/fragment_layout.xml index 3eb607f..4b1a1c3 100644 --- a/app/src/main/res/layout/fragment_layout.xml +++ b/app/src/main/res/layout/fragment_layout.xml @@ -317,18 +317,10 @@ android:orientation="vertical" android:visibility="gone"> - - @@ -546,18 +538,10 @@ android:orientation="vertical" android:visibility="gone"> - - @@ -775,18 +759,10 @@ android:orientation="vertical" android:visibility="gone"> - - diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 98d68c9..ffb7baa 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -209,8 +209,6 @@ Right Middle Vertical position - If Middle overlaps the cutout, move it to the nearest side. - Else, or if the overlap is centred, move clock to: Left side Right side Custom format diff --git a/app/src/test/java/se/ajpanton/statusbartweak/ExampleUnitTest.java b/app/src/test/java/se/ajpanton/statusbartweak/ExampleUnitTest.java deleted file mode 100644 index 4a3ed77..0000000 --- a/app/src/test/java/se/ajpanton/statusbartweak/ExampleUnitTest.java +++ /dev/null @@ -1,17 +0,0 @@ -package se.ajpanton.statusbartweak; - -import org.junit.Test; - -import static org.junit.Assert.*; - -/** - * Example local unit test, which will execute on the development machine (host). - * - * @see Testing documentation - */ -public class ExampleUnitTest { - @Test - public void addition_isCorrect() { - assertEquals(4, 2 + 2); - } -} diff --git a/app/src/test/java/se/ajpanton/statusbartweak/runtime/render/UnlockedLayoutBandTest.java b/app/src/test/java/se/ajpanton/statusbartweak/runtime/render/UnlockedLayoutBandTest.java index ff2cafd..e3e8b52 100644 --- a/app/src/test/java/se/ajpanton/statusbartweak/runtime/render/UnlockedLayoutBandTest.java +++ b/app/src/test/java/se/ajpanton/statusbartweak/runtime/render/UnlockedLayoutBandTest.java @@ -21,9 +21,7 @@ public final class UnlockedLayoutBandTest { null, placements(6, 39, 39), LayoutPosition.LEFT, - false, - AnchorSide.LEFT, - true); + AnchorSide.LEFT); band.applyPackedIconState(0, 0, true, 14); band.place(388); @@ -54,9 +52,7 @@ public final class UnlockedLayoutBandTest { null, placements, LayoutPosition.LEFT, - false, - AnchorSide.LEFT, - true); + AnchorSide.LEFT); band.applyPackedIconState(2, 3, false, 117); @@ -86,9 +82,7 @@ public final class UnlockedLayoutBandTest { null, placements, LayoutPosition.LEFT, - false, - AnchorSide.LEFT, - false); + AnchorSide.LEFT); band.prepareForSide(AnchorSide.RIGHT, "normal"); band.applyPackedContinuousWidth(211, AnchorSide.RIGHT);