From 0e43cfe004aade582a35508aae0b7aa8f76bc07f Mon Sep 17 00:00:00 2001 From: ajp_anton Date: Wed, 13 May 2026 03:55:02 +0000 Subject: [PATCH] Start lockscreen statusbar layout --- .../layout/StockLayoutCanvasController.java | 66 +++-- .../layoutsolver/StatusBarLayoutSolver.java | 1 + .../runtime/render/ClockLayout.java | 44 +++- .../runtime/render/OwnedIconHostManager.java | 9 + .../runtime/render/SnapshotModels.java | 32 ++- .../UnlockedIconSnapshotRenderController.java | 65 ++++- .../runtime/render/UnlockedLayoutBand.java | 45 +++- .../runtime/render/UnlockedLayoutPlanner.java | 232 +++++++++++++++-- .../render/UnlockedStockSourceCollector.java | 47 +++- .../shell/settings/SbtDefaults.java | 7 +- .../shell/settings/SbtSettings.java | 242 ++++++++++++++++++ .../shell/settings/SbtSettingsProvider.java | 53 ++++ .../shell/ui/LayoutFragment.java | 14 +- .../shell/ui/LayoutOrderingUi.java | 10 +- .../shell/ui/LockedSceneLayoutFragment.java | 42 ++- app/src/main/res/values/strings.xml | 2 + 16 files changed, 841 insertions(+), 70 deletions(-) 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 526585d..61f06f1 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 @@ -187,7 +187,7 @@ final class StockLayoutCanvasController { if (!isUnlockedStatusBarRoot(root)) { return; } - if (activeScene != null && activeScene.isUnlocked()) { + if (activeScene != null && (activeScene.isUnlocked() || activeScene.isLockscreen())) { if (isKnownRootSizeChanged(root)) { ownedIconHostManager.setUnlockedHostsVisible(root, false); removeDebugOverlay(root); @@ -198,6 +198,7 @@ final class StockLayoutCanvasController { unlockedIconRenderController.refreshUnlockedAppearance( root, unlockedHosts.clockHost, + unlockedHosts.carrierHost, unlockedHosts.chipHost, unlockedHosts.statusHost, unlockedHosts.notificationHost, @@ -236,6 +237,22 @@ final class StockLayoutCanvasController { return; } UnlockedHosts unlockedHosts = updateUnlockedOwnedHosts(root, activeScene); + RenderResult renderResult = new RenderResult(false, false); + if (unlockedHosts != null && (unlockedScene || activeScene != null && activeScene.isLockscreen())) { + if (!unlockedScene) { + restoreTrackedLockedStatusBarIconSurfaces(root); + } + markRootSizeBeforeDraw(root); + renderResult = unlockedIconRenderController.renderUnlocked( + root, + unlockedHosts.clockHost, + unlockedHosts.carrierHost, + unlockedHosts.chipHost, + unlockedHosts.statusHost, + unlockedHosts.notificationHost, + activeScene); + ownedIconHostManager.setUnlockedHostsVisible(root, true); + } if (!unlockedScene) { trackedUnlockedStockSurfaces.clear(); restoreTransientUnlockedSources(); @@ -243,18 +260,6 @@ final class StockLayoutCanvasController { removeDebugOverlay(root); return; } - RenderResult renderResult = new RenderResult(false, false); - if (unlockedHosts != null) { - markRootSizeBeforeDraw(root); - renderResult = unlockedIconRenderController.renderUnlocked( - root, - unlockedHosts.clockHost, - unlockedHosts.chipHost, - unlockedHosts.statusHost, - unlockedHosts.notificationHost, - activeScene); - ownedIconHostManager.setUnlockedHostsVisible(root, true); - } boolean scanTree = renderResult.stockSourcesChanged() || !hasTrackedUnlockedStockSurfaces(root); applyDebugOverlayIfNeeded(root, true, settings, renderResult.layoutChanged()); hideTrackedStatusChipSources(root); @@ -417,7 +422,7 @@ final class StockLayoutCanvasController { walkTree(root, view -> { if (isLockedStatusBarIconSurface(view)) { trackedLockedStatusBarIconSurfaces.add(view); - hideView(view); + hideView(view, isCarrierView(view)); } }); } @@ -442,7 +447,7 @@ final class StockLayoutCanvasController { } if (root == null || isDescendantOf(view, root)) { foundInRoot = true; - hideView(view); + hideView(view, isCarrierView(view)); } } while (!staleViews.isEmpty()) { @@ -451,6 +456,17 @@ final class StockLayoutCanvasController { return foundInRoot; } + private void restoreTrackedLockedStatusBarIconSurfaces(View root) { + if (trackedLockedStatusBarIconSurfaces.isEmpty()) { + return; + } + for (View view : trackedLockedStatusBarIconSurfaces) { + if (view != null && view.isAttachedToWindow() && (root == null || isDescendantOf(view, root))) { + restoreView(view); + } + } + } + private boolean hasTrackedStatusChipSources(View root) { if (trackedStatusChipSources.isEmpty()) { return false; @@ -499,6 +515,7 @@ final class StockLayoutCanvasController { || "keyguard_icononly_container_view".equals(idName) || "common_notification_widget".equals(idName); if (!("system_icons".equals(idName) + || idName.toLowerCase(java.util.Locale.ROOT).contains("carrier") || "system_icon_area".equals(idName) || "statusIcons".equals(idName) || "battery".equals(idName) @@ -531,6 +548,15 @@ final class StockLayoutCanvasController { return false; } + private boolean isCarrierView(View view) { + if (view == null) { + return false; + } + String idName = resolveIdName(view).toLowerCase(java.util.Locale.ROOT); + String className = view.getClass().getName().toLowerCase(java.util.Locale.ROOT); + return idName.contains("carrier") || className.contains("carrier"); + } + private boolean canContainLockedStatusBarIconSurfaces(View root) { if (root == null) { return false; @@ -557,6 +583,9 @@ final class StockLayoutCanvasController { return true; } String className = view.getClass().getName(); + if (className.toLowerCase(java.util.Locale.ROOT).contains("carrier")) { + return true; + } if (className.contains("NotificationShelf")) { return true; } @@ -784,12 +813,14 @@ final class StockLayoutCanvasController { View statusHost = ownedIconHostManager.ensureUnlockedStatusHost(root); View notificationHost = ownedIconHostManager.ensureUnlockedNotificationHost(root); View clockHost = ownedIconHostManager.ensureUnlockedClockHost(root); + View carrierHost = ownedIconHostManager.ensureUnlockedCarrierHost(root); View chipHost = ownedIconHostManager.ensureUnlockedChipHost(root); if (statusHost instanceof ViewGroup statusGroup && notificationHost instanceof ViewGroup notificationGroup && clockHost instanceof ViewGroup clockGroup + && carrierHost instanceof ViewGroup carrierGroup && chipHost instanceof ViewGroup chipGroup) { - UnlockedHosts hosts = new UnlockedHosts(clockGroup, chipGroup, statusGroup, notificationGroup); + UnlockedHosts hosts = new UnlockedHosts(clockGroup, carrierGroup, chipGroup, statusGroup, notificationGroup); unlockedHostsByRoot.put(root, hosts); return hosts; } @@ -805,6 +836,7 @@ final class StockLayoutCanvasController { private boolean areUnlockedHostsAttached(View root, UnlockedHosts hosts) { return hosts != null && hosts.clockHost.getParent() == root + && hosts.carrierHost.getParent() == root && hosts.chipHost.getParent() == root && hosts.statusHost.getParent() == root && hosts.notificationHost.getParent() == root; @@ -816,6 +848,7 @@ final class StockLayoutCanvasController { } String className = root.getClass().getName(); return className.contains("PhoneStatusBarView") + || className.contains("KeyguardStatusBarView") || className.contains("StatusBarWindowView"); } @@ -902,6 +935,7 @@ final class StockLayoutCanvasController { private record UnlockedHosts( ViewGroup clockHost, + ViewGroup carrierHost, ViewGroup chipHost, ViewGroup statusHost, ViewGroup notificationHost 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 b38ba97..65fc979 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 @@ -664,6 +664,7 @@ public final class StatusBarLayoutSolver { } public enum LayoutItemKind { + CARRIER, CLOCK, CHIP, NOTIFICATIONS, diff --git a/app/src/main/java/se/ajpanton/statusbartweak/runtime/render/ClockLayout.java b/app/src/main/java/se/ajpanton/statusbartweak/runtime/render/ClockLayout.java index 7cf4a91..f986bc4 100644 --- a/app/src/main/java/se/ajpanton/statusbartweak/runtime/render/ClockLayout.java +++ b/app/src/main/java/se/ajpanton/statusbartweak/runtime/render/ClockLayout.java @@ -124,6 +124,47 @@ final class ClockLayout { bounds.height); } + static ClockLayout simpleText( + TextView source, + LayoutPosition position, + int sourceBaselineY + ) { + if (source == null || source.getText() == null || source.getText().length() == 0) { + return null; + } + TextView probe = new TextView(source.getContext()); + probe.setLayoutParams(new ViewGroup.LayoutParams( + ViewGroup.LayoutParams.WRAP_CONTENT, + ViewGroup.LayoutParams.WRAP_CONTENT)); + ClockProxyRenderer.copyTextStyleIfChanged(source, probe); + MeasuredText measured = measureText(probe, source.getText()); + if (measured.width <= 0 || measured.height <= 0) { + return null; + } + int top = sourceBaselineY - measured.baseline; + ClockRow row = new ClockRow( + source.getText(), + 0, + 0, + measured.width, + measured.height, + 0, + 0, + ClockRowSegment.FULL); + ArrayList rows = new ArrayList<>(); + rows.add(row); + return new ClockLayout( + source, + null, + rows, + new ArrayList<>(), + top, + 0, + false, + measured.width, + measured.height); + } + private static ArrayList positionRowsFromBaseline( ArrayList measuredRows, int sourceBaselineY, @@ -426,7 +467,8 @@ final class ClockLayout { } ClockPlacement placement() { - return new ClockPlacement(source, model.contentDescription, rows, new Bounds(placedLeft, top, width, height)); + String description = model != null ? model.contentDescription : String.valueOf(source.getText()); + return new ClockPlacement(source, description, rows, new Bounds(placedLeft, top, width, height)); } private record MeasuredClockRow( diff --git a/app/src/main/java/se/ajpanton/statusbartweak/runtime/render/OwnedIconHostManager.java b/app/src/main/java/se/ajpanton/statusbartweak/runtime/render/OwnedIconHostManager.java index 8262b0f..a6ddbac 100644 --- a/app/src/main/java/se/ajpanton/statusbartweak/runtime/render/OwnedIconHostManager.java +++ b/app/src/main/java/se/ajpanton/statusbartweak/runtime/render/OwnedIconHostManager.java @@ -20,6 +20,8 @@ public final class OwnedIconHostManager { "statusbartweak.unlocked.notification.host"; public static final String TAG_UNLOCKED_CLOCK_HOST = "statusbartweak.unlocked.clock.host"; + public static final String TAG_UNLOCKED_CARRIER_HOST = + "statusbartweak.unlocked.carrier.host"; public static final String TAG_UNLOCKED_CHIP_HOST = "statusbartweak.unlocked.chip.host"; @@ -39,6 +41,10 @@ public final class OwnedIconHostManager { return ensureHost(root, TAG_UNLOCKED_CLOCK_HOST); } + public FrameLayout ensureUnlockedCarrierHost(View root) { + return ensureHost(root, TAG_UNLOCKED_CARRIER_HOST); + } + public FrameLayout ensureHost(View root, String tag) { Objects.requireNonNull(tag, "tag"); if (!(root instanceof ViewGroup parent)) { @@ -77,6 +83,7 @@ public final class OwnedIconHostManager { removeHost(root, TAG_UNLOCKED_STATUS_HOST); removeHost(root, TAG_UNLOCKED_NOTIFICATION_HOST); removeHost(root, TAG_UNLOCKED_CLOCK_HOST); + removeHost(root, TAG_UNLOCKED_CARRIER_HOST); removeHost(root, TAG_UNLOCKED_CHIP_HOST); } @@ -84,6 +91,7 @@ public final class OwnedIconHostManager { setHostVisible(root, TAG_UNLOCKED_STATUS_HOST, visible); setHostVisible(root, TAG_UNLOCKED_NOTIFICATION_HOST, visible); setHostVisible(root, TAG_UNLOCKED_CLOCK_HOST, visible); + setHostVisible(root, TAG_UNLOCKED_CARRIER_HOST, visible); setHostVisible(root, TAG_UNLOCKED_CHIP_HOST, visible); } @@ -95,6 +103,7 @@ public final class OwnedIconHostManager { return TAG_UNLOCKED_STATUS_HOST.equals(tag) || TAG_UNLOCKED_NOTIFICATION_HOST.equals(tag) || TAG_UNLOCKED_CLOCK_HOST.equals(tag) + || TAG_UNLOCKED_CARRIER_HOST.equals(tag) || TAG_UNLOCKED_CHIP_HOST.equals(tag); } 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 f8d5f5e..42c85c6 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 @@ -167,6 +167,7 @@ final class RootAnchors { final View statusIcons; final View battery; final View notificationRoot; + final TextView carrierView; RootAnchors( View clockContainer, @@ -175,7 +176,8 @@ final class RootAnchors { View statusEndContent, View statusIcons, View battery, - View notificationRoot + View notificationRoot, + TextView carrierView ) { this.clockContainer = clockContainer; this.clockView = clockView; @@ -184,6 +186,7 @@ final class RootAnchors { this.statusIcons = statusIcons; this.battery = battery; this.notificationRoot = notificationRoot; + this.carrierView = carrierView; } boolean isUsable() { @@ -204,19 +207,22 @@ final class CollectedIcons { final ArrayList notificationIcons; final ArrayList statusChips; final ArrayList statusChipMetrics; + final TextView carrierView; CollectedIcons( TextView clockView, ArrayList statusIcons, ArrayList notificationIcons, ArrayList statusChips, - ArrayList statusChipMetrics + ArrayList statusChipMetrics, + TextView carrierView ) { this.clockView = clockView; this.statusIcons = statusIcons; this.notificationIcons = notificationIcons; this.statusChips = statusChips; this.statusChipMetrics = statusChipMetrics; + this.carrierView = carrierView; } } @@ -239,6 +245,7 @@ final class LayoutInputSignature { final int statusIcons; final int battery; final int notificationRoot; + final int carrierView; final int statusSources; final int notificationSources; final int chipSources; @@ -262,6 +269,7 @@ final class LayoutInputSignature { int statusIcons, int battery, int notificationRoot, + int carrierView, int statusSources, int notificationSources, int chipSources @@ -284,6 +292,7 @@ final class LayoutInputSignature { this.statusIcons = statusIcons; this.battery = battery; this.notificationRoot = notificationRoot; + this.carrierView = carrierView; this.statusSources = statusSources; this.notificationSources = notificationSources; this.chipSources = chipSources; @@ -301,6 +310,7 @@ final class LayoutInputSignature { statusIcons, battery, notificationRoot, + carrierView, statusSources, notificationSources); } @@ -322,6 +332,7 @@ final class LayoutInputSignature { statusIcons, battery, notificationRoot, + carrierView, statusSources, notificationSources, chipSources); @@ -352,6 +363,7 @@ final class LayoutInputSignature { && statusIcons == that.statusIcons && battery == that.battery && notificationRoot == that.notificationRoot + && carrierView == that.carrierView && statusSources == that.statusSources && notificationSources == that.notificationSources && chipSources == that.chipSources @@ -379,6 +391,7 @@ final class LayoutInputSignature { statusIcons, battery, notificationRoot, + carrierView, statusSources, notificationSources, chipSources); @@ -390,17 +403,29 @@ final class LayoutPlan { final ArrayList chipPlacements; final ArrayList statusPlacements; 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, + ArrayList statusPlacements, + ArrayList notificationPlacements, + ClockPlacement carrierPlacement ) { this.clockPlacement = clockPlacement; this.chipPlacements = chipPlacements; this.statusPlacements = statusPlacements; this.notificationPlacements = notificationPlacements; + this.carrierPlacement = carrierPlacement; } LayoutPlan withClockPlacement(ClockPlacement placement) { @@ -408,6 +433,7 @@ final class LayoutPlan { placement, chipPlacements, statusPlacements, - notificationPlacements); + notificationPlacements, + carrierPlacement); } } 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 53dfd23..c9a9eb8 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 @@ -24,6 +24,7 @@ public final class UnlockedIconSnapshotRenderController { private final SnapshotRenderer notificationRenderer; private final SnapshotRenderer chipRenderer; private final ClockProxyRenderer clockRenderer = new ClockProxyRenderer(); + private final ClockProxyRenderer carrierRenderer = new ClockProxyRenderer(); private final UnlockedStockSourceCollector sourceCollector = new UnlockedStockSourceCollector(); private final UnlockedVerticalOffsetScaler offsetScaler = new UnlockedVerticalOffsetScaler(); private final UnlockedChipPlacementController chipPlacementController; @@ -52,17 +53,19 @@ public final class UnlockedIconSnapshotRenderController { public RenderResult renderUnlocked( View root, ViewGroup clockHost, + ViewGroup carrierHost, ViewGroup chipHost, ViewGroup statusHost, ViewGroup notificationHost, SceneKey scene ) { - if (scene == null || !scene.isUnlocked() || !root.isAttachedToWindow()) { + if (scene == null || (!scene.isUnlocked() && !scene.isLockscreen()) || !root.isAttachedToWindow()) { clearAll(); return new RenderResult(true, true); } SbtSettings settings = RuntimeSettingsCache.get(root.getContext()); layoutHostToRoot(root, clockHost); + layoutHostToRoot(root, carrierHost); layoutHostToRoot(root, chipHost); layoutHostToRoot(root, statusHost); layoutHostToRoot(root, notificationHost); @@ -89,6 +92,7 @@ public final class UnlockedIconSnapshotRenderController { ClockLayout currentClockLayout = null; Integer currentClockGeometry = null; if (isClockOnlySignatureChange(previousSignature, signature) + && scene.isUnlocked() && settings.clockEnabledUnlocked && previousIcons != null) { LayoutPlan previousPlan = lastLayoutPlanByRoot.get(root); @@ -144,7 +148,7 @@ public final class UnlockedIconSnapshotRenderController { collectedIcons = sourceCollector.collectChips(root, anchors, collectedIcons); lastCollectedIconsByRoot.put(root, collectedIcons); } - if (currentClockLayout == null && settings.clockEnabledUnlocked) { + if (currentClockLayout == null && clockEnabledForScene(settings, scene)) { currentClockLayout = buildClockLayout(root, anchors, settings); currentClockGeometry = clockGeometrySignature( root, @@ -155,34 +159,41 @@ public final class UnlockedIconSnapshotRenderController { LayoutPlan layoutPlan = layoutPlanner.solve( root, clockHost, + carrierHost, chipHost, statusHost, notificationHost, anchors, collectedIcons, settings, - currentClockLayout); + currentClockLayout, + scene); lastLayoutPlanByRoot.put(root, layoutPlan); lastClockGeometryByRoot.put(root, currentClockGeometry != null ? currentClockGeometry : 0); lastClockSourceGeometryByRoot.put(root, currentClockSourceGeometry); layoutPlan = withCurrentDotColors(layoutPlan, collectedIcons); lastLayoutPlanByRoot.put(root, layoutPlan); - if (settings.clockEnabledUnlocked && layoutPlan.clockPlacement != null) { + if (clockEnabledForScene(settings, scene) && layoutPlan.clockPlacement != null) { clockRenderer.render(clockHost, layoutPlan.clockPlacement); } else { clockRenderer.clear(clockHost); } - if (settings.layoutChipEnabledUnlocked && layoutPlan.chipPlacements != null) { + if (scene.isLockscreen() && settings.layoutCarrierEnabledLockscreen && layoutPlan.carrierPlacement != null) { + carrierRenderer.render(carrierHost, layoutPlan.carrierPlacement); + } else { + carrierRenderer.clear(carrierHost); + } + if (scene.isUnlocked() && settings.layoutChipEnabledUnlocked && layoutPlan.chipPlacements != null) { chipRenderer.renderPlacements(chipHost, layoutPlan.chipPlacements); } else { chipRenderer.clear(chipHost); } - if (settings.layoutStatusEnabledUnlocked && layoutPlan.statusPlacements != null) { + if (statusEnabledForScene(settings, scene) && layoutPlan.statusPlacements != null) { statusRenderer.renderPlacements(statusHost, layoutPlan.statusPlacements); } else { statusRenderer.clear(statusHost); } - if (settings.layoutNotifEnabledUnlocked && layoutPlan.notificationPlacements != null) { + if (notificationsEnabledForScene(settings, scene) && layoutPlan.notificationPlacements != null) { notificationRenderer.renderPlacements(notificationHost, layoutPlan.notificationPlacements); } else { notificationRenderer.clear(notificationHost); @@ -193,6 +204,7 @@ public final class UnlockedIconSnapshotRenderController { public void refreshUnlockedAppearance( View root, ViewGroup clockHost, + ViewGroup carrierHost, ViewGroup chipHost, ViewGroup statusHost, ViewGroup notificationHost, @@ -249,6 +261,41 @@ public final class UnlockedIconSnapshotRenderController { host.layout(0, 0, root.getWidth(), root.getHeight()); } + private boolean clockEnabledForScene(SbtSettings settings, SceneKey scene) { + if (settings == null || scene == null) { + return false; + } + if (scene.isUnlocked()) { + return settings.clockEnabledUnlocked; + } + if (scene.isLockscreen()) { + return settings.clockEnabledLockscreen; + } + return false; + } + + private boolean statusEnabledForScene(SbtSettings settings, SceneKey scene) { + if (settings == null || scene == null) { + return false; + } + return scene.isLockscreen() + ? settings.layoutStatusEnabledLockscreen + : settings.layoutStatusEnabledUnlocked; + } + + private boolean notificationsEnabledForScene(SbtSettings settings, SceneKey scene) { + if (settings == null || scene == null) { + return false; + } + if (scene.isLockscreen()) { + return settings.layoutNotifEnabledLockscreen + && !"none".equals(settings.lockedNotificationMode) + && scene.notificationDisplayStyle() != se.ajpanton.statusbartweak.runtime.mode.NotificationDisplayStyle.NONE + && scene.notificationDisplayStyle() != se.ajpanton.statusbartweak.runtime.mode.NotificationDisplayStyle.CARDS; + } + return settings.layoutNotifEnabledUnlocked; + } + private LayoutPlan withCurrentDotColors(LayoutPlan plan, CollectedIcons icons) { if (plan == null) { return null; @@ -266,7 +313,8 @@ public final class UnlockedIconSnapshotRenderController { plan.clockPlacement, plan.chipPlacements, status, - notifications); + notifications, + plan.carrierPlacement); } private ArrayList withCurrentDotColors( @@ -425,6 +473,7 @@ public final class UnlockedIconSnapshotRenderController { public void clearAll() { clockRenderer.clearAll(); + carrierRenderer.clearAll(); statusRenderer.clearAll(); statusRenderer.clearHeldSignals(); notificationRenderer.clearAll(); 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 1b6b3c5..42268c4 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 @@ -89,6 +89,27 @@ final class UnlockedLayoutBand extends StatusBarLayoutSolver.LayoutBand { splitRegion); } + static UnlockedLayoutBand carrier( + ViewGroup host, + ClockLayout carrierLayout, + LayoutPosition position, + boolean middleAutoNearestSide, + AnchorSide middleSide + ) { + return new UnlockedLayoutBand( + LayoutItemKind.CARRIER, + host, + null, + null, + position, + middleAutoNearestSide, + middleSide, + false, + null, + carrierLayout, + SplitRegion.NONE); + } + static UnlockedLayoutBand icons( LayoutItemKind kind, ViewGroup host, @@ -115,7 +136,7 @@ final class UnlockedLayoutBand extends StatusBarLayoutSolver.LayoutBand { @Override protected void prepareForSide(AnchorSide side, String sortOrder) { - if (kind == LayoutItemKind.CLOCK) { + if (isTextKind()) { placements = null; placedBounds = clockLayout != null ? clockLayout.bounds() : reservedBounds; return; @@ -134,7 +155,7 @@ final class UnlockedLayoutBand extends StatusBarLayoutSolver.LayoutBand { } int naturalWidth() { - if (kind == LayoutItemKind.CLOCK) { + if (isTextKind()) { if (clockLayout != null) { return clockLayout.width(); } @@ -145,7 +166,7 @@ final class UnlockedLayoutBand extends StatusBarLayoutSolver.LayoutBand { @Override protected boolean canClipContinuously() { - return (kind == LayoutItemKind.CHIP || kind == LayoutItemKind.CLOCK) + return (kind == LayoutItemKind.CHIP || isTextKind()) && naturalWidth() > clipStartPx + clipEndPx; } @@ -202,7 +223,7 @@ final class UnlockedLayoutBand extends StatusBarLayoutSolver.LayoutBand { } int height() { - if (kind == LayoutItemKind.CLOCK) { + if (isTextKind()) { if (clockLayout != null) { return clockLayout.height(); } @@ -216,7 +237,7 @@ final class UnlockedLayoutBand extends StatusBarLayoutSolver.LayoutBand { } int top() { - if (kind == LayoutItemKind.CLOCK) { + if (isTextKind()) { if (clockLayout != null) { return clockLayout.top(); } @@ -306,7 +327,7 @@ final class UnlockedLayoutBand extends StatusBarLayoutSolver.LayoutBand { @Override protected void place(int left) { - if (kind == LayoutItemKind.CLOCK) { + if (isTextKind()) { placedBounds = clockLayout != null ? clockLayout.place(left) : new Bounds(left, top(), width(), height()); @@ -356,7 +377,7 @@ final class UnlockedLayoutBand extends StatusBarLayoutSolver.LayoutBand { } Bounds bounds() { - if (kind == LayoutItemKind.CLOCK) { + if (isTextKind()) { return placedBounds; } Bounds union = null; @@ -373,7 +394,7 @@ final class UnlockedLayoutBand extends StatusBarLayoutSolver.LayoutBand { @Override protected ArrayList collisionBoxes() { ArrayList boxes = new ArrayList<>(); - if (kind == LayoutItemKind.CLOCK) { + if (isTextKind()) { if (clockLayout != null) { int clipLeft = clipStartPx; int clipRight = naturalWidth() - clipEndPx; @@ -399,7 +420,7 @@ final class UnlockedLayoutBand extends StatusBarLayoutSolver.LayoutBand { @Override protected ArrayList placedCollisionBounds() { ArrayList boxes = new ArrayList<>(); - int left = kind == LayoutItemKind.CLOCK && placedBounds != null + int left = isTextKind() && placedBounds != null ? placedBounds.left : 0; for (Bounds box : collisionBoxes()) { @@ -413,7 +434,7 @@ final class UnlockedLayoutBand extends StatusBarLayoutSolver.LayoutBand { } private SnapshotPlacement wallPlacement(AnchorSide side) { - if (kind == LayoutItemKind.CLOCK) { + if (isTextKind()) { return null; } ArrayList icons = activePlacements(); @@ -738,6 +759,10 @@ final class UnlockedLayoutBand extends StatusBarLayoutSolver.LayoutBand { new Bounds(clipLeft, placement.bounds.top, Math.max(0, clipRight - clipLeft), placement.bounds.height)); } + private boolean isTextKind() { + return kind == LayoutItemKind.CLOCK || kind == LayoutItemKind.CARRIER; + } + private static AnchorSide sideFor(String value) { return "right".equals(value) ? AnchorSide.RIGHT : AnchorSide.LEFT; } 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 3f49832..2a69b53 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 @@ -17,6 +17,8 @@ import se.ajpanton.statusbartweak.runtime.layoutsolver.StatusBarLayoutSolver.Lay 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.shell.settings.SbtSettings; final class UnlockedLayoutPlanner { @@ -43,26 +45,37 @@ final class UnlockedLayoutPlanner { LayoutPlan solve( View root, ViewGroup clockHost, + ViewGroup carrierHost, ViewGroup chipHost, ViewGroup statusHost, ViewGroup notificationHost, RootAnchors anchors, CollectedIcons collectedIcons, SbtSettings settings, - ClockLayout clockLayout + ClockLayout clockLayout, + SceneKey scene ) { ArrayList bands = new ArrayList<>(); Rect cutout = ViewGeometry.middleCutout(root); Bounds layoutCutoutBounds = cutoutBounds(cutout, settings.layoutPaddingCutoutPx); Bounds clockCutoutBounds = cutoutBounds(cutout, settings.clockMiddleCutoutGapPx); - if (settings.clockEnabledUnlocked && clockLayout != null && clockLayout.width() > 0) { + if (clockEnabledForScene(settings, scene) && clockLayout != null && clockLayout.width() > 0) { bands.add(UnlockedLayoutBand.clock( clockHost, clockLayout, positionFor(settings.clockPosition), settings)); } - if (settings.layoutChipEnabledUnlocked) { + ClockLayout carrierLayout = carrierLayout(root, collectedIcons, settings, scene); + if (carrierLayout != null && carrierLayout.width() > 0) { + bands.add(UnlockedLayoutBand.carrier( + carrierHost, + carrierLayout, + positionFor(settings.layoutCarrierPosition), + settings.layoutCarrierMiddleAutoNearestSide, + sideFor(settings.layoutCarrierMiddleSide))); + } + if (scene != null && scene.isUnlocked() && settings.layoutChipEnabledUnlocked) { ArrayList placements = chipPlacementController.placements( root, collectedIcons.statusChips, @@ -80,16 +93,21 @@ final class UnlockedLayoutPlanner { false)); } } - if (settings.layoutStatusUnlockedCount > 0) { + int statusCount = statusCountForScene(settings, scene); + if (statusCount > 0) { ArrayList rawPlacements = statusRenderer.rawPlacements(root, collectedIcons.statusIcons); int representativeHeight = representativeHeight(rawPlacements); - for (int i = 0; i < settings.layoutStatusUnlockedCount; i++) { + String[] positions = statusPositionsForScene(settings, scene); + String[] middleSides = statusMiddleSidesForScene(settings, scene); + boolean[] autoNearest = statusAutoNearestForScene(settings, scene); + int[] verticalOffsets = statusVerticalOffsetsForScene(settings, scene); + for (int i = 0; i < statusCount; i++) { ArrayList placements = offsetPlacements( rawPlacements, offsetScaler.status( - intAt(settings.layoutStatusVerticalOffsetsPx, i, settings.layoutStatusVerticalOffsetPx), + intAt(verticalOffsets, i, settings.layoutStatusVerticalOffsetPx), representativeHeight)); if (!placements.isEmpty()) { bands.add(UnlockedLayoutBand.icons( @@ -97,26 +115,37 @@ final class UnlockedLayoutPlanner { statusHost, statusRenderer, placements, - positionFor(stringAt(settings.layoutStatusPositions, i, settings.layoutStatusPosition)), + positionFor(stringAt(positions, i, settings.layoutStatusPosition)), booleanAt( - settings.layoutStatusMiddleAutoNearestSides, + autoNearest, i, settings.layoutStatusMiddleAutoNearestSide), - sideFor(stringAt(settings.layoutStatusMiddleSides, i, settings.layoutStatusMiddleSide)), + sideFor(stringAt(middleSides, i, settings.layoutStatusMiddleSide)), true)); } } } - if (settings.layoutNotifUnlockedCount > 0) { + int notificationCount = notificationCountForScene(settings, scene); + if (notificationCount > 0) { ArrayList rawPlacements = notificationRenderer.rawPlacements(root, collectedIcons.notificationIcons); + if (scene != null + && scene.isLockscreen() + && scene.notificationDisplayStyle() == NotificationDisplayStyle.DOT) { + rawPlacements = dotOnlyPlacements(rawPlacements); + notificationCount = rawPlacements.isEmpty() ? 0 : 1; + } int representativeHeight = representativeHeight(rawPlacements); - for (int i = 0; i < settings.layoutNotifUnlockedCount; i++) { + String[] positions = notificationPositionsForScene(settings, scene); + String[] middleSides = notificationMiddleSidesForScene(settings, scene); + boolean[] autoNearest = notificationAutoNearestForScene(settings, scene); + int[] verticalOffsets = notificationVerticalOffsetsForScene(settings, scene); + for (int i = 0; i < notificationCount; i++) { ArrayList placements = offsetPlacements( rawPlacements, offsetScaler.notification( - intAt(settings.layoutNotifVerticalOffsetsPx, i, settings.layoutNotifVerticalOffsetPx), + intAt(verticalOffsets, i, settings.layoutNotifVerticalOffsetPx), representativeHeight)); if (!placements.isEmpty()) { bands.add(UnlockedLayoutBand.icons( @@ -124,12 +153,12 @@ final class UnlockedLayoutPlanner { notificationHost, notificationRenderer, placements, - positionFor(stringAt(settings.layoutNotifPositions, i, settings.layoutNotifPosition)), + positionFor(stringAt(positions, i, settings.layoutNotifPosition)), booleanAt( - settings.layoutNotifMiddleAutoNearestSides, + autoNearest, i, settings.layoutNotifMiddleAutoNearestSide), - sideFor(stringAt(settings.layoutNotifMiddleSides, i, settings.layoutNotifMiddleSide)), + sideFor(stringAt(middleSides, i, settings.layoutNotifMiddleSide)), true)); } } @@ -147,9 +176,12 @@ final class UnlockedLayoutPlanner { ArrayList notificationPlacements = new ArrayList<>(); ArrayList chipPlacements = new ArrayList<>(); ArrayList clockPlacements = new ArrayList<>(); + ClockPlacement carrierPlacement = null; for (UnlockedLayoutBand band : bands) { if (band.kind == LayoutItemKind.CLOCK && band.clockLayout != null) { clockPlacements.add(band.clockPlacement()); + } else if (band.kind == LayoutItemKind.CARRIER && band.clockLayout != null) { + carrierPlacement = band.clockPlacement(); } else if (band.kind == LayoutItemKind.CHIP && band.placements != null) { chipPlacements.addAll(band.placements); } else if (band.kind == LayoutItemKind.STATUS && band.placements != null) { @@ -162,7 +194,8 @@ final class UnlockedLayoutPlanner { mergeClockPlacements(clockPlacements), chipPlacements, statusPlacements, - notificationPlacements); + notificationPlacements, + carrierPlacement); } private void solveWithPackedLayout( @@ -200,13 +233,16 @@ final class UnlockedLayoutPlanner { for (int i = 0; i < items.size(); i++) { UnlockedLayoutBand band = itemBands.get(i); PackedStatusBarLayoutSolver.LayoutItem item = items.get(i); - if (band.kind == LayoutItemKind.NOTIFICATIONS || band.kind == LayoutItemKind.STATUS) { + if ((band.kind == LayoutItemKind.NOTIFICATIONS || band.kind == LayoutItemKind.STATUS) + && item.iconGroup != null) { band.applyPackedIconState( item.firstVisibleIconIndex, item.visibleIcons, item.dot, Math.round((float) item.width())); - } else if (band.kind == LayoutItemKind.CHIP || band.kind == LayoutItemKind.CLOCK) { + } else if (band.kind == LayoutItemKind.CHIP + || band.kind == LayoutItemKind.CLOCK + || band.kind == LayoutItemKind.CARRIER) { band.applyPackedContinuousWidth(Math.round((float) item.width()), packedAnchorSide(band)); } band.place(Math.round((float) item.x)); @@ -262,7 +298,8 @@ final class UnlockedLayoutPlanner { packedPosition(band.position), packedFallback(band), boxes); - if (band.kind == LayoutItemKind.NOTIFICATIONS || band.kind == LayoutItemKind.STATUS) { + if ((band.kind == LayoutItemKind.NOTIFICATIONS || band.kind == LayoutItemKind.STATUS) + && !isFixedDotBand(band)) { item.iconGroup = packedKind(band.kind).toLowerCase(java.util.Locale.ROOT); item.iconCount = band.rawPlacements != null ? band.rawPlacements.size() : 0; item.visibleIcons = item.iconCount; @@ -371,6 +408,7 @@ final class UnlockedLayoutPlanner { ArrayList order = new ArrayList<>(); order.add("Notifs"); order.add("Status"); + order.add("Carrier"); order.add("Chip"); order.add("Clock"); return order; @@ -390,6 +428,9 @@ final class UnlockedLayoutPlanner { if (kind == LayoutItemKind.CHIP) { return "Chip"; } + if (kind == LayoutItemKind.CARRIER) { + return "Carrier"; + } return "Clock"; } @@ -425,6 +466,153 @@ final class UnlockedLayoutPlanner { return band.middleSide; } + private boolean clockEnabledForScene(SbtSettings settings, SceneKey scene) { + if (settings == null || scene == null) { + return false; + } + if (scene.isUnlocked()) { + return settings.clockEnabledUnlocked; + } + if (scene.isLockscreen()) { + return settings.clockEnabledLockscreen; + } + return false; + } + + private ClockLayout carrierLayout( + View root, + CollectedIcons collectedIcons, + SbtSettings settings, + SceneKey scene + ) { + if (root == null + || collectedIcons == null + || collectedIcons.carrierView == null + || settings == null + || scene == null + || !scene.isLockscreen() + || !settings.layoutCarrierEnabledLockscreen) { + return null; + } + Bounds bounds = ViewGeometry.boundsRelativeTo(root, collectedIcons.carrierView); + if (bounds == null || bounds.width <= 0 || bounds.height <= 0) { + return null; + } + int baseline = collectedIcons.carrierView.getBaseline() > 0 + ? collectedIcons.carrierView.getBaseline() + : Math.max(0, (bounds.height * 3) / 4); + int verticalOffset = offsetScaler.clock( + settings.layoutCarrierVerticalOffsetPx, + collectedIcons.carrierView); + return ClockLayout.simpleText( + collectedIcons.carrierView, + positionFor(settings.layoutCarrierPosition), + bounds.top + baseline - verticalOffset); + } + + private int statusCountForScene(SbtSettings settings, SceneKey scene) { + if (scene != null && scene.isLockscreen()) { + return settings.layoutStatusEnabledLockscreen ? settings.layoutStatusLockCount : 0; + } + return settings.layoutStatusUnlockedCount; + } + + private int notificationCountForScene(SbtSettings settings, SceneKey scene) { + if (scene != null && scene.isLockscreen()) { + if ("none".equals(settings.lockedNotificationMode)) { + return 0; + } + NotificationDisplayStyle style = scene.notificationDisplayStyle(); + if (style == NotificationDisplayStyle.NONE || style == NotificationDisplayStyle.CARDS) { + return 0; + } + if (style == NotificationDisplayStyle.DOT) { + return settings.layoutNotifEnabledLockscreen ? 1 : 0; + } + return settings.layoutNotifEnabledLockscreen ? settings.layoutNotifLockCount : 0; + } + return settings.layoutNotifUnlockedCount; + } + + private String[] statusPositionsForScene(SbtSettings settings, SceneKey scene) { + return scene != null && scene.isLockscreen() + ? settings.layoutStatusLockPositions + : settings.layoutStatusPositions; + } + + private String[] statusMiddleSidesForScene(SbtSettings settings, SceneKey scene) { + return scene != null && scene.isLockscreen() + ? settings.layoutStatusLockMiddleSides + : settings.layoutStatusMiddleSides; + } + + private boolean[] statusAutoNearestForScene(SbtSettings settings, SceneKey scene) { + return scene != null && scene.isLockscreen() + ? settings.layoutStatusLockMiddleAutoNearestSides + : settings.layoutStatusMiddleAutoNearestSides; + } + + private int[] statusVerticalOffsetsForScene(SbtSettings settings, SceneKey scene) { + return scene != null && scene.isLockscreen() + ? settings.layoutStatusLockVerticalOffsetsPx + : settings.layoutStatusVerticalOffsetsPx; + } + + private String[] notificationPositionsForScene(SbtSettings settings, SceneKey scene) { + return scene != null && scene.isLockscreen() + ? settings.layoutNotifLockPositions + : settings.layoutNotifPositions; + } + + private String[] notificationMiddleSidesForScene(SbtSettings settings, SceneKey scene) { + return scene != null && scene.isLockscreen() + ? settings.layoutNotifLockMiddleSides + : settings.layoutNotifMiddleSides; + } + + private boolean[] notificationAutoNearestForScene(SbtSettings settings, SceneKey scene) { + return scene != null && scene.isLockscreen() + ? settings.layoutNotifLockMiddleAutoNearestSides + : settings.layoutNotifMiddleAutoNearestSides; + } + + private int[] notificationVerticalOffsetsForScene(SbtSettings settings, SceneKey scene) { + return scene != null && scene.isLockscreen() + ? settings.layoutNotifLockVerticalOffsetsPx + : settings.layoutNotifVerticalOffsetsPx; + } + + private ArrayList dotOnlyPlacements(ArrayList source) { + ArrayList result = new ArrayList<>(); + if (source == null || source.isEmpty()) { + return result; + } + SnapshotPlacement first = source.get(0); + int height = Math.max(1, first.bounds.height); + int width = Math.max(1, Math.round(height * 0.75f)); + int color = SnapshotAppearanceSignature.preferredColor( + first.source != null ? first.source.view() : null, + android.graphics.Color.WHITE); + result.add(new SnapshotPlacement( + null, + new Bounds(0, first.bounds.top, width, height), + SnapshotKeys.OVERFLOW_DOT + ":lockscreen_notifications", + false, + true, + color, + null, + new Bounds(0, 0, width, height), + 0)); + return result; + } + + private boolean isFixedDotBand(UnlockedLayoutBand band) { + return band != null + && band.rawPlacements != null + && band.rawPlacements.size() == 1 + && band.rawPlacements.get(0).overflowDot; + } + private ArrayList offsetPlacements(ArrayList placements, int verticalOffsetPx) { if (placements == null || placements.isEmpty() || verticalOffsetPx == 0) { return placements; @@ -647,6 +835,9 @@ final class UnlockedLayoutPlanner { } } } + if (!result.contains(LayoutItemKind.CARRIER)) { + result.add(0, LayoutItemKind.CARRIER); + } addKindIfMissing(result, LayoutItemKind.CLOCK); addKindIfMissing(result, LayoutItemKind.CHIP); addKindIfMissing(result, LayoutItemKind.STATUS); @@ -661,6 +852,9 @@ final class UnlockedLayoutPlanner { } private LayoutItemKind kindFor(String token) { + if ("carrier".equals(token)) { + return LayoutItemKind.CARRIER; + } if ("clock".equals(token)) { return LayoutItemKind.CLOCK; } 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 749e5ea..81d0ec5 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 @@ -53,7 +53,8 @@ final class UnlockedStockSourceCollector { statusIcons, notificationIcons, statusChips, - statusChipMetrics); + statusChipMetrics, + anchors.carrierView); } CollectedIcons collectChips( @@ -72,7 +73,8 @@ final class UnlockedStockSourceCollector { previousIcons != null ? previousIcons.statusIcons : new ArrayList<>(), previousIcons != null ? previousIcons.notificationIcons : new ArrayList<>(), statusChips, - statusChipMetrics); + statusChipMetrics, + anchors != null ? anchors.carrierView : null); } LayoutInputSignature layoutInputSignature( @@ -113,6 +115,7 @@ final class UnlockedStockSourceCollector { anchors != null ? anchors.battery : null, anchors != null ? anchors.clockContainer : null), notificationRootSignature(anchors != null ? anchors.notificationRoot : null), + viewSignatureOrZero(anchors != null ? anchors.carrierView : null), sourceListSignature(previousIcons != null ? previousIcons.statusIcons : null), sourceListSignature(previousIcons != null ? previousIcons.notificationIcons : null), chipSourceSignature); @@ -156,6 +159,7 @@ final class UnlockedStockSourceCollector { View battery = null; View statusIcons = null; View notificationRoot = null; + TextView carrierView = null; ArrayDeque queue = new ArrayDeque<>(); queue.add(root); while (!queue.isEmpty()) { @@ -186,13 +190,17 @@ final class UnlockedStockSourceCollector { if (notificationRoot == null && idName.equals("notificationIcons")) { notificationRoot = view; } + if (carrierView == null && view instanceof TextView textView && isCarrierTextView(textView)) { + carrierView = textView; + } if (clockContainer != null && clockView != null && statusRootPriority == 0 && statusEndContent != null && statusIcons != null && battery != null - && notificationRoot != null) { + && notificationRoot != null + && carrierView != null) { break; } if (view instanceof ViewGroup group) { @@ -211,7 +219,20 @@ final class UnlockedStockSourceCollector { statusEndContent, statusIcons, battery, - notificationRoot); + notificationRoot, + carrierView); + } + + private boolean isCarrierTextView(TextView view) { + if (view == null) { + return false; + } + String idName = resolveIdName(view).toLowerCase(java.util.Locale.ROOT); + String className = view.getClass().getName().toLowerCase(java.util.Locale.ROOT); + CharSequence text = view.getText(); + return (idName.contains("carrier") || className.contains("carrier")) + && text != null + && text.length() > 0; } private int statusRootPriority(String idName) { @@ -711,6 +732,12 @@ final class UnlockedStockSourceCollector { settings.layoutPaddingRightAddStock, settings.layoutIgnoreUnderDisplayCameras, settings.layoutItemOrder, + settings.clockEnabledLockscreen, + settings.layoutCarrierPosition, + settings.layoutCarrierEnabledLockscreen, + settings.layoutCarrierMiddleSide, + settings.layoutCarrierMiddleAutoNearestSide, + settings.layoutCarrierVerticalOffsetPx, settings.layoutChipPosition, settings.layoutChipEnabledUnlocked, settings.layoutChipMiddleSide, @@ -724,6 +751,12 @@ final class UnlockedStockSourceCollector { java.util.Arrays.hashCode(settings.layoutNotifMiddleSides), java.util.Arrays.hashCode(settings.layoutNotifMiddleAutoNearestSides), java.util.Arrays.hashCode(settings.layoutNotifVerticalOffsetsPx), + settings.layoutNotifEnabledLockscreen, + settings.layoutNotifLockCount, + java.util.Arrays.hashCode(settings.layoutNotifLockPositions), + java.util.Arrays.hashCode(settings.layoutNotifLockMiddleSides), + java.util.Arrays.hashCode(settings.layoutNotifLockMiddleAutoNearestSides), + java.util.Arrays.hashCode(settings.layoutNotifLockVerticalOffsetsPx), settings.layoutNotifMiddleSide, settings.layoutNotifMiddleAutoNearestSide, settings.layoutNotifVerticalOffsetPx, @@ -734,6 +767,12 @@ final class UnlockedStockSourceCollector { java.util.Arrays.hashCode(settings.layoutStatusMiddleSides), java.util.Arrays.hashCode(settings.layoutStatusMiddleAutoNearestSides), java.util.Arrays.hashCode(settings.layoutStatusVerticalOffsetsPx), + settings.layoutStatusEnabledLockscreen, + settings.layoutStatusLockCount, + java.util.Arrays.hashCode(settings.layoutStatusLockPositions), + java.util.Arrays.hashCode(settings.layoutStatusLockMiddleSides), + java.util.Arrays.hashCode(settings.layoutStatusLockMiddleAutoNearestSides), + java.util.Arrays.hashCode(settings.layoutStatusLockVerticalOffsetsPx), settings.layoutStatusMiddleSide, settings.layoutStatusMiddleAutoNearestSide, settings.layoutStatusVerticalOffsetPx, 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 d4ccf40..210c1ec 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 @@ -102,7 +102,12 @@ public final class SbtDefaults { public static final boolean LAYOUT_PADDING_LEFT_ADD_STOCK_DEFAULT = true; public static final boolean LAYOUT_PADDING_RIGHT_ADD_STOCK_DEFAULT = true; public static final boolean LAYOUT_IGNORE_UNDER_DISPLAY_CAMERAS_DEFAULT = true; - public static final String LAYOUT_ITEM_ORDER_DEFAULT = "clock,chip,status,notifications"; + public static final String LAYOUT_ITEM_ORDER_DEFAULT = "carrier,clock,chip,status,notifications"; + 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; 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 346fbbe..f47f9c0 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 @@ -95,6 +95,11 @@ public final class SbtSettings { public static final String KEY_LAYOUT_PADDING_RIGHT_ADD_STOCK = "layout_padding_right_add_stock"; public static final String KEY_LAYOUT_IGNORE_UNDER_DISPLAY_CAMERAS = "layout_ignore_under_display_cameras"; public static final String KEY_LAYOUT_ITEM_ORDER = "layout_item_order"; + 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"; @@ -157,6 +162,38 @@ public final class SbtSettings { return suffixedKey(KEY_LAYOUT_STATUS_VERTICAL_OFFSET_PX, index); } + public static String layoutLockNotifPositionKey(int index) { + return suffixedKey("layout_lock_notifications_position", index); + } + + public static String layoutLockNotifMiddleSideKey(int index) { + return suffixedKey("layout_lock_notifications_middle_side", index); + } + + public static String layoutLockNotifMiddleAutoNearestSideKey(int index) { + return suffixedKey("layout_lock_notifications_middle_auto_nearest_side", index); + } + + public static String layoutLockNotifVerticalOffsetKey(int index) { + return suffixedKey("layout_lock_notifications_vertical_offset_px", index); + } + + public static String layoutLockStatusPositionKey(int index) { + return suffixedKey("layout_lock_status_position", index); + } + + public static String layoutLockStatusMiddleSideKey(int index) { + return suffixedKey("layout_lock_status_middle_side", index); + } + + public static String layoutLockStatusMiddleAutoNearestSideKey(int index) { + return suffixedKey("layout_lock_status_middle_auto_nearest_side", index); + } + + public static String layoutLockStatusVerticalOffsetKey(int index) { + return suffixedKey("layout_lock_status_vertical_offset_px", index); + } + private static String suffixedKey(String base, int index) { return index <= 0 ? base : base + "_" + (index + 1); } @@ -212,6 +249,11 @@ public final class SbtSettings { public final boolean layoutPaddingRightAddStock; public final boolean layoutIgnoreUnderDisplayCameras; public final String layoutItemOrder; + 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; @@ -229,6 +271,11 @@ public final class SbtSettings { 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 String layoutNotifMiddleSide; public final boolean layoutNotifMiddleAutoNearestSide; public final int layoutNotifVerticalOffsetPx; @@ -241,6 +288,11 @@ public final class SbtSettings { 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 boolean layoutStatusShowDotIfTruncated; public final String layoutStatusMiddleSide; public final boolean layoutStatusMiddleAutoNearestSide; @@ -253,6 +305,7 @@ public final class SbtSettings { public final boolean statusChipsHideCallUnlocked; public final Map appIconBlockedModes; public final Map> appIconExceptionRules; + public final String lockedNotificationMode; public final boolean debugVisualizeNotificationContainer; public final boolean debugVisualizeStatusContainer; public final boolean debugVisualizeClockContainer; @@ -311,6 +364,11 @@ public final class SbtSettings { boolean layoutPaddingRightAddStock, boolean layoutIgnoreUnderDisplayCameras, String layoutItemOrder, + String layoutCarrierPosition, + boolean layoutCarrierEnabledLockscreen, + String layoutCarrierMiddleSide, + boolean layoutCarrierMiddleAutoNearestSide, + int layoutCarrierVerticalOffsetPx, String layoutChipPosition, boolean layoutChipEnabledLockscreen, boolean layoutChipEnabledUnlocked, @@ -331,6 +389,11 @@ public final class SbtSettings { String[] layoutNotifMiddleSides, boolean[] layoutNotifMiddleAutoNearestSides, int[] layoutNotifVerticalOffsetsPx, + int layoutNotifLockCount, + String[] layoutNotifLockPositions, + String[] layoutNotifLockMiddleSides, + boolean[] layoutNotifLockMiddleAutoNearestSides, + int[] layoutNotifLockVerticalOffsetsPx, String layoutStatusPosition, boolean layoutStatusEnabledAod, boolean layoutStatusEnabledLockscreen, @@ -344,6 +407,11 @@ public final class SbtSettings { String[] layoutStatusMiddleSides, boolean[] layoutStatusMiddleAutoNearestSides, int[] layoutStatusVerticalOffsetsPx, + int layoutStatusLockCount, + String[] layoutStatusLockPositions, + String[] layoutStatusLockMiddleSides, + boolean[] layoutStatusLockMiddleAutoNearestSides, + int[] layoutStatusLockVerticalOffsetsPx, Map clockCameraTypeOverrides, Map systemIconBlockedModes, boolean statusChipsHideAll, @@ -352,6 +420,7 @@ public final class SbtSettings { boolean statusChipsHideCallUnlocked, Map appIconBlockedModes, Map> appIconExceptionRules, + String lockedNotificationMode, boolean debugVisualizeNotificationContainer, boolean debugVisualizeStatusContainer, boolean debugVisualizeClockContainer, @@ -457,6 +526,18 @@ public final class SbtSettings { this.layoutItemOrder = layoutItemOrder != null ? layoutItemOrder : SbtDefaults.LAYOUT_ITEM_ORDER_DEFAULT; + this.layoutCarrierPosition = layoutCarrierPosition != null + ? layoutCarrierPosition + : SbtDefaults.LAYOUT_CARRIER_POSITION_DEFAULT; + this.layoutCarrierEnabledLockscreen = layoutCarrierEnabledLockscreen; + this.layoutCarrierMiddleSide = layoutCarrierMiddleSide != null + ? layoutCarrierMiddleSide + : SbtDefaults.LAYOUT_CARRIER_MIDDLE_SIDE_DEFAULT; + this.layoutCarrierMiddleAutoNearestSide = layoutCarrierMiddleAutoNearestSide; + this.layoutCarrierVerticalOffsetPx = clampInt( + layoutCarrierVerticalOffsetPx, + SbtDefaults.CLOCK_VERTICAL_OFFSET_PX_MIN, + SbtDefaults.CLOCK_VERTICAL_OFFSET_PX_MAX); this.layoutChipPosition = layoutChipPosition != null ? layoutChipPosition : SbtDefaults.LAYOUT_CHIP_POSITION_DEFAULT; @@ -509,6 +590,25 @@ public final class SbtSettings { SbtDefaults.LAYOUT_ICON_CONTAINER_COUNT_MAX, SbtDefaults.CLOCK_VERTICAL_OFFSET_PX_MIN, SbtDefaults.CLOCK_VERTICAL_OFFSET_PX_MAX); + this.layoutNotifLockCount = clampIconContainerCount(layoutNotifLockCount); + this.layoutNotifLockPositions = sanitizeStringArray( + layoutNotifLockPositions, + this.layoutNotifPosition, + SbtDefaults.LAYOUT_ICON_CONTAINER_COUNT_MAX); + this.layoutNotifLockMiddleSides = sanitizeStringArray( + 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, + SbtDefaults.LAYOUT_ICON_CONTAINER_COUNT_MAX, + SbtDefaults.CLOCK_VERTICAL_OFFSET_PX_MIN, + SbtDefaults.CLOCK_VERTICAL_OFFSET_PX_MAX); this.layoutStatusPosition = layoutStatusPosition != null ? layoutStatusPosition : SbtDefaults.LAYOUT_STATUS_POSITION_DEFAULT; @@ -545,6 +645,25 @@ public final class SbtSettings { SbtDefaults.LAYOUT_ICON_CONTAINER_COUNT_MAX, SbtDefaults.CLOCK_VERTICAL_OFFSET_PX_MIN, SbtDefaults.CLOCK_VERTICAL_OFFSET_PX_MAX); + this.layoutStatusLockCount = clampIconContainerCount(layoutStatusLockCount); + this.layoutStatusLockPositions = sanitizeStringArray( + layoutStatusLockPositions, + this.layoutStatusPosition, + SbtDefaults.LAYOUT_ICON_CONTAINER_COUNT_MAX); + this.layoutStatusLockMiddleSides = sanitizeStringArray( + 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, + SbtDefaults.LAYOUT_ICON_CONTAINER_COUNT_MAX, + SbtDefaults.CLOCK_VERTICAL_OFFSET_PX_MIN, + SbtDefaults.CLOCK_VERTICAL_OFFSET_PX_MAX); this.clockCameraTypeOverrides = clockCameraTypeOverrides != null ? Collections.unmodifiableMap(new HashMap<>(clockCameraTypeOverrides)) : Collections.emptyMap(); @@ -570,6 +689,7 @@ public final class SbtSettings { } else { this.appIconExceptionRules = Collections.emptyMap(); } + this.lockedNotificationMode = lockedNotificationMode != null ? lockedNotificationMode : "dot"; this.debugVisualizeNotificationContainer = debugVisualizeNotificationContainer; this.debugVisualizeStatusContainer = debugVisualizeStatusContainer; this.debugVisualizeClockContainer = debugVisualizeClockContainer; @@ -631,6 +751,11 @@ public final class SbtSettings { SbtDefaults.LAYOUT_PADDING_RIGHT_ADD_STOCK_DEFAULT, SbtDefaults.LAYOUT_IGNORE_UNDER_DISPLAY_CAMERAS_DEFAULT, SbtDefaults.LAYOUT_ITEM_ORDER_DEFAULT, + 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, @@ -651,6 +776,11 @@ public final class SbtSettings { 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, @@ -664,6 +794,11 @@ public final class SbtSettings { null, null, null, + SbtDefaults.LAYOUT_STATUS_UNLOCKED_COUNT_DEFAULT, + null, + null, + null, + null, Collections.emptyMap(), Collections.emptyMap(), false, @@ -672,6 +807,7 @@ public final class SbtSettings { false, Collections.emptyMap(), Collections.emptyMap(), + "dot", SbtDefaults.DEBUG_VISUALIZE_NOTIFICATION_CONTAINER_DEFAULT, SbtDefaults.DEBUG_VISUALIZE_STATUS_CONTAINER_DEFAULT, SbtDefaults.DEBUG_VISUALIZE_CLOCK_CONTAINER_DEFAULT, @@ -882,6 +1018,11 @@ public final class SbtSettings { prefs.getBoolean(KEY_LAYOUT_PADDING_RIGHT_ADD_STOCK, SbtDefaults.LAYOUT_PADDING_RIGHT_ADD_STOCK_DEFAULT), prefs.getBoolean(KEY_LAYOUT_IGNORE_UNDER_DISPLAY_CAMERAS, SbtDefaults.LAYOUT_IGNORE_UNDER_DISPLAY_CAMERAS_DEFAULT), prefs.getString(KEY_LAYOUT_ITEM_ORDER, SbtDefaults.LAYOUT_ITEM_ORDER_DEFAULT), + 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), @@ -925,6 +1066,28 @@ public final class SbtSettings { prefs, SbtSettings::layoutNotifVerticalOffsetKey, SbtDefaults.LAYOUT_NOTIF_VERTICAL_OFFSET_PX_DEFAULT), + readIconContainerCount( + prefs, + "layout_lock_notifications_count", + KEY_LAYOUT_NOTIF_ENABLED_LOCKSCREEN, + SbtDefaults.LAYOUT_NOTIF_UNLOCKED_COUNT_DEFAULT, + SbtDefaults.LAYOUT_NOTIF_ENABLED_LOCKSCREEN_DEFAULT), + readStringArrayFromPrefs( + prefs, + SbtSettings::layoutLockNotifPositionKey, + SbtDefaults.LAYOUT_NOTIF_POSITION_DEFAULT), + readStringArrayFromPrefs( + 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, + SbtDefaults.LAYOUT_NOTIF_VERTICAL_OFFSET_PX_DEFAULT), prefs.getString(KEY_LAYOUT_STATUS_POSITION, SbtDefaults.LAYOUT_STATUS_POSITION_DEFAULT), 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), @@ -958,6 +1121,28 @@ public final class SbtSettings { prefs, SbtSettings::layoutStatusVerticalOffsetKey, SbtDefaults.LAYOUT_STATUS_VERTICAL_OFFSET_PX_DEFAULT), + readIconContainerCount( + prefs, + "layout_lock_status_count", + KEY_LAYOUT_STATUS_ENABLED_LOCKSCREEN, + SbtDefaults.LAYOUT_STATUS_UNLOCKED_COUNT_DEFAULT, + SbtDefaults.LAYOUT_STATUS_ENABLED_LOCKSCREEN_DEFAULT), + readStringArrayFromPrefs( + prefs, + SbtSettings::layoutLockStatusPositionKey, + SbtDefaults.LAYOUT_STATUS_POSITION_DEFAULT), + readStringArrayFromPrefs( + 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, + SbtDefaults.LAYOUT_STATUS_VERTICAL_OFFSET_PX_DEFAULT), ClockCameraTypeSupport.parseOverrides(copyStringSet( prefs.getStringSet(KEY_CLOCK_CAMERA_TYPE_OVERRIDES, Collections.emptySet()))), systemIconBlockedModes, @@ -969,6 +1154,7 @@ public final class SbtSettings { prefs.getStringSet(KEY_APP_ICON_BLOCKED_MODES, Collections.emptySet()))), AppIconRules.parseExceptionRules(copyStringSet( prefs.getStringSet(KEY_APP_ICON_EXCEPTION_RULES, Collections.emptySet()))), + prefs.getString(KEY_LOCKED_NOTIFICATION_MODE, "dot"), prefs.getBoolean( KEY_DEBUG_VISUALIZE_NOTIFICATION_CONTAINER, SbtDefaults.DEBUG_VISUALIZE_NOTIFICATION_CONTAINER_DEFAULT), @@ -1079,6 +1265,11 @@ public final class SbtSettings { bundle.getBoolean(KEY_LAYOUT_PADDING_RIGHT_ADD_STOCK, SbtDefaults.LAYOUT_PADDING_RIGHT_ADD_STOCK_DEFAULT), bundle.getBoolean(KEY_LAYOUT_IGNORE_UNDER_DISPLAY_CAMERAS, SbtDefaults.LAYOUT_IGNORE_UNDER_DISPLAY_CAMERAS_DEFAULT), bundle.getString(KEY_LAYOUT_ITEM_ORDER, SbtDefaults.LAYOUT_ITEM_ORDER_DEFAULT), + 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), @@ -1122,6 +1313,28 @@ public final class SbtSettings { bundle, SbtSettings::layoutNotifVerticalOffsetKey, SbtDefaults.LAYOUT_NOTIF_VERTICAL_OFFSET_PX_DEFAULT), + readIconContainerCount( + bundle, + "layout_lock_notifications_count", + KEY_LAYOUT_NOTIF_ENABLED_LOCKSCREEN, + SbtDefaults.LAYOUT_NOTIF_UNLOCKED_COUNT_DEFAULT, + SbtDefaults.LAYOUT_NOTIF_ENABLED_LOCKSCREEN_DEFAULT), + readStringArrayFromBundle( + bundle, + SbtSettings::layoutLockNotifPositionKey, + SbtDefaults.LAYOUT_NOTIF_POSITION_DEFAULT), + readStringArrayFromBundle( + 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, + SbtDefaults.LAYOUT_NOTIF_VERTICAL_OFFSET_PX_DEFAULT), bundle.getString(KEY_LAYOUT_STATUS_POSITION, SbtDefaults.LAYOUT_STATUS_POSITION_DEFAULT), 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), @@ -1155,6 +1368,28 @@ public final class SbtSettings { bundle, SbtSettings::layoutStatusVerticalOffsetKey, SbtDefaults.LAYOUT_STATUS_VERTICAL_OFFSET_PX_DEFAULT), + readIconContainerCount( + bundle, + "layout_lock_status_count", + KEY_LAYOUT_STATUS_ENABLED_LOCKSCREEN, + SbtDefaults.LAYOUT_STATUS_UNLOCKED_COUNT_DEFAULT, + SbtDefaults.LAYOUT_STATUS_ENABLED_LOCKSCREEN_DEFAULT), + readStringArrayFromBundle( + bundle, + SbtSettings::layoutLockStatusPositionKey, + SbtDefaults.LAYOUT_STATUS_POSITION_DEFAULT), + readStringArrayFromBundle( + 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, + SbtDefaults.LAYOUT_STATUS_VERTICAL_OFFSET_PX_DEFAULT), ClockCameraTypeSupport.parseOverrides(readStringSetFromBundle(bundle, KEY_CLOCK_CAMERA_TYPE_OVERRIDES)), systemIconBlockedModes, bundle.getBoolean(KEY_STATUS_CHIPS_HIDE_ALL, false), @@ -1163,6 +1398,7 @@ public final class SbtSettings { bundle.getBoolean(KEY_STATUS_CHIPS_HIDE_CALL, false), AppIconRules.parseBlockedModes(readBlockedSetFromBundle(bundle)), AppIconRules.parseExceptionRules(readRuleSetFromBundle(bundle)), + bundle.getString(KEY_LOCKED_NOTIFICATION_MODE, "dot"), bundle.getBoolean( KEY_DEBUG_VISUALIZE_NOTIFICATION_CONTAINER, SbtDefaults.DEBUG_VISUALIZE_NOTIFICATION_CONTAINER_DEFAULT), @@ -1189,6 +1425,12 @@ public final class SbtSettings { return value; } + private static int clampIconContainerCount(int value) { + return Math.max( + SbtDefaults.LAYOUT_ICON_CONTAINER_COUNT_MIN, + Math.min(SbtDefaults.LAYOUT_ICON_CONTAINER_COUNT_MAX, value)); + } + private static int readIconContainerCount( SharedPreferences prefs, String countKey, 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 61b191a..02f093a 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 @@ -182,6 +182,23 @@ public class SbtSettingsProvider extends ContentProvider { out.putString(SbtSettings.KEY_LAYOUT_ITEM_ORDER, prefs.getString(SbtSettings.KEY_LAYOUT_ITEM_ORDER, SbtDefaults.LAYOUT_ITEM_ORDER_DEFAULT)); + out.putString(SbtSettings.KEY_LOCKED_NOTIFICATION_MODE, + prefs.getString(SbtSettings.KEY_LOCKED_NOTIFICATION_MODE, "dot")); + out.putString(SbtSettings.KEY_LAYOUT_CARRIER_POSITION, + prefs.getString(SbtSettings.KEY_LAYOUT_CARRIER_POSITION, + SbtDefaults.LAYOUT_CARRIER_POSITION_DEFAULT)); + out.putBoolean(SbtSettings.KEY_LAYOUT_CARRIER_ENABLED_LOCKSCREEN, + prefs.getBoolean(SbtSettings.KEY_LAYOUT_CARRIER_ENABLED_LOCKSCREEN, + SbtDefaults.LAYOUT_CARRIER_ENABLED_LOCKSCREEN_DEFAULT)); + 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)); @@ -245,6 +262,24 @@ public class SbtSettingsProvider extends ContentProvider { SbtDefaults.LAYOUT_NOTIF_MIDDLE_AUTO_NEAREST_SIDE_DEFAULT, SbtSettings::layoutNotifVerticalOffsetKey, SbtDefaults.LAYOUT_NOTIF_VERTICAL_OFFSET_PX_DEFAULT); + out.putInt("layout_lock_notifications_count", + prefs.getInt("layout_lock_notifications_count", + prefs.getBoolean( + SbtSettings.KEY_LAYOUT_NOTIF_ENABLED_LOCKSCREEN, + SbtDefaults.LAYOUT_NOTIF_ENABLED_LOCKSCREEN_DEFAULT) + ? SbtDefaults.LAYOUT_NOTIF_UNLOCKED_COUNT_DEFAULT + : 0)); + putIconCopySettings( + out, + prefs, + SbtSettings::layoutLockNotifPositionKey, + 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.putString(SbtSettings.KEY_LAYOUT_STATUS_POSITION, prefs.getString(SbtSettings.KEY_LAYOUT_STATUS_POSITION, SbtDefaults.LAYOUT_STATUS_POSITION_DEFAULT)); @@ -287,6 +322,24 @@ public class SbtSettingsProvider extends ContentProvider { SbtDefaults.LAYOUT_STATUS_MIDDLE_AUTO_NEAREST_SIDE_DEFAULT, SbtSettings::layoutStatusVerticalOffsetKey, SbtDefaults.LAYOUT_STATUS_VERTICAL_OFFSET_PX_DEFAULT); + out.putInt("layout_lock_status_count", + prefs.getInt("layout_lock_status_count", + prefs.getBoolean( + SbtSettings.KEY_LAYOUT_STATUS_ENABLED_LOCKSCREEN, + SbtDefaults.LAYOUT_STATUS_ENABLED_LOCKSCREEN_DEFAULT) + ? SbtDefaults.LAYOUT_STATUS_UNLOCKED_COUNT_DEFAULT + : 0)); + putIconCopySettings( + out, + prefs, + SbtSettings::layoutLockStatusPositionKey, + 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.putStringArrayList( SbtSettings.KEY_CLOCK_CAMERA_TYPE_OVERRIDES, new ArrayList<>(prefs.getStringSet( 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 4be52f7..2a75901 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 @@ -1161,6 +1161,7 @@ public final class LayoutFragment extends Fragment { for (String token : encoded.split(",")) { addOrderingItemIfValid(items, token != null ? token.trim() : ""); } + addCarrierOrderingItemIfMissing(items); addOrderingItemIfValid(items, "clock"); addOrderingItemIfValid(items, "chip"); addOrderingItemIfValid(items, "status"); @@ -1168,6 +1169,15 @@ public final class LayoutFragment extends Fragment { return items; } + private void addCarrierOrderingItemIfMissing(ArrayList items) { + for (OrderingItem item : items) { + if ("carrier".equals(item.key)) { + return; + } + } + items.add(0, new OrderingItem("carrier", getString(R.string.layout_ordering_carrier))); + } + private void addOrderingItemIfValid(ArrayList items, String key) { if (key == null || key.isEmpty()) { return; @@ -1178,7 +1188,9 @@ public final class LayoutFragment extends Fragment { } } int labelRes; - if ("clock".equals(key)) { + if ("carrier".equals(key)) { + labelRes = R.string.layout_ordering_carrier; + } else if ("clock".equals(key)) { labelRes = R.string.layout_ordering_clock; } else if ("chip".equals(key)) { labelRes = R.string.layout_ordering_chip; 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 31cdecc..84e8505 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 @@ -148,6 +148,9 @@ final class LayoutOrderingUi { for (String token : encoded.split(",")) { addKeyIfValid(keys, token != null ? token.trim() : ""); } + if (!keys.contains("carrier")) { + keys.add(0, "carrier"); + } addKeyIfValid(keys, "clock"); addKeyIfValid(keys, "chip"); addKeyIfValid(keys, "status"); @@ -156,7 +159,8 @@ final class LayoutOrderingUi { } private static void addKeyIfValid(ArrayList keys, String key) { - if (!"clock".equals(key) + if (!"carrier".equals(key) + && !"clock".equals(key) && !"chip".equals(key) && !"status".equals(key) && !"notifications".equals(key)) { @@ -177,7 +181,9 @@ final class LayoutOrderingUi { } } int labelRes; - if ("clock".equals(key)) { + if ("carrier".equals(key)) { + labelRes = R.string.layout_ordering_carrier; + } else if ("clock".equals(key)) { labelRes = R.string.layout_ordering_clock; } else if ("chip".equals(key)) { labelRes = R.string.layout_ordering_chip; 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 feef061..6ba4f79 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 @@ -82,10 +82,6 @@ abstract class LockedSceneLayoutFragment extends Fragment { private void rebuildDynamic(Context context, SharedPreferences prefs, String mode) { dynamicContent.removeAllViews(); - if (LockedNotificationModeUi.MODE_DOT.equals(mode) - || LockedNotificationModeUi.MODE_NONE.equals(mode)) { - return; - } LinkedHashMap cardsByOrderKey = new LinkedHashMap<>(); if (!aod) { cardsByOrderKey.put("clock", configuredPositionCardFromLayout( @@ -115,6 +111,35 @@ abstract class LockedSceneLayoutFragment extends Fragment { SbtDefaults.CLOCK_MIDDLE_CUTOUT_SIDE_DEFAULT, sceneKey("clock_vertical_offset_px"), SbtDefaults.CLOCK_VERTICAL_OFFSET_PX_DEFAULT)); + View carrierCard = configuredPositionCardFromLayout( + context, + prefs, + R.id.layout_clock_card, + R.id.clock_position_mode_lockscreen, + SbtSettings.KEY_LAYOUT_CARRIER_ENABLED_LOCKSCREEN, + SbtDefaults.LAYOUT_CARRIER_ENABLED_LOCKSCREEN_DEFAULT, + R.id.clock_position_group, + R.id.clock_position_middle_options_container, + R.id.clock_middle_auto_nearest, + R.id.clock_middle_side_prompt, + R.id.clock_middle_side_group, + R.id.clock_middle_side_right, + R.id.clock_vertical_offset_input, + R.id.clock_vertical_offset_minus_fast, + R.id.clock_vertical_offset_minus, + R.id.clock_vertical_offset_plus, + R.id.clock_vertical_offset_plus_fast, + 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, + SbtSettings.KEY_LAYOUT_CARRIER_MIDDLE_SIDE, + SbtDefaults.LAYOUT_CARRIER_MIDDLE_SIDE_DEFAULT, + SbtSettings.KEY_LAYOUT_CARRIER_VERTICAL_OFFSET_PX, + SbtDefaults.LAYOUT_CARRIER_VERTICAL_OFFSET_PX_DEFAULT); + setCardTitle(carrierCard, R.string.layout_carrier_position_title); + cardsByOrderKey.put("carrier", carrierCard); } cardsByOrderKey.put("status", configuredIconContainersCardFromLayout( context, @@ -143,7 +168,7 @@ abstract class LockedSceneLayoutFragment extends Fragment { SbtDefaults.LAYOUT_STATUS_VERTICAL_OFFSET_PX_DEFAULT)); if (LockedNotificationModeUi.MODE_CARDS.equals(mode)) { cardsByOrderKey.put("notifications", cardsNotificationCard(context, prefs)); - } else { + } else if (!LockedNotificationModeUi.MODE_NONE.equals(mode)) { cardsByOrderKey.put("notifications", configuredIconContainersCardFromLayout( context, prefs, @@ -178,6 +203,13 @@ abstract class LockedSceneLayoutFragment extends Fragment { } } + private void setCardTitle(View card, int titleId) { + TextView title = findCardTitle(card); + if (title != null) { + title.setText(titleId); + } + } + private View configuredPositionCardFromLayout( Context context, SharedPreferences prefs, diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 5505499..4e97d8c 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -169,6 +169,7 @@ Use custom layout Clock position Clock + Carrier Status chip Notification icons Status icons @@ -198,6 +199,7 @@ Reversed Auto Clock + Carrier Status chip Notif icons Status icons