Advance lockscreen layout and rotation handling
This commit is contained in:
+93
-20
@@ -6,7 +6,9 @@ import android.content.res.Resources;
|
||||
import android.os.PowerManager;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Collections;
|
||||
import java.util.IdentityHashMap;
|
||||
@@ -56,7 +58,7 @@ final class StockLayoutCanvasController {
|
||||
|
||||
private final RuntimeContext runtimeContext;
|
||||
private final Map<View, HiddenViewState> hiddenViewStates = new WeakHashMap<>();
|
||||
private final Map<View, RootSize> rootSizes = new WeakHashMap<>();
|
||||
private final Map<View, RootGeometry> rootGeometries = new WeakHashMap<>();
|
||||
private final Map<View, Integer> debugOverlaySignatures = new WeakHashMap<>();
|
||||
private final Set<View> confirmedAodPluginViews =
|
||||
Collections.newSetFromMap(new WeakHashMap<>());
|
||||
@@ -75,6 +77,10 @@ final class StockLayoutCanvasController {
|
||||
private final DebugBoundsOverlayController debugBoundsOverlayController =
|
||||
new DebugBoundsOverlayController();
|
||||
private final UnlockedIconSnapshotRenderController unlockedIconRenderController;
|
||||
// The keyguard carrier text lives outside the statusbar root on this device.
|
||||
// Keep a weak source reference so the lockscreen statusbar can render it when
|
||||
// normal current-root anchor discovery cannot find it.
|
||||
private WeakReference<TextView> lockedCarrierTextSource = new WeakReference<>(null);
|
||||
|
||||
private boolean hooksInstalled;
|
||||
|
||||
@@ -188,7 +194,7 @@ final class StockLayoutCanvasController {
|
||||
return;
|
||||
}
|
||||
if (activeScene != null && (activeScene.isUnlocked() || activeScene.isLockscreen())) {
|
||||
if (isKnownRootSizeChanged(root)) {
|
||||
if (isKnownRootGeometryChanged(root)) {
|
||||
ownedIconHostManager.setUnlockedHostsVisible(root, false);
|
||||
removeDebugOverlay(root);
|
||||
}
|
||||
@@ -203,6 +209,7 @@ final class StockLayoutCanvasController {
|
||||
unlockedHosts.statusHost,
|
||||
unlockedHosts.notificationHost,
|
||||
activeScene);
|
||||
ownedIconHostManager.bringUnlockedHostsToFront(root);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -236,13 +243,18 @@ final class StockLayoutCanvasController {
|
||||
removeDebugOverlay(root);
|
||||
return;
|
||||
}
|
||||
if (activeScene != null
|
||||
&& (activeScene.isUnlocked() || activeScene.isLockscreen())
|
||||
&& resetUnlockedHostsForRootGeometryChange(root)) {
|
||||
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);
|
||||
markRootGeometryBeforeDraw(root);
|
||||
renderResult = unlockedIconRenderController.renderUnlocked(
|
||||
root,
|
||||
unlockedHosts.clockHost,
|
||||
@@ -250,13 +262,20 @@ final class StockLayoutCanvasController {
|
||||
unlockedHosts.chipHost,
|
||||
unlockedHosts.statusHost,
|
||||
unlockedHosts.notificationHost,
|
||||
activeScene);
|
||||
ownedIconHostManager.setUnlockedHostsVisible(root, true);
|
||||
activeScene,
|
||||
lockedCarrierTextSource());
|
||||
boolean shouldShowUnlockedHosts = unlockedScene || renderResult.shouldOwnLockscreen();
|
||||
ownedIconHostManager.setUnlockedHostsVisible(root, shouldShowUnlockedHosts);
|
||||
if (shouldShowUnlockedHosts) {
|
||||
ownedIconHostManager.bringUnlockedHostsToFront(root);
|
||||
}
|
||||
}
|
||||
if (!unlockedScene) {
|
||||
trackedUnlockedStockSurfaces.clear();
|
||||
restoreTransientUnlockedSources();
|
||||
hideOrDiscoverLockedStatusBarIconSurfaces(root);
|
||||
if (renderResult.shouldOwnLockscreen()) {
|
||||
hideOrDiscoverLockedStatusBarIconSurfaces(root);
|
||||
}
|
||||
removeDebugOverlay(root);
|
||||
return;
|
||||
}
|
||||
@@ -421,6 +440,7 @@ final class StockLayoutCanvasController {
|
||||
private void trackAndHideLockedStatusBarIconSurfaces(View root) {
|
||||
walkTree(root, view -> {
|
||||
if (isLockedStatusBarIconSurface(view)) {
|
||||
rememberLockedCarrierTextSource(view);
|
||||
trackedLockedStatusBarIconSurfaces.add(view);
|
||||
hideView(view, isCarrierView(view));
|
||||
}
|
||||
@@ -509,13 +529,15 @@ final class StockLayoutCanvasController {
|
||||
}
|
||||
String idName = resolveIdName(view);
|
||||
String viewClassName = view.getClass().getName();
|
||||
boolean carrierSurface = idName.toLowerCase(java.util.Locale.ROOT).contains("carrier")
|
||||
|| viewClassName.toLowerCase(java.util.Locale.ROOT).contains("carrier");
|
||||
boolean shelfSurface = viewClassName.contains("NotificationShelf");
|
||||
boolean shadeIconOnlySurface = "notification_icononly_container".equals(idName)
|
||||
|| "notification_icononly_area".equals(idName)
|
||||
|| "keyguard_icononly_container_view".equals(idName)
|
||||
|| "common_notification_widget".equals(idName);
|
||||
if (!("system_icons".equals(idName)
|
||||
|| idName.toLowerCase(java.util.Locale.ROOT).contains("carrier")
|
||||
|| carrierSurface
|
||||
|| "system_icon_area".equals(idName)
|
||||
|| "statusIcons".equals(idName)
|
||||
|| "battery".equals(idName)
|
||||
@@ -537,6 +559,9 @@ final class StockLayoutCanvasController {
|
||||
|| className.contains("StatusBarWindowView")) {
|
||||
return true;
|
||||
}
|
||||
if (carrierSurface && className.contains("NotificationShadeWindowView")) {
|
||||
return true;
|
||||
}
|
||||
if (shelfSurface && className.contains("NotificationShadeWindowView")) {
|
||||
return true;
|
||||
}
|
||||
@@ -568,6 +593,32 @@ final class StockLayoutCanvasController {
|
||||
|| className.contains("StatusBarWindowView");
|
||||
}
|
||||
|
||||
private void rememberLockedCarrierTextSource(View root) {
|
||||
if (lockedCarrierTextSource() != null || root == null || !isCarrierView(root)) {
|
||||
return;
|
||||
}
|
||||
walkTree(root, view -> {
|
||||
if (lockedCarrierTextSource() != null || !(view instanceof TextView textView)) {
|
||||
return;
|
||||
}
|
||||
String idName = resolveIdName(textView);
|
||||
String className = textView.getClass().getName();
|
||||
if ("keyguard_carrier_text".equals(idName) || className.contains("CarrierText")) {
|
||||
lockedCarrierTextSource = new WeakReference<>(textView);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private TextView lockedCarrierTextSource() {
|
||||
TextView source = lockedCarrierTextSource.get();
|
||||
if (source == null || !source.isAttachedToWindow()) {
|
||||
lockedCarrierTextSource.clear();
|
||||
return null;
|
||||
}
|
||||
CharSequence text = source.getText();
|
||||
return text != null && text.length() > 0 ? source : null;
|
||||
}
|
||||
|
||||
private boolean shouldHideNonChipView(View view) {
|
||||
if (view == null) {
|
||||
return false;
|
||||
@@ -637,32 +688,54 @@ final class StockLayoutCanvasController {
|
||||
|| "ongoing_activity_capsule".equals(idName);
|
||||
}
|
||||
|
||||
private void markRootSizeBeforeDraw(View root) {
|
||||
private void markRootGeometryBeforeDraw(View root) {
|
||||
if (!isUnlockedStatusBarRoot(root)) {
|
||||
return;
|
||||
}
|
||||
markRootSize(root, new RootSize(root.getWidth(), root.getHeight()));
|
||||
markRootGeometry(root, rootGeometry(root));
|
||||
}
|
||||
|
||||
private boolean isKnownRootSizeChanged(View root) {
|
||||
private boolean resetUnlockedHostsForRootGeometryChange(View root) {
|
||||
if (!isKnownRootGeometryChanged(root)) {
|
||||
return false;
|
||||
}
|
||||
markRootGeometryBeforeDraw(root);
|
||||
unlockedIconRenderController.clearAll();
|
||||
ownedIconHostManager.removeUnlockedHosts(root);
|
||||
unlockedHostsByRoot.remove(root);
|
||||
removeDebugOverlay(root);
|
||||
root.requestLayout();
|
||||
root.invalidate();
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean isKnownRootGeometryChanged(View root) {
|
||||
if (!isUnlockedStatusBarRoot(root)) {
|
||||
return false;
|
||||
}
|
||||
RootSize previous = rootSizes.get(root);
|
||||
return previous != null
|
||||
&& (previous.width != root.getWidth() || previous.height != root.getHeight());
|
||||
RootGeometry previous = rootGeometries.get(root);
|
||||
RootGeometry current = rootGeometry(root);
|
||||
return previous != null && !previous.equals(current);
|
||||
}
|
||||
|
||||
private void markRootSize(View root, RootSize size) {
|
||||
if (size.width <= 0 || size.height <= 0) {
|
||||
private void markRootGeometry(View root, RootGeometry geometry) {
|
||||
if (geometry.width <= 0 || geometry.height <= 0) {
|
||||
return;
|
||||
}
|
||||
RootSize previous = rootSizes.put(root, size);
|
||||
if (previous != null && !previous.equals(size)) {
|
||||
RootGeometry previous = rootGeometries.put(root, geometry);
|
||||
if (previous != null && !previous.equals(geometry)) {
|
||||
unlockedIconRenderController.beginRootTransition();
|
||||
}
|
||||
}
|
||||
|
||||
private RootGeometry rootGeometry(View root) {
|
||||
int rotation = root != null && root.getDisplay() != null ? root.getDisplay().getRotation() : -1;
|
||||
return new RootGeometry(
|
||||
root != null ? root.getWidth() : 0,
|
||||
root != null ? root.getHeight() : 0,
|
||||
rotation);
|
||||
}
|
||||
|
||||
private void enforceDirectAodControllerPolicy(Object controller) {
|
||||
if (controller == null) {
|
||||
return;
|
||||
@@ -758,7 +831,7 @@ final class StockLayoutCanvasController {
|
||||
if (!isUnlockedStatusBarRoot(root) || !layoutOffCleanedRoots.add(root)) {
|
||||
return;
|
||||
}
|
||||
rootSizes.remove(root);
|
||||
rootGeometries.remove(root);
|
||||
unlockedIconRenderController.clearAll();
|
||||
ownedIconHostManager.removeUnlockedHosts(root);
|
||||
}
|
||||
@@ -805,7 +878,7 @@ final class StockLayoutCanvasController {
|
||||
if (!isUnlockedStatusBarRoot(root)) {
|
||||
return null;
|
||||
}
|
||||
if (activeScene != null && activeScene.isUnlocked()) {
|
||||
if (activeScene != null && (activeScene.isUnlocked() || activeScene.isLockscreen())) {
|
||||
UnlockedHosts cached = unlockedHostsByRoot.get(root);
|
||||
if (areUnlockedHostsAttached(root, cached)) {
|
||||
return cached;
|
||||
@@ -942,7 +1015,7 @@ final class StockLayoutCanvasController {
|
||||
) {
|
||||
}
|
||||
|
||||
private record RootSize(int width, int height) {
|
||||
private record RootGeometry(int width, int height, int rotation) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -95,6 +95,14 @@ public final class OwnedIconHostManager {
|
||||
setHostVisible(root, TAG_UNLOCKED_CHIP_HOST, visible);
|
||||
}
|
||||
|
||||
public void bringUnlockedHostsToFront(View root) {
|
||||
bringHostToFront(root, TAG_UNLOCKED_STATUS_HOST);
|
||||
bringHostToFront(root, TAG_UNLOCKED_NOTIFICATION_HOST);
|
||||
bringHostToFront(root, TAG_UNLOCKED_CLOCK_HOST);
|
||||
bringHostToFront(root, TAG_UNLOCKED_CARRIER_HOST);
|
||||
bringHostToFront(root, TAG_UNLOCKED_CHIP_HOST);
|
||||
}
|
||||
|
||||
public boolean isOwnedHost(View view) {
|
||||
if (view == null) {
|
||||
return false;
|
||||
@@ -128,6 +136,16 @@ public final class OwnedIconHostManager {
|
||||
host.setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
|
||||
}
|
||||
|
||||
private void bringHostToFront(View root, String tag) {
|
||||
if (!(root instanceof ViewGroup parent) || tag == null) {
|
||||
return;
|
||||
}
|
||||
FrameLayout host = findDirectHost(parent, tag);
|
||||
if (host != null) {
|
||||
host.bringToFront();
|
||||
}
|
||||
}
|
||||
|
||||
private void disableAncestorClipping(View view) {
|
||||
Object current = view;
|
||||
int depth = 0;
|
||||
|
||||
@@ -196,6 +196,18 @@ final class RootAnchors {
|
||||
&& (clockContainer == null || isAttached(clockContainer));
|
||||
}
|
||||
|
||||
RootAnchors withCarrierView(TextView carrierView) {
|
||||
return new RootAnchors(
|
||||
clockContainer,
|
||||
clockView,
|
||||
statusRoot,
|
||||
statusEndContent,
|
||||
statusIcons,
|
||||
battery,
|
||||
notificationRoot,
|
||||
carrierView);
|
||||
}
|
||||
|
||||
private static boolean isAttached(View view) {
|
||||
return view != null && view.isAttachedToWindow();
|
||||
}
|
||||
|
||||
+45
-4
@@ -57,7 +57,8 @@ public final class UnlockedIconSnapshotRenderController {
|
||||
ViewGroup chipHost,
|
||||
ViewGroup statusHost,
|
||||
ViewGroup notificationHost,
|
||||
SceneKey scene
|
||||
SceneKey scene,
|
||||
TextView externalCarrierView
|
||||
) {
|
||||
if (scene == null || (!scene.isUnlocked() && !scene.isLockscreen()) || !root.isAttachedToWindow()) {
|
||||
clearAll();
|
||||
@@ -70,6 +71,18 @@ public final class UnlockedIconSnapshotRenderController {
|
||||
layoutHostToRoot(root, statusHost);
|
||||
layoutHostToRoot(root, notificationHost);
|
||||
RootAnchors anchors = sourceCollector.anchorsFor(root);
|
||||
if (scene.isLockscreen()
|
||||
&& settings.layoutCarrierEnabledLockscreen
|
||||
&& (anchors == null || anchors.carrierView == null)) {
|
||||
anchors = sourceCollector.refreshAnchors(root);
|
||||
}
|
||||
if (scene.isLockscreen()
|
||||
&& settings.layoutCarrierEnabledLockscreen
|
||||
&& anchors != null
|
||||
&& anchors.carrierView == null
|
||||
&& externalCarrierView != null) {
|
||||
anchors = anchors.withCarrierView(externalCarrierView);
|
||||
}
|
||||
CollectedIcons previousIcons = lastCollectedIconsByRoot.get(root);
|
||||
LayoutInputSignature signature = sourceCollector.layoutInputSignature(
|
||||
root,
|
||||
@@ -84,7 +97,11 @@ public final class UnlockedIconSnapshotRenderController {
|
||||
boolean chipSourcesChanged = previousSignature == null
|
||||
|| signature.chipSources != previousSignature.chipSources;
|
||||
if (signature.equals(previousSignature)) {
|
||||
return new RenderResult(false, false);
|
||||
return new RenderResult(
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
!scene.isLockscreen() || lastLayoutPlanByRoot.get(root) != null);
|
||||
}
|
||||
lastLayoutSignatureByRoot.put(root, signature);
|
||||
Integer currentClockSourceGeometry = clockSourceGeometrySignature(
|
||||
@@ -156,6 +173,11 @@ public final class UnlockedIconSnapshotRenderController {
|
||||
settings,
|
||||
UnlockedLayoutPlanner.cutoutBounds(ViewGeometry.middleCutout(root), settings.clockMiddleCutoutGapPx));
|
||||
}
|
||||
if (scene.isLockscreen() && clockEnabledForScene(settings, scene) && currentClockLayout == null) {
|
||||
clearLockscreenHosts(clockHost, carrierHost, chipHost, statusHost, notificationHost);
|
||||
lastLayoutPlanByRoot.remove(root);
|
||||
return new RenderResult(false, stockSourcesChanged, chipSourcesChanged, false);
|
||||
}
|
||||
LayoutPlan layoutPlan = layoutPlanner.solve(
|
||||
root,
|
||||
clockHost,
|
||||
@@ -243,6 +265,20 @@ public final class UnlockedIconSnapshotRenderController {
|
||||
}
|
||||
}
|
||||
|
||||
private void clearLockscreenHosts(
|
||||
ViewGroup clockHost,
|
||||
ViewGroup carrierHost,
|
||||
ViewGroup chipHost,
|
||||
ViewGroup statusHost,
|
||||
ViewGroup notificationHost
|
||||
) {
|
||||
clockRenderer.clear(clockHost);
|
||||
carrierRenderer.clear(carrierHost);
|
||||
chipRenderer.clear(chipHost);
|
||||
statusRenderer.clear(statusHost);
|
||||
notificationRenderer.clear(notificationHost);
|
||||
}
|
||||
|
||||
private void layoutHostToRoot(View root, ViewGroup host) {
|
||||
if (root == null || host == null || root.getWidth() <= 0 || root.getHeight() <= 0) {
|
||||
return;
|
||||
@@ -817,10 +853,15 @@ public final class UnlockedIconSnapshotRenderController {
|
||||
public record RenderResult(
|
||||
boolean layoutChanged,
|
||||
boolean stockSourcesChanged,
|
||||
boolean chipSourcesChanged
|
||||
boolean chipSourcesChanged,
|
||||
boolean shouldOwnLockscreen
|
||||
) {
|
||||
public RenderResult(boolean layoutChanged, boolean stockSourcesChanged) {
|
||||
this(layoutChanged, stockSourcesChanged, stockSourcesChanged);
|
||||
this(layoutChanged, stockSourcesChanged, stockSourcesChanged, true);
|
||||
}
|
||||
|
||||
public RenderResult(boolean layoutChanged, boolean stockSourcesChanged, boolean chipSourcesChanged) {
|
||||
this(layoutChanged, stockSourcesChanged, chipSourcesChanged, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+36
-4
@@ -168,6 +168,7 @@ final class UnlockedLayoutPlanner {
|
||||
}
|
||||
ArrayList<LayoutItemKind> itemOrder = orderedKinds(settings.layoutItemOrder);
|
||||
splitClockIfNeeded(root, bands, itemOrder, clockCutoutBounds, settings);
|
||||
sortBandsForItemOrder(bands, itemOrder);
|
||||
LayoutEdges edges = layoutEdges(root, settings, anchors);
|
||||
int itemPadding = Math.max(0, settings.layoutItemPaddingPx);
|
||||
solveWithPackedLayout(root, edges, bands, layoutCutoutBounds, settings, itemPadding);
|
||||
@@ -198,6 +199,30 @@ final class UnlockedLayoutPlanner {
|
||||
carrierPlacement);
|
||||
}
|
||||
|
||||
private void sortBandsForItemOrder(
|
||||
ArrayList<UnlockedLayoutBand> bands,
|
||||
ArrayList<LayoutItemKind> itemOrder
|
||||
) {
|
||||
if (bands == null || bands.size() < 2 || itemOrder == null || itemOrder.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
ArrayList<UnlockedLayoutBand> originalOrder = new ArrayList<>(bands);
|
||||
bands.sort((left, right) -> {
|
||||
int orderComparison = Integer.compare(
|
||||
orderIndex(itemOrder, left != null ? left.kind : null),
|
||||
orderIndex(itemOrder, right != null ? right.kind : null));
|
||||
if (orderComparison != 0) {
|
||||
return orderComparison;
|
||||
}
|
||||
return Integer.compare(originalOrder.indexOf(left), originalOrder.indexOf(right));
|
||||
});
|
||||
}
|
||||
|
||||
private int orderIndex(ArrayList<LayoutItemKind> itemOrder, LayoutItemKind kind) {
|
||||
int index = itemOrder != null ? itemOrder.indexOf(kind) : -1;
|
||||
return index >= 0 ? index : Integer.MAX_VALUE;
|
||||
}
|
||||
|
||||
private void solveWithPackedLayout(
|
||||
View root,
|
||||
LayoutEdges edges,
|
||||
@@ -495,19 +520,25 @@ final class UnlockedLayoutPlanner {
|
||||
return null;
|
||||
}
|
||||
Bounds bounds = ViewGeometry.boundsRelativeTo(root, collectedIcons.carrierView);
|
||||
if (bounds == null || bounds.width <= 0 || bounds.height <= 0) {
|
||||
return null;
|
||||
Bounds anchorBounds = bounds != null
|
||||
? bounds
|
||||
: ViewGeometry.boundsRelativeTo(root, collectedIcons.clockView);
|
||||
if (anchorBounds == null || anchorBounds.height <= 0) {
|
||||
anchorBounds = new Bounds(0, 0, Math.max(0, root.getWidth()), Math.max(1, root.getHeight()));
|
||||
}
|
||||
int sourceHeight = collectedIcons.carrierView.getHeight() > 0
|
||||
? collectedIcons.carrierView.getHeight()
|
||||
: collectedIcons.carrierView.getMeasuredHeight();
|
||||
int baseline = collectedIcons.carrierView.getBaseline() > 0
|
||||
? collectedIcons.carrierView.getBaseline()
|
||||
: Math.max(0, (bounds.height * 3) / 4);
|
||||
: Math.max(0, ((sourceHeight > 0 ? sourceHeight : anchorBounds.height) * 3) / 4);
|
||||
int verticalOffset = offsetScaler.clock(
|
||||
settings.layoutCarrierVerticalOffsetPx,
|
||||
collectedIcons.carrierView);
|
||||
return ClockLayout.simpleText(
|
||||
collectedIcons.carrierView,
|
||||
positionFor(settings.layoutCarrierPosition),
|
||||
bounds.top + baseline - verticalOffset);
|
||||
anchorBounds.top + baseline - verticalOffset);
|
||||
}
|
||||
|
||||
private int statusCountForScene(SbtSettings settings, SceneKey scene) {
|
||||
@@ -707,6 +738,7 @@ final class UnlockedLayoutPlanner {
|
||||
) {
|
||||
int left = firstUsableInset(
|
||||
rootWidth,
|
||||
leftInset(root, anchors != null ? anchors.clockView : null),
|
||||
leftInset(root, anchors != null ? anchors.clockContainer : null),
|
||||
leftInset(root, anchors != null ? anchors.notificationRoot : null),
|
||||
root != null ? root.getPaddingLeft() : 0);
|
||||
|
||||
+4
@@ -28,6 +28,10 @@ final class UnlockedStockSourceCollector {
|
||||
if (cached != null && cached.isUsable()) {
|
||||
return cached;
|
||||
}
|
||||
return refreshAnchors(root);
|
||||
}
|
||||
|
||||
RootAnchors refreshAnchors(View root) {
|
||||
RootAnchors anchors = discoverAnchors(root);
|
||||
anchorsByRoot.put(root, anchors);
|
||||
return anchors;
|
||||
|
||||
@@ -3,7 +3,6 @@ package se.ajpanton.statusbartweak.shell.settings;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
@@ -862,60 +861,6 @@ public final class SbtSettings {
|
||||
}
|
||||
}
|
||||
|
||||
public static void restoreCredentialProtectedPreferences(Context context) {
|
||||
if (context == null || Build.VERSION.SDK_INT < 24) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
Context deviceContext = context.createDeviceProtectedStorageContext();
|
||||
if (deviceContext == null) {
|
||||
return;
|
||||
}
|
||||
SharedPreferences devicePrefs = deviceContext.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE);
|
||||
Map<String, ?> deviceValues = devicePrefs.getAll();
|
||||
if (deviceValues == null || deviceValues.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
SharedPreferences normalPrefs = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE);
|
||||
Map<String, ?> normalValues = normalPrefs.getAll();
|
||||
SharedPreferences.Editor editor = normalPrefs.edit();
|
||||
boolean changed = false;
|
||||
for (Map.Entry<String, ?> entry : deviceValues.entrySet()) {
|
||||
String key = entry.getKey();
|
||||
if (key == null || normalValues.containsKey(key)) {
|
||||
continue;
|
||||
}
|
||||
Object value = entry.getValue();
|
||||
if (value instanceof Boolean bool) {
|
||||
editor.putBoolean(key, bool);
|
||||
} else if (value instanceof Integer integer) {
|
||||
editor.putInt(key, integer);
|
||||
} else if (value instanceof Long longValue) {
|
||||
editor.putLong(key, longValue);
|
||||
} else if (value instanceof Float floatValue) {
|
||||
editor.putFloat(key, floatValue);
|
||||
} else if (value instanceof String string) {
|
||||
editor.putString(key, string);
|
||||
} else if (value instanceof Set<?> set) {
|
||||
HashSet<String> strings = new HashSet<>();
|
||||
for (Object item : set) {
|
||||
if (item instanceof String stringItem) {
|
||||
strings.add(stringItem);
|
||||
}
|
||||
}
|
||||
editor.putStringSet(key, strings);
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
changed = true;
|
||||
}
|
||||
if (changed) {
|
||||
editor.commit();
|
||||
}
|
||||
} catch (Throwable ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean hasSettingsProvider(Context context) {
|
||||
if (context == null) {
|
||||
return false;
|
||||
|
||||
@@ -35,7 +35,6 @@ public class SbtSettingsProvider extends ContentProvider {
|
||||
if (ctx == null) {
|
||||
return null;
|
||||
}
|
||||
SbtSettings.restoreCredentialProtectedPreferences(ctx);
|
||||
SharedPreferences prefs = ctx.getSharedPreferences(SbtSettings.PREFS_NAME, Context.MODE_PRIVATE);
|
||||
if (METHOD_GET_UNLOCKED.equals(method)) {
|
||||
int value = prefs.getInt(SbtSettings.KEY_UNLOCKED_MAX_ICONS_PER_ROW,
|
||||
|
||||
@@ -9,21 +9,23 @@ import android.view.MenuItem;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.ActionBarDrawerToggle;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.core.graphics.Insets;
|
||||
import androidx.core.view.GravityCompat;
|
||||
import androidx.drawerlayout.widget.DrawerLayout;
|
||||
import androidx.core.view.ViewCompat;
|
||||
import androidx.core.view.WindowInsetsCompat;
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import com.google.android.material.appbar.MaterialToolbar;
|
||||
import com.google.android.material.navigation.NavigationView;
|
||||
|
||||
import se.ajpanton.statusbartweak.R;
|
||||
import se.ajpanton.statusbartweak.shell.settings.SbtSettings;
|
||||
|
||||
public class MainActivity extends AppCompatActivity implements NavigationView.OnNavigationItemSelectedListener {
|
||||
private static final String EXTRA_OPEN_NAV_ITEM = "open_nav_item";
|
||||
|
||||
private DrawerLayout drawerLayout;
|
||||
private SafeInsetDrawerLayout drawerLayout;
|
||||
private NavigationView navigationView;
|
||||
private Integer navigationBasePaddingLeft;
|
||||
|
||||
public static Intent newOpenDebugIntent(Context context) {
|
||||
Intent intent = new Intent(context, MainActivity.class);
|
||||
@@ -35,7 +37,6 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
SbtSettings.restoreCredentialProtectedPreferences(this);
|
||||
setContentView(R.layout.activity_main);
|
||||
|
||||
MaterialToolbar toolbar = findViewById(R.id.toolbar);
|
||||
@@ -45,6 +46,7 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
|
||||
navigationView = findViewById(R.id.nav_view);
|
||||
navigationView.setNavigationItemSelectedListener(this);
|
||||
navigationView.getMenu().setGroupCheckable(0, true, true);
|
||||
applyNavigationDrawerInsets();
|
||||
|
||||
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
|
||||
this,
|
||||
@@ -182,4 +184,41 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
|
||||
intent.removeExtra(EXTRA_OPEN_NAV_ITEM);
|
||||
}
|
||||
}
|
||||
|
||||
private void applyNavigationDrawerInsets() {
|
||||
drawerLayout.addOnLayoutChangeListener((view, left, top, right, bottom,
|
||||
oldLeft, oldTop, oldRight, oldBottom) ->
|
||||
applyNavigationDrawerMarginsFromRootInsets());
|
||||
drawerLayout.post(this::applyNavigationDrawerMarginsFromRootInsets);
|
||||
}
|
||||
|
||||
private void applyNavigationDrawerMarginsFromRootInsets() {
|
||||
WindowInsetsCompat insets = ViewCompat.getRootWindowInsets(drawerLayout);
|
||||
if (insets == null) {
|
||||
return;
|
||||
}
|
||||
Insets safeInsets = insets.getInsetsIgnoringVisibility(
|
||||
WindowInsetsCompat.Type.systemBars() | WindowInsetsCompat.Type.displayCutout());
|
||||
applyNavigationDrawerSafeArea(safeInsets.left, safeInsets.right);
|
||||
}
|
||||
|
||||
private void applyNavigationDrawerSafeArea(int leftInset, int rightInset) {
|
||||
int safeLeft = Math.max(Math.max(0, leftInset), Math.max(0, drawerLayout.getPaddingLeft()));
|
||||
int safeRight = Math.max(Math.max(0, rightInset), Math.max(0, drawerLayout.getPaddingRight()));
|
||||
drawerLayout.setDrawerSafeInsets(safeLeft, safeRight);
|
||||
if (navigationBasePaddingLeft == null) {
|
||||
navigationBasePaddingLeft = navigationView.getPaddingLeft();
|
||||
}
|
||||
int leftPadding = navigationBasePaddingLeft + safeLeft;
|
||||
if (navigationView.getPaddingLeft() != leftPadding
|
||||
|| Math.round(navigationView.getTranslationX()) != 0) {
|
||||
navigationView.setTranslationX(0f);
|
||||
navigationView.setPadding(
|
||||
leftPadding,
|
||||
navigationView.getPaddingTop(),
|
||||
navigationView.getPaddingRight(),
|
||||
navigationView.getPaddingBottom());
|
||||
navigationView.requestLayout();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
package se.ajpanton.statusbartweak.shell.ui;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Canvas;
|
||||
import android.util.AttributeSet;
|
||||
|
||||
import androidx.drawerlayout.widget.DrawerLayout;
|
||||
|
||||
public class SafeInsetDrawerLayout extends DrawerLayout {
|
||||
private int safeInsetLeft;
|
||||
private int safeInsetRight;
|
||||
|
||||
public SafeInsetDrawerLayout(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public SafeInsetDrawerLayout(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
public SafeInsetDrawerLayout(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
}
|
||||
|
||||
public void setDrawerSafeInsets(int left, int right) {
|
||||
int safeLeft = Math.max(0, left);
|
||||
int safeRight = Math.max(0, right);
|
||||
if (safeInsetLeft == safeLeft && safeInsetRight == safeRight) {
|
||||
return;
|
||||
}
|
||||
safeInsetLeft = safeLeft;
|
||||
safeInsetRight = safeRight;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void dispatchDraw(Canvas canvas) {
|
||||
if (safeInsetLeft == 0 && safeInsetRight == 0) {
|
||||
super.dispatchDraw(canvas);
|
||||
return;
|
||||
}
|
||||
int save = canvas.save();
|
||||
canvas.clipRect(
|
||||
safeInsetLeft,
|
||||
0,
|
||||
Math.max(safeInsetLeft, getWidth() - safeInsetRight),
|
||||
getHeight());
|
||||
super.dispatchDraw(canvas);
|
||||
canvas.restoreToCount(save);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.drawerlayout.widget.DrawerLayout
|
||||
<se.ajpanton.statusbartweak.shell.ui.SafeInsetDrawerLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/drawer_layout"
|
||||
@@ -38,4 +38,4 @@
|
||||
app:itemTextColor="@color/drawer_item_text_color"
|
||||
app:menu="@menu/drawer_menu" />
|
||||
|
||||
</androidx.drawerlayout.widget.DrawerLayout>
|
||||
</se.ajpanton.statusbartweak.shell.ui.SafeInsetDrawerLayout>
|
||||
|
||||
Reference in New Issue
Block a user