13 Commits
23 changed files with 1381 additions and 811 deletions
@@ -0,0 +1,27 @@
package se.ajpanton.statusbartweak.runtime;
public final class RuntimeMutationGuard {
private static final ThreadLocal<Integer> SNAPSHOT_RENDER_DEPTH =
ThreadLocal.withInitial(() -> 0);
private RuntimeMutationGuard() {
}
public static void enterSnapshotRenderMutation() {
SNAPSHOT_RENDER_DEPTH.set(SNAPSHOT_RENDER_DEPTH.get() + 1);
}
public static void exitSnapshotRenderMutation() {
int depth = SNAPSHOT_RENDER_DEPTH.get() - 1;
if (depth <= 0) {
SNAPSHOT_RENDER_DEPTH.remove();
} else {
SNAPSHOT_RENDER_DEPTH.set(depth);
}
}
public static boolean isSnapshotRenderMutation() {
Integer depth = SNAPSHOT_RENDER_DEPTH.get();
return depth != null && depth > 0;
}
}
@@ -12,8 +12,11 @@ import android.graphics.Path;
import android.graphics.PathMeasure; import android.graphics.PathMeasure;
import android.graphics.PixelFormat; import android.graphics.PixelFormat;
import android.graphics.Rect; import android.graphics.Rect;
import android.graphics.RectF;
import android.os.BatteryManager; import android.os.BatteryManager;
import android.util.DisplayMetrics;
import android.view.Gravity; import android.view.Gravity;
import android.view.RoundedCorner;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.view.ViewParent; import android.view.ViewParent;
@@ -384,12 +387,7 @@ final class BatteryBarController {
return; return;
} }
SbtSettings settings = RuntimeSettingsCache.get(root.getContext()); SbtSettings settings = RuntimeSettingsCache.get(root.getContext());
if (!settings.batteryBarEnabled || root.getWidth() <= 0 || root.getHeight() <= 0) { if (root.getWidth() <= 0 || root.getHeight() <= 0) {
removeBatteryBarView(root);
return;
}
int color = resolveBarColor(root, settings);
if (!shouldRenderOnRoot(root)) {
removeBatteryBarView(root); removeBatteryBarView(root);
return; return;
} }
@@ -400,6 +398,15 @@ final class BatteryBarController {
if (transientStatusBarReveal) { if (transientStatusBarReveal) {
scenario = visibleStatusBarScenarioForRoot(root); scenario = visibleStatusBarScenarioForRoot(root);
} }
if (!isBatteryBarEnabled(settings, scenario)) {
removeBatteryBarView(root);
return;
}
int color = resolveBarColor(root, settings);
if (!shouldRenderOnRoot(root)) {
removeBatteryBarView(root);
return;
}
BatteryBarGeometry geometry = BatteryBarGeometry.resolve(settings, scenario); BatteryBarGeometry geometry = BatteryBarGeometry.resolve(settings, scenario);
if (isFullscreenScenario(scenario)) { if (isFullscreenScenario(scenario)) {
removeEmbeddedBatteryBarView(root); removeEmbeddedBatteryBarView(root);
@@ -541,6 +548,7 @@ final class BatteryBarController {
+ plugged + "|" + plugged + "|"
+ color + "|" + color + "|"
+ settings.batteryBarEnabled + "|" + settings.batteryBarEnabled + "|"
+ settings.batteryBarScenarioEnabled + "|"
+ settings.batteryBarPosition + "|" + settings.batteryBarPosition + "|"
+ settings.batteryBarAlignment + "|" + settings.batteryBarAlignment + "|"
+ settings.batteryBarThicknessDp + "|" + settings.batteryBarThicknessDp + "|"
@@ -577,6 +585,21 @@ final class BatteryBarController {
: BatteryBarGeometry.Scenario.UNLOCKED_PORTRAIT; : BatteryBarGeometry.Scenario.UNLOCKED_PORTRAIT;
} }
private boolean isBatteryBarEnabled(
SbtSettings settings,
BatteryBarGeometry.Scenario scenario
) {
if (settings == null || scenario == null) {
return false;
}
if (scenario == BatteryBarGeometry.Scenario.UNLOCKED_PORTRAIT
|| scenario == BatteryBarGeometry.Scenario.UNLOCKED_LANDSCAPE) {
return settings.batteryBarEnabled;
}
Boolean scenarioEnabled = settings.batteryBarScenarioEnabled.get(scenario.id);
return scenarioEnabled == null || scenarioEnabled;
}
private BatteryBarGeometry.Scenario visibleStatusBarScenarioForRoot(View root) { private BatteryBarGeometry.Scenario visibleStatusBarScenarioForRoot(View root) {
boolean landscape = isLandscapeForRoot(root, isFullscreenSystemBarState()); boolean landscape = isLandscapeForRoot(root, isFullscreenSystemBarState());
if (isPhoneRoot(root) && isUnlockedScene() && isTransparentStatusBarActive()) { if (isPhoneRoot(root) && isUnlockedScene() && isTransparentStatusBarActive()) {
@@ -1015,7 +1038,6 @@ final class BatteryBarController {
private final Path fullCurvePath = new Path(); private final Path fullCurvePath = new Path();
private final Path drawPath = new Path(); private final Path drawPath = new Path();
private final PathMeasure pathMeasure = new PathMeasure(); private final PathMeasure pathMeasure = new PathMeasure();
private final float[] pathPoint = new float[2];
private ViewGroup host; private ViewGroup host;
private SbtSettings settings; private SbtSettings settings;
private BatteryBarGeometry geometry; private BatteryBarGeometry geometry;
@@ -1063,7 +1085,18 @@ final class BatteryBarController {
? geometry ? geometry
: BatteryBarGeometry.global(settings); : BatteryBarGeometry.global(settings);
int thickness = Math.max(1, dpToPx(getContext(), activeGeometry.thicknessDp)); int thickness = Math.max(1, dpToPx(getContext(), activeGeometry.thicknessDp));
int edgeOffset = Math.max(0, dpToPx(getContext(), settings.batteryBarEdgeOffsetDp)); int edgeOffset = Math.max(0, dpToPx(getContext(), activeGeometry.edgeOffsetDp));
float fraction = resolveFraction(batteryLevel, settings);
if (shouldDrawCurvedTop(activeGeometry)) {
buildCurvedPath(
width,
height,
thickness,
edgeOffset,
fraction,
activeGeometry.alignment);
return;
}
int left = edgeOffset; int left = edgeOffset;
int right = width - edgeOffset; int right = width - edgeOffset;
if (right <= left) { if (right <= left) {
@@ -1074,11 +1107,6 @@ final class BatteryBarController {
if (bottom <= top) { if (bottom <= top) {
return; return;
} }
float fraction = resolveFraction(batteryLevel, settings);
if (shouldDrawCurvedTop(activeGeometry)) {
buildCurvedPath(left, right, height, thickness, fraction, activeGeometry.alignment);
return;
}
int availableWidth = right - left; int availableWidth = right - left;
int barWidth = Math.round(availableWidth * fraction); int barWidth = Math.round(availableWidth * fraction);
if (barWidth <= 0) { if (barWidth <= 0) {
@@ -1100,53 +1128,47 @@ final class BatteryBarController {
return false; return false;
} }
return !SbtSettings.BATTERY_BAR_CURVED_GEOMETRY_OFF.equals( return !SbtSettings.BATTERY_BAR_CURVED_GEOMETRY_OFF.equals(
settings.batteryBarCurvedGeometryMode); geometry.curvedGeometryMode);
} }
private void buildCurvedPath( private void buildCurvedPath(
int left, int width,
int right,
int height, int height,
int thickness, int thickness,
int edgeOffset,
float fraction, float fraction,
String alignment String alignment
) { ) {
if (fraction <= 0f || right <= left || height <= 0 || thickness <= 0) { if (fraction <= 0f || width <= 0 || height <= 0 || thickness <= 0) {
return; return;
} }
float halfStroke = thickness / 2f; buildFullCurvePath(width, height, thickness);
float leftCenter = left + halfStroke;
float rightCenter = right - halfStroke;
if (rightCenter <= leftCenter) {
return;
}
buildFullCurvePath(leftCenter, rightCenter, height, thickness);
pathMeasure.setPath(fullCurvePath, false); pathMeasure.setPath(fullCurvePath, false);
float fullLength = pathMeasure.getLength(); float fullLength = pathMeasure.getLength();
if (fullLength <= 0f) { if (fullLength <= 0f) {
return; return;
} }
float targetLength = SbtSettings.BATTERY_BAR_CURVED_GEOMETRY_LENGTH.equals( float pathOffset = Math.min(Math.max(0f, edgeOffset), fullLength / 2f);
settings.batteryBarCurvedGeometryMode) float usableStart = pathOffset;
? fullLength * fraction float usableEnd = fullLength - pathOffset;
: targetDistanceForHorizontalFraction( float usableLength = usableEnd - usableStart;
leftCenter, if (usableLength <= 0f) {
rightCenter, return;
fullLength, }
fraction); float targetLength = usableLength * fraction;
if (targetLength <= 0f) { if (targetLength <= 0f) {
return; return;
} }
targetLength = Math.min(fullLength, targetLength); targetLength = Math.min(usableLength, targetLength);
float start = 0f; float start = usableStart;
float end = targetLength; float end = usableStart + targetLength;
if ("rtl".equals(alignment)) { if ("rtl".equals(alignment)) {
start = fullLength - targetLength; start = usableEnd - targetLength;
end = fullLength; end = usableEnd;
} else if ("center".equals(alignment)) { } else if ("center".equals(alignment)) {
float center = fullLength / 2f; float center = (usableStart + usableEnd) / 2f;
start = Math.max(0f, center - targetLength / 2f); start = Math.max(usableStart, center - targetLength / 2f);
end = Math.min(fullLength, center + targetLength / 2f); end = Math.min(usableEnd, center + targetLength / 2f);
} }
if (end <= start) { if (end <= start) {
return; return;
@@ -1156,64 +1178,119 @@ final class BatteryBarController {
pathStrokeWidth = thickness; pathStrokeWidth = thickness;
} }
private void buildFullCurvePath(float left, float right, int height, int thickness) { private void buildFullCurvePath(int width, int height, int thickness) {
fullCurvePath.reset(); fullCurvePath.reset();
float halfStroke = thickness / 2f; float halfStroke = thickness / 2f;
if (width <= thickness) {
return;
}
float topY = halfStroke; float topY = halfStroke;
float bottomY = Math.max(topY, height - halfStroke); float bottomY = Math.max(topY, height - halfStroke);
float verticalSpan = bottomY - topY; float verticalSpan = bottomY - topY;
float radius = Math.min(verticalSpan, (right - left) / 2f); float outerRadius = Math.min(
fullCurvePath.moveTo(left, bottomY); resolveTopCornerRadius(verticalSpan + halfStroke),
if (radius <= 0f) { width / 2f);
fullCurvePath.lineTo(right, topY); float curveRadius = outerRadius - halfStroke;
if (curveRadius <= 0f) {
buildSharpTopPath(width, topY, bottomY, halfStroke);
return; return;
} }
fullCurvePath.lineTo(left, topY + radius); float leftTopX = outerRadius;
fullCurvePath.quadTo(left, topY, left + radius, topY); float rightTopX = width - outerRadius;
fullCurvePath.lineTo(right - radius, topY); if (rightTopX <= leftTopX) {
fullCurvePath.quadTo(right, topY, right, topY + radius); buildSharpTopPath(width, topY, bottomY, halfStroke);
fullCurvePath.lineTo(right, bottomY); return;
}
RectF leftCorner = new RectF(
halfStroke,
halfStroke,
outerRadius + curveRadius,
outerRadius + curveRadius);
RectF rightCorner = new RectF(
width - outerRadius - curveRadius,
halfStroke,
width - halfStroke,
outerRadius + curveRadius);
float leftStartAngle = leftCornerStartAngle(bottomY, outerRadius, curveRadius);
float leftStartX = cornerX(leftCorner.centerX(), curveRadius, leftStartAngle);
float leftStartY = cornerY(leftCorner.centerY(), curveRadius, leftStartAngle);
fullCurvePath.moveTo(halfStroke, bottomY);
fullCurvePath.lineTo(leftStartX, leftStartY);
fullCurvePath.arcTo(leftCorner, leftStartAngle, 270f - leftStartAngle);
fullCurvePath.lineTo(rightTopX, topY);
float rightEndAngle = rightCornerEndAngle(bottomY, outerRadius, curveRadius);
fullCurvePath.arcTo(rightCorner, 270f, rightEndAngle - 270f);
fullCurvePath.lineTo(width - halfStroke, bottomY);
} }
private float targetDistanceForHorizontalFraction( private float resolveTopCornerRadius(float fallback) {
float left, WindowInsets insets = getRootWindowInsets();
float right, if (insets == null) {
float fullLength, return fallback;
float fraction
) {
if (fraction >= 1f) {
return fullLength;
} }
float horizontalSpan = right - left; int leftRadius = roundedCornerRadius(insets, RoundedCorner.POSITION_TOP_LEFT);
if (horizontalSpan <= 0f) { int rightRadius = roundedCornerRadius(insets, RoundedCorner.POSITION_TOP_RIGHT);
return fullLength * fraction; if (leftRadius > 0 && rightRadius > 0) {
return Math.min(leftRadius, rightRadius);
}
if (leftRadius > 0 || rightRadius > 0) {
return Math.max(leftRadius, rightRadius);
} }
float targetHorizontal = horizontalSpan * fraction;
if (targetHorizontal <= 0f) {
return 0f; return 0f;
} }
int steps = Math.max(32, Math.min(512, Math.round(fullLength / 2f)));
float previousDistance = 0f; private int roundedCornerRadius(WindowInsets insets, int position) {
float previousX = left; RoundedCorner corner = insets.getRoundedCorner(position);
float accumulatedHorizontal = 0f; if (corner == null) {
for (int step = 1; step <= steps; step++) { return 0;
float distance = fullLength * step / steps;
if (!pathMeasure.getPosTan(distance, pathPoint, null)) {
continue;
} }
float dx = Math.abs(pathPoint[0] - previousX); return stableDensityRadius(Math.max(0, corner.getRadius()));
if (accumulatedHorizontal + dx >= targetHorizontal) {
if (dx <= 0f) {
return distance;
} }
float ratio = (targetHorizontal - accumulatedHorizontal) / dx;
return previousDistance + (distance - previousDistance) * ratio; private int stableDensityRadius(int radius) {
if (radius <= 0 || getResources() == null) {
return radius;
} }
accumulatedHorizontal += dx; DisplayMetrics metrics = getResources().getDisplayMetrics();
previousDistance = distance; int currentDpi = metrics != null ? metrics.densityDpi : 0;
previousX = pathPoint[0]; int stableDpi = DisplayMetrics.DENSITY_DEVICE_STABLE;
if (currentDpi <= 0 || stableDpi <= 0 || currentDpi == stableDpi) {
return radius;
} }
return fullLength; return Math.max(1, Math.round(radius * (stableDpi / (float) currentDpi)));
}
private void buildSharpTopPath(int width, float topY, float bottomY, float halfStroke) {
fullCurvePath.moveTo(halfStroke, bottomY);
fullCurvePath.lineTo(halfStroke, topY);
fullCurvePath.lineTo(width - halfStroke, topY);
fullCurvePath.lineTo(width - halfStroke, bottomY);
}
private float leftCornerStartAngle(float bottomY, float outerRadius, float curveRadius) {
if (bottomY >= outerRadius) {
return 180f;
}
float ratio = Math.max(-1f, Math.min(1f, (outerRadius - bottomY) / curveRadius));
return 180f + (float) Math.toDegrees(Math.asin(ratio));
}
private float rightCornerEndAngle(float bottomY, float outerRadius, float curveRadius) {
if (bottomY >= outerRadius) {
return 360f;
}
float ratio = Math.max(-1f, Math.min(1f, (outerRadius - bottomY) / curveRadius));
return 360f - (float) Math.toDegrees(Math.asin(ratio));
}
private float cornerX(float centerX, float radius, float angleDegrees) {
return centerX + radius * (float) Math.cos(Math.toRadians(angleDegrees));
}
private float cornerY(float centerY, float radius, float angleDegrees) {
return centerY + radius * (float) Math.sin(Math.toRadians(angleDegrees));
} }
private int resolveTop(BatteryBarGeometry geometry, int thickness, int height) { private int resolveTop(BatteryBarGeometry geometry, int thickness, int height) {
@@ -153,7 +153,7 @@ final class StockClockController {
} }
runtimeContext.getModeStateRepository().addLayoutEnabledListener(enabled -> { runtimeContext.getModeStateRepository().addLayoutEnabledListener(enabled -> {
if (enabled) { if (enabled) {
restoreAllOwnedClocks(); suspendOwnedClockTickers();
} else { } else {
refreshAllClocks(); refreshAllClocks();
} }
@@ -212,23 +212,22 @@ final class StockClockController {
} }
} }
private void removeAllRowOverlays() { private void suspendOwnedClockTickers() {
for (TextView clockView : new ArrayList<>(trackedClocks)) { for (TextView clockView : new ArrayList<>(ownedClocks)) {
removeRowOverlay(clockView); stopTicker(clockView);
} }
} }
private void restoreAllOwnedClocks() {
for (TextView clockView : new ArrayList<>(trackedClocks)) {
restoreOwnedClock(clockView);
}
removeAllRowOverlays();
}
private void applyClockText(TextView clockView) { private void applyClockText(TextView clockView) {
SbtSettings settings = RuntimeSettingsCache.get(clockView.getContext()); SbtSettings settings = RuntimeSettingsCache.get(clockView.getContext());
boolean layoutEnabled = settings.clockEnabled; boolean layoutEnabled = settings.clockEnabled;
if (layoutEnabled || !hasCustomClockTextEnabled(settings)) { if (layoutEnabled) {
if (ownedClocks.contains(clockView)) {
stopTicker(clockView);
}
return;
}
if (!hasCustomClockTextEnabled(settings)) {
restoreOwnedClock(clockView); restoreOwnedClock(clockView);
return; return;
} }
@@ -237,6 +237,9 @@ final class StockUnlockedNotificationIconsController {
} }
private boolean shouldManageContainer(View view) { private boolean shouldManageContainer(View view) {
if (!isFeatureEnabled(view.getContext())) {
return false;
}
if (!isUnlockedScene()) { if (!isUnlockedScene()) {
return false; return false;
} }
@@ -10,6 +10,7 @@ import android.graphics.drawable.Drawable;
import android.os.Looper; import android.os.Looper;
import android.os.PowerManager; import android.os.PowerManager;
import android.service.notification.StatusBarNotification; import android.service.notification.StatusBarNotification;
import android.telecom.TelecomManager;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.ImageView; import android.widget.ImageView;
@@ -34,6 +35,7 @@ import java.util.WeakHashMap;
import java.util.function.Function; import java.util.function.Function;
import se.ajpanton.statusbartweak.runtime.NotificationKeyReflection; import se.ajpanton.statusbartweak.runtime.NotificationKeyReflection;
import se.ajpanton.statusbartweak.runtime.RuntimeMutationGuard;
import se.ajpanton.statusbartweak.runtime.ViewIdNames; import se.ajpanton.statusbartweak.runtime.ViewIdNames;
import se.ajpanton.statusbartweak.runtime.features.RuntimeContext; import se.ajpanton.statusbartweak.runtime.features.RuntimeContext;
import se.ajpanton.statusbartweak.runtime.hooks.ReflectionSupport; import se.ajpanton.statusbartweak.runtime.hooks.ReflectionSupport;
@@ -405,6 +407,9 @@ final class StockLayoutCanvasController {
Object target = chain.getThisObject(); Object target = chain.getThisObject();
Object alphaArg = firstArg(chain.getArgs()); Object alphaArg = firstArg(chain.getArgs());
if (target instanceof View view && alphaArg instanceof Float alpha) { if (target instanceof View view && alphaArg instanceof Float alpha) {
if (shouldSuppressPrivacyOverlayStatusBarAlpha(view, alpha)) {
return null;
}
if (shouldSuppressConflictingShadeHeaderAlpha(view, alpha)) { if (shouldSuppressConflictingShadeHeaderAlpha(view, alpha)) {
return null; return null;
} }
@@ -450,6 +455,16 @@ final class StockLayoutCanvasController {
} }
return chain.proceed(); return chain.proceed();
}); });
XposedHookSupport.hookAllMethodsIfExists(runtimeContext.getFramework(), viewClass, "setTranslationX", chain -> {
Object target = chain.getThisObject();
Object translationArg = firstArg(chain.getArgs());
if (target instanceof View view && translationArg instanceof Float translationX) {
if (shouldSuppressPrivacyOverlayStatusBarTranslationX(view, translationX)) {
return null;
}
}
return chain.proceed();
});
XposedHookSupport.hookAllMethodsIfExists(runtimeContext.getFramework(), viewClass, "layout", chain -> { XposedHookSupport.hookAllMethodsIfExists(runtimeContext.getFramework(), viewClass, "layout", chain -> {
Object target = chain.getThisObject(); Object target = chain.getThisObject();
List<Object> args = chain.getArgs(); List<Object> args = chain.getArgs();
@@ -1491,6 +1506,9 @@ final class StockLayoutCanvasController {
} }
private void markStatusChipLifecycleDirtyIfNeeded(View view, View fallbackRoot) { private void markStatusChipLifecycleDirtyIfNeeded(View view, View fallbackRoot) {
if (RuntimeMutationGuard.isSnapshotRenderMutation()) {
return;
}
if (view == null || !isStatusChipCandidate(view)) { if (view == null || !isStatusChipCandidate(view)) {
View root = view != null ? unlockedStatusBarRootFor(view) : fallbackRoot; View root = view != null ? unlockedStatusBarRootFor(view) : fallbackRoot;
if (deferDrawerStatusChipRefresh(root)) { if (deferDrawerStatusChipRefresh(root)) {
@@ -2437,8 +2455,7 @@ final class StockLayoutCanvasController {
} }
if (!isTrackableStatusChipSurface(view) if (!isTrackableStatusChipSurface(view)
&& !isTrackedHiddenStatusChipSource(root, view)) { && !isTrackedHiddenStatusChipSource(root, view)) {
hiddenViewStates.remove(view); forgetTrackedStatusChipState(view);
trackedUnlockedStockSurfaces.remove(view);
staleViews.add(view); staleViews.add(view);
continue; continue;
} }
@@ -2989,6 +3006,7 @@ final class StockLayoutCanvasController {
private boolean isTrackedStatusChipWriteTarget(View view) { private boolean isTrackedStatusChipWriteTarget(View view) {
if (view == null if (view == null
|| ownHiddenViewAlphaWriteDepth > 0 || ownHiddenViewAlphaWriteDepth > 0
|| RuntimeMutationGuard.isSnapshotRenderMutation()
|| !trackedStatusChipSources.contains(view) || !trackedStatusChipSources.contains(view)
|| !hiddenViewStates.containsKey(view) || !hiddenViewStates.containsKey(view)
|| !view.isAttachedToWindow() || !view.isAttachedToWindow()
@@ -3008,6 +3026,7 @@ final class StockLayoutCanvasController {
private boolean isStatusChipShellWriteTarget(View view) { private boolean isStatusChipShellWriteTarget(View view) {
if (view == null if (view == null
|| ownHiddenViewAlphaWriteDepth > 0 || ownHiddenViewAlphaWriteDepth > 0
|| RuntimeMutationGuard.isSnapshotRenderMutation()
|| !view.isAttachedToWindow() || !view.isAttachedToWindow()
|| !isLayoutEnabled(view.getContext()) || !isLayoutEnabled(view.getContext())
|| !isStatusChipShell(view)) { || !isStatusChipShell(view)) {
@@ -3344,6 +3363,60 @@ final class StockLayoutCanvasController {
return true; return true;
} }
private boolean shouldSuppressPrivacyOverlayStatusBarAlpha(View view, float alpha) {
if (alpha >= 0.99f
|| ownHiddenViewAlphaWriteDepth > 0
|| !isPhoneStatusBarRoot(view)
|| !isLayoutEnabled(view.getContext())
|| ongoingPrivacyChipInRoot(view) == null) {
return false;
}
return true;
}
private boolean shouldSuppressPrivacyOverlayStatusBarTranslationX(View view, float translationX) {
if (Math.abs(translationX) < 0.5f
|| ownHiddenViewAlphaWriteDepth > 0
|| !isPhoneStatusBarRoot(view)
|| !isLayoutEnabled(view.getContext())
|| ongoingPrivacyChipInRoot(view) == null) {
return false;
}
return true;
}
private boolean isPhoneStatusBarRoot(View view) {
return view != null
&& view.getClass().getName().contains("PhoneStatusBarView");
}
private boolean isOngoingPrivacyChip(View view) {
return view != null
&& view.getClass().getName().contains("OngoingPrivacyChip")
&& "privacy_chip".equals(ViewIdNames.idName(view));
}
private View ongoingPrivacyChipInRoot(View view) {
View root = view != null ? view.getRootView() : null;
if (!(root instanceof ViewGroup group)) {
return null;
}
ArrayDeque<View> queue = new ArrayDeque<>();
queue.add(group);
while (!queue.isEmpty()) {
View current = queue.removeFirst();
if (isOngoingPrivacyChip(current)) {
return current;
}
if (current instanceof ViewGroup childGroup) {
for (int i = 0; i < childGroup.getChildCount(); i++) {
queue.addLast(childGroup.getChildAt(i));
}
}
}
return null;
}
private boolean isStatusChipSource(View view) { private boolean isStatusChipSource(View view) {
if (view == null || view.getVisibility() != View.VISIBLE) { if (view == null || view.getVisibility() != View.VISIBLE) {
return false; return false;
@@ -3384,6 +3457,9 @@ final class StockLayoutCanvasController {
if (view == null || ownedIconHostManager.isOwnedHost(view)) { if (view == null || ownedIconHostManager.isOwnedHost(view)) {
return false; return false;
} }
if (view.getVisibility() != View.VISIBLE) {
return false;
}
String idName = ViewIdNames.idName(view); String idName = ViewIdNames.idName(view);
if (!"ongoing_activity_capsule".equals(idName)) { if (!"ongoing_activity_capsule".equals(idName)) {
return false; return false;
@@ -3412,9 +3488,26 @@ final class StockLayoutCanvasController {
|| !isStatusChipCandidate(view)) { || !isStatusChipCandidate(view)) {
return false; return false;
} }
if (isCallStatusChip(view)
&& view.getVisibility() != View.VISIBLE
&& !isPhoneCallActive(view)) {
return false;
}
return hasVisibleStatusChipContent(view); return hasVisibleStatusChipContent(view);
} }
private boolean isPhoneCallActive(View view) {
if (view == null || view.getContext() == null) {
return false;
}
try {
TelecomManager telecomManager = view.getContext().getSystemService(TelecomManager.class);
return telecomManager != null && telecomManager.isInCall();
} catch (RuntimeException ignored) {
return false;
}
}
private boolean hasVisibleStatusChipContent(View source) { private boolean hasVisibleStatusChipContent(View source) {
if (!(source instanceof ViewGroup group)) { if (!(source instanceof ViewGroup group)) {
return false; return false;
@@ -4230,11 +4323,19 @@ final class StockLayoutCanvasController {
|| isStatusChipShell(view)) { || isStatusChipShell(view)) {
return false; return false;
} }
hiddenViewStates.remove(view); forgetTrackedStatusChip(view);
return true;
}
private void forgetTrackedStatusChip(View view) {
forgetTrackedStatusChipState(view);
trackedStatusChipSources.remove(view); trackedStatusChipSources.remove(view);
}
private void forgetTrackedStatusChipState(View view) {
hiddenViewStates.remove(view);
trackedUnlockedStockSurfaces.remove(view); trackedUnlockedStockSurfaces.remove(view);
statusChipLifecycleLayoutSignatureByView.remove(view); statusChipLifecycleLayoutSignatureByView.remove(view);
return true;
} }
private void cleanupLayoutOffRoot(View root, SceneKey activeScene) { private void cleanupLayoutOffRoot(View root, SceneKey activeScene) {
@@ -11,6 +11,7 @@ import android.graphics.Path;
import android.graphics.PorterDuff; import android.graphics.PorterDuff;
import android.graphics.Rect; import android.graphics.Rect;
import android.graphics.RectF; import android.graphics.RectF;
import android.graphics.drawable.AnimationDrawable;
import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.os.BatteryManager; import android.os.BatteryManager;
@@ -35,6 +36,7 @@ import java.util.Objects;
import java.util.WeakHashMap; import java.util.WeakHashMap;
import se.ajpanton.statusbartweak.runtime.NotificationKeyReflection; import se.ajpanton.statusbartweak.runtime.NotificationKeyReflection;
import se.ajpanton.statusbartweak.runtime.RuntimeMutationGuard;
import se.ajpanton.statusbartweak.runtime.ViewIdNames; import se.ajpanton.statusbartweak.runtime.ViewIdNames;
import se.ajpanton.statusbartweak.runtime.hooks.ReflectionSupport; import se.ajpanton.statusbartweak.runtime.hooks.ReflectionSupport;
import se.ajpanton.statusbartweak.runtime.layoutsolver.StatusBarLayoutSolver.Bounds; import se.ajpanton.statusbartweak.runtime.layoutsolver.StatusBarLayoutSolver.Bounds;
@@ -238,9 +240,24 @@ final class SnapshotRenderer {
proxy.setTag(key); proxy.setTag(key);
proxyChanged = true; proxyChanged = true;
} }
SnapshotRenderState desiredState = renderStateFor(placement);
Drawable animatedDrawable = animatedNotificationDrawable(placement);
if (animatedDrawable != null) {
SnapshotRenderState currentState = statesByProxy.get(proxy);
boolean drawableChanged = !(proxy.getDrawable() instanceof AnimationDrawable)
|| !canReuseAnimatedProxy(currentState, desiredState);
if (drawableChanged) {
Drawable proxyDrawable = newDrawableInstance(animatedDrawable);
proxy.setImageDrawable(proxyDrawable);
proxyChanged = true;
}
startAnimationIfNeeded(proxy.getDrawable());
if (!desiredState.equals(currentState)) {
statesByProxy.put(proxy, desiredState);
}
} else {
BitmapResult bitmapResult = bitmapFor(proxy, bounds); BitmapResult bitmapResult = bitmapFor(proxy, bounds);
Bitmap bitmap = bitmapResult.bitmap(); Bitmap bitmap = bitmapResult.bitmap();
SnapshotRenderState desiredState = renderStateFor(placement);
boolean bitmapChanged = bitmapResult.created() boolean bitmapChanged = bitmapResult.created()
|| !desiredState.equals(statesByProxy.get(proxy)); || !desiredState.equals(statesByProxy.get(proxy));
if (bitmapChanged) { if (bitmapChanged) {
@@ -268,6 +285,7 @@ final class SnapshotRenderer {
proxy.setImageBitmap(bitmap); proxy.setImageBitmap(bitmap);
proxyChanged = true; proxyChanged = true;
} }
}
if (proxy.getAlpha() != 1f) { if (proxy.getAlpha() != 1f) {
proxy.setAlpha(1f); proxy.setAlpha(1f);
proxyChanged = true; proxyChanged = true;
@@ -304,6 +322,52 @@ final class SnapshotRenderer {
return renderedBounds; return renderedBounds;
} }
private boolean canReuseAnimatedProxy(
SnapshotRenderState currentState,
SnapshotRenderState desiredState
) {
return currentState != null
&& desiredState != null
&& Objects.equals(currentState.key(), desiredState.key())
&& currentState.width() == desiredState.width()
&& currentState.height() == desiredState.height()
&& currentState.signal() == desiredState.signal()
&& currentState.overflowDot() == desiredState.overflowDot()
&& currentState.overflowDotColor() == desiredState.overflowDotColor()
&& currentState.sourceOffsetX() == desiredState.sourceOffsetX()
&& currentState.sourceRenderBoundsSignature() == desiredState.sourceRenderBoundsSignature()
&& Objects.equals(currentState.heldSignalKey(), desiredState.heldSignalKey())
&& currentState.heldBitmapId() == desiredState.heldBitmapId()
&& currentState.sourceMode() == desiredState.sourceMode()
&& currentState.tintSignature() == desiredState.tintSignature();
}
private Drawable animatedNotificationDrawable(SnapshotPlacement placement) {
if (placement == null
|| placement.source() == null
|| placement.source().mode() != SnapshotMode.NOTIFICATION_DRAWABLE
|| !(placement.source().view() instanceof ImageView imageView)) {
return null;
}
Drawable drawable = imageView.getDrawable();
return drawable instanceof AnimationDrawable ? drawable : null;
}
private Drawable newDrawableInstance(Drawable drawable) {
Drawable.ConstantState constantState = drawable != null ? drawable.getConstantState() : null;
if (constantState != null) {
return constantState.newDrawable().mutate();
}
return drawable != null ? drawable.mutate() : null;
}
private void startAnimationIfNeeded(Drawable drawable) {
if (drawable instanceof AnimationDrawable animationDrawable && !animationDrawable.isRunning()) {
animationDrawable.setVisible(true, true);
animationDrawable.start();
}
}
void clear(ViewGroup host) { void clear(ViewGroup host) {
LinkedHashMap<String, ImageView> proxies = proxiesByHost.remove(host); LinkedHashMap<String, ImageView> proxies = proxiesByHost.remove(host);
if (proxies == null) { if (proxies == null) {
@@ -748,6 +812,8 @@ final class SnapshotRenderer {
bitmap.getHeight())) { bitmap.getHeight())) {
return; return;
} }
RuntimeMutationGuard.enterSnapshotRenderMutation();
try {
sourceView.setVisibility(View.VISIBLE); sourceView.setVisibility(View.VISIBLE);
sourceView.setAlpha(1f); sourceView.setAlpha(1f);
if (source.mode() == SnapshotMode.STATUS_CHIP) { if (source.mode() == SnapshotMode.STATUS_CHIP) {
@@ -756,8 +822,16 @@ final class SnapshotRenderer {
sourceView.draw(canvas); sourceView.draw(canvas);
} }
} finally { } finally {
RuntimeMutationGuard.exitSnapshotRenderMutation();
}
} finally {
RuntimeMutationGuard.enterSnapshotRenderMutation();
try {
sourceView.setAlpha(oldAlpha); sourceView.setAlpha(oldAlpha);
sourceView.setVisibility(oldVisibility); sourceView.setVisibility(oldVisibility);
} finally {
RuntimeMutationGuard.exitSnapshotRenderMutation();
}
} }
} }
@@ -1183,7 +1257,9 @@ final class SnapshotRenderer {
view.getRight(), view.getRight(),
view.getBottom(), view.getBottom(),
view.getMeasuredWidth(), view.getMeasuredWidth(),
view.getMeasuredHeight())); view.getMeasuredHeight(),
view.getVisibility(),
view.getAlpha()));
if (view instanceof ViewGroup group) { if (view instanceof ViewGroup group) {
for (int i = 0; i < group.getChildCount(); i++) { for (int i = 0; i < group.getChildCount(); i++) {
captureFrameState(group.getChildAt(i), state); captureFrameState(group.getChildAt(i), state);
@@ -1207,6 +1283,12 @@ final class SnapshotRenderer {
View.MeasureSpec.makeMeasureSpec(frame.measuredHeight, View.MeasureSpec.EXACTLY)); View.MeasureSpec.makeMeasureSpec(frame.measuredHeight, View.MeasureSpec.EXACTLY));
} }
view.layout(frame.left, frame.top, frame.right, frame.bottom); view.layout(frame.left, frame.top, frame.right, frame.bottom);
if (view.getAlpha() != frame.alpha) {
view.setAlpha(frame.alpha);
}
if (view.getVisibility() != frame.visibility) {
view.setVisibility(frame.visibility);
}
} }
} }
@@ -1221,7 +1303,9 @@ final class SnapshotRenderer {
int right, int right,
int bottom, int bottom,
int measuredWidth, int measuredWidth,
int measuredHeight int measuredHeight,
int visibility,
float alpha
) { ) {
} }
@@ -21,6 +21,10 @@ final class UnlockedChipPlacementController {
} }
void clear() { void clear() {
resetMissingChipFallback();
}
private void resetMissingChipFallback() {
heldPlacements = null; heldPlacements = null;
lastCollisionBounds = null; lastCollisionBounds = null;
lastRootWidth = 0; lastRootWidth = 0;
@@ -47,10 +51,11 @@ final class UnlockedChipPlacementController {
return rawPlacements; return rawPlacements;
} }
ArrayList<SnapshotPlacement> placements = isAnyChipHidingEnabled(settings) boolean hasMetricSources = metricSources != null && !metricSources.isEmpty();
ArrayList<SnapshotPlacement> placements = isAnyChipHidingEnabled(settings) || !hasMetricSources
? new ArrayList<>() ? new ArrayList<>()
: heldPlacements(root); : heldPlacements(root);
if (placements.isEmpty()) { if (placements.isEmpty() && hasMetricSources) {
placements = emptyPlacement(root, metricSources); placements = emptyPlacement(root, metricSources);
} }
return placements; return placements;
@@ -88,7 +88,13 @@ final class UnlockedLayoutPlanner {
Bounds aodStatusbarBounds = scene != null && scene.isAod() Bounds aodStatusbarBounds = scene != null && scene.isAod()
? aodStatusbarBounds(root, settings, aodNotificationBounds, aodStatusAnchorBounds) ? aodStatusbarBounds(root, settings, aodNotificationBounds, aodStatusAnchorBounds)
: null; : null;
LayoutEdges edges = layoutEdges(root, settings, anchors, scene, aodStatusAnchorBounds); LayoutEdges edges = layoutEdges(
root,
settings,
anchors,
collectedIcons,
scene,
aodStatusAnchorBounds);
int statusbarHeight = statusbarHeight(root, anchors, scene, aodStatusContentBounds); int statusbarHeight = statusbarHeight(root, anchors, scene, aodStatusContentBounds);
if (clockEnabledForScene(settings, scene) && clockLayout != null && clockLayout.width() > 0) { if (clockEnabledForScene(settings, scene) && clockLayout != null && clockLayout.width() > 0) {
bands.add(UnlockedLayoutBand.clock( bands.add(UnlockedLayoutBand.clock(
@@ -1393,6 +1399,7 @@ final class UnlockedLayoutPlanner {
View root, View root,
SbtSettings settings, SbtSettings settings,
RootAnchors anchors, RootAnchors anchors,
CollectedIcons collectedIcons,
SceneKey scene, SceneKey scene,
Bounds aodStatusAnchorBounds Bounds aodStatusAnchorBounds
) { ) {
@@ -1419,11 +1426,29 @@ final class UnlockedLayoutPlanner {
if (settings.layoutPaddingRightAddStock) { if (settings.layoutPaddingRightAddStock) {
right -= stockInsets.right; right -= stockInsets.right;
} }
if (scene != null && scene.isUnlocked() && hasStatusChipSources(collectedIcons)) {
LayoutEdges recentEdges = recentNonAodEdgesByRootWidth.get(rootWidth);
if (isReusableUnlockedEdge(left, recentEdges)) {
left = recentEdges.left();
}
}
LayoutEdges edges = new LayoutEdges(left, right); LayoutEdges edges = new LayoutEdges(left, right);
rememberNonAodEdges(rootWidth, scene, edges); rememberNonAodEdges(rootWidth, scene, edges);
return edges; return edges;
} }
private boolean hasStatusChipSources(CollectedIcons icons) {
return icons != null
&& ((icons.statusChips != null && !icons.statusChips.isEmpty())
|| (icons.statusChipMetrics != null && !icons.statusChipMetrics.isEmpty()));
}
private boolean isReusableUnlockedEdge(int currentLeft, LayoutEdges recentEdges) {
return recentEdges != null
&& recentEdges.right() > recentEdges.left()
&& Math.abs(currentLeft - recentEdges.left()) <= 8;
}
private LayoutEdges stableAodEdges(int rootWidth, LayoutEdges aodEdges) { private LayoutEdges stableAodEdges(int rootWidth, LayoutEdges aodEdges) {
if (rootWidth <= 0) { if (rootWidth <= 0) {
return aodEdges; return aodEdges;
@@ -1188,6 +1188,7 @@ final class UnlockedStockSourceCollector {
View view = source.view(); View view = source.view();
if (view == null if (view == null
|| view == root || view == root
|| view.getVisibility() != View.VISIBLE
|| !view.isAttachedToWindow() || !view.isAttachedToWindow()
|| !ViewGeometry.isDescendantOf(view, root) || !ViewGeometry.isDescendantOf(view, root)
|| ReflectionSupport.getBooleanField(view, "sbtStatusChipForcedHidden", false) || ReflectionSupport.getBooleanField(view, "sbtStatusChipForcedHidden", false)
@@ -1301,7 +1302,7 @@ final class UnlockedStockSourceCollector {
} }
private boolean isStatusChipMetricCandidate(View root, View view, boolean allowHidden) { private boolean isStatusChipMetricCandidate(View root, View view, boolean allowHidden) {
if (view == null || view == root || root == null) { if (view == null || view == root || root == null || view.getVisibility() != View.VISIBLE) {
return false; return false;
} }
if (!allowHidden && view.getAlpha() <= 0f && !hasRenderableStatusChipContent(view)) { if (!allowHidden && view.getAlpha() <= 0f && !hasRenderableStatusChipContent(view)) {
@@ -417,7 +417,7 @@ public final class AppIconRules {
continue; continue;
} }
String[] parts = entry.split("\\|", -1); String[] parts = entry.split("\\|", -1);
if (parts.length != 2 && parts.length != 4) { if (parts.length != 4) {
continue; continue;
} }
String pkg = parts[0]; String pkg = parts[0];
@@ -429,13 +429,8 @@ public final class AppIconRules {
int lastSeenOffsetMinutes; int lastSeenOffsetMinutes;
try { try {
firstSeen = Long.parseLong(parts[1]); firstSeen = Long.parseLong(parts[1]);
if (parts.length == 4) {
lastSeen = Long.parseLong(parts[2]); lastSeen = Long.parseLong(parts[2]);
lastSeenOffsetMinutes = Integer.parseInt(parts[3]); lastSeenOffsetMinutes = Integer.parseInt(parts[3]);
} else {
lastSeen = firstSeen;
lastSeenOffsetMinutes = currentTimezoneOffsetMinutes();
}
} catch (NumberFormatException ignored) { } catch (NumberFormatException ignored) {
continue; continue;
} }
@@ -21,11 +21,28 @@ public final class BatteryBarGeometry {
public final String position; public final String position;
public final String alignment; public final String alignment;
public final int thicknessDp; public final int thicknessDp;
public final int edgeOffsetDp;
public final String curvedGeometryMode;
public BatteryBarGeometry( public BatteryBarGeometry(
String position, String position,
String alignment, String alignment,
int thicknessDp int thicknessDp
) {
this(
position,
alignment,
thicknessDp,
SbtDefaults.BATTERY_BAR_EDGE_OFFSET_DP_DEFAULT,
SbtDefaults.BATTERY_BAR_CURVED_GEOMETRY_MODE_DEFAULT);
}
public BatteryBarGeometry(
String position,
String alignment,
int thicknessDp,
int edgeOffsetDp,
String curvedGeometryMode
) { ) {
this.position = sanitizePosition(position); this.position = sanitizePosition(position);
this.alignment = sanitizeAlignment(alignment); this.alignment = sanitizeAlignment(alignment);
@@ -33,6 +50,11 @@ public final class BatteryBarGeometry {
thicknessDp, thicknessDp,
SbtDefaults.BATTERY_BAR_THICKNESS_DP_MIN, SbtDefaults.BATTERY_BAR_THICKNESS_DP_MIN,
SbtDefaults.BATTERY_BAR_THICKNESS_DP_MAX); SbtDefaults.BATTERY_BAR_THICKNESS_DP_MAX);
this.edgeOffsetDp = clamp(
edgeOffsetDp,
SbtDefaults.BATTERY_BAR_EDGE_OFFSET_DP_MIN,
SbtDefaults.BATTERY_BAR_EDGE_OFFSET_DP_MAX);
this.curvedGeometryMode = sanitizeCurvedGeometryMode(curvedGeometryMode);
} }
public static BatteryBarGeometry global(SbtSettings settings) { public static BatteryBarGeometry global(SbtSettings settings) {
@@ -45,7 +67,9 @@ public final class BatteryBarGeometry {
return new BatteryBarGeometry( return new BatteryBarGeometry(
settings.batteryBarPosition, settings.batteryBarPosition,
settings.batteryBarAlignment, settings.batteryBarAlignment,
settings.batteryBarThicknessDp); settings.batteryBarThicknessDp,
settings.batteryBarEdgeOffsetDp,
settings.batteryBarCurvedGeometryMode);
} }
public static BatteryBarGeometry resolve( public static BatteryBarGeometry resolve(
@@ -68,17 +92,19 @@ public final class BatteryBarGeometry {
return safeFallback; return safeFallback;
} }
String[] parts = value.split("\\|", -1); String[] parts = value.split("\\|", -1);
if (parts.length != 3 && parts.length != 4) { if (parts.length != 5) {
return safeFallback; return safeFallback;
} }
return new BatteryBarGeometry( return new BatteryBarGeometry(
parts[0], parts[0],
parts[1], parts[1],
parseInt(parts[2], safeFallback.thicknessDp)); parseInt(parts[2], safeFallback.thicknessDp),
parseInt(parts[3], safeFallback.edgeOffsetDp),
parts[4]);
} }
public String encode() { public String encode() {
return position + "|" + alignment + "|" + thicknessDp; return position + "|" + alignment + "|" + thicknessDp + "|" + edgeOffsetDp + "|" + curvedGeometryMode;
} }
public String signature() { public String signature() {
@@ -104,6 +130,13 @@ public final class BatteryBarGeometry {
return "ltr"; return "ltr";
} }
private static String sanitizeCurvedGeometryMode(String mode) {
if ("length".equals(mode)) {
return "length";
}
return "off";
}
private static int parseInt(String value, int fallback) { private static int parseInt(String value, int fallback) {
try { try {
return Integer.parseInt(value); return Integer.parseInt(value);
@@ -51,7 +51,7 @@ public final class SbtDefaults {
public static final boolean AOD_KEEP_VISIBLE_DURING_CALL_DEFAULT = false; public static final boolean AOD_KEEP_VISIBLE_DURING_CALL_DEFAULT = false;
public static final boolean BATTERY_LOCKSCREEN_UNPLUGGED_PERCENT_DEFAULT = true; public static final boolean BATTERY_LOCKSCREEN_UNPLUGGED_PERCENT_DEFAULT = true;
public static final boolean BATTERY_AOD_UNPLUGGED_PERCENT_DEFAULT = true; public static final boolean BATTERY_AOD_UNPLUGGED_PERCENT_DEFAULT = true;
public static final boolean BATTERY_BAR_ENABLED_DEFAULT = false; public static final boolean BATTERY_BAR_ENABLED_DEFAULT = true;
public static final String BATTERY_BAR_POSITION_DEFAULT = "top"; public static final String BATTERY_BAR_POSITION_DEFAULT = "top";
public static final String BATTERY_BAR_ALIGNMENT_DEFAULT = "ltr"; public static final String BATTERY_BAR_ALIGNMENT_DEFAULT = "ltr";
public static final int BATTERY_BAR_THICKNESS_DP_DEFAULT = 2; public static final int BATTERY_BAR_THICKNESS_DP_DEFAULT = 2;
@@ -78,13 +78,14 @@ public final class SbtSettings {
public static final String KEY_BATTERY_BAR_GEOMETRY_OVERRIDE_ENABLED_PREFIX = public static final String KEY_BATTERY_BAR_GEOMETRY_OVERRIDE_ENABLED_PREFIX =
"battery_bar_geometry_override_enabled_"; "battery_bar_geometry_override_enabled_";
public static final String KEY_BATTERY_BAR_GEOMETRY_PREFIX = "battery_bar_geometry_"; public static final String KEY_BATTERY_BAR_GEOMETRY_PREFIX = "battery_bar_geometry_";
public static final String KEY_BATTERY_BAR_SCENARIO_ENABLED_PREFIX =
"battery_bar_scenario_enabled_";
public static final String KEY_BATTERY_BAR_MIN_LEVEL = "battery_bar_min_level"; public static final String KEY_BATTERY_BAR_MIN_LEVEL = "battery_bar_min_level";
public static final String KEY_BATTERY_BAR_MAX_LEVEL = "battery_bar_max_level"; public static final String KEY_BATTERY_BAR_MAX_LEVEL = "battery_bar_max_level";
public static final String KEY_BATTERY_BAR_DEFAULT_DISCHARGE_COLOR = "battery_bar_default_discharge_color"; public static final String KEY_BATTERY_BAR_DEFAULT_DISCHARGE_COLOR = "battery_bar_default_discharge_color";
public static final String KEY_BATTERY_BAR_DEFAULT_CHARGE_COLOR = "battery_bar_default_charge_color"; public static final String KEY_BATTERY_BAR_DEFAULT_CHARGE_COLOR = "battery_bar_default_charge_color";
public static final String KEY_BATTERY_BAR_THRESHOLDS = "battery_bar_thresholds"; public static final String KEY_BATTERY_BAR_THRESHOLDS = "battery_bar_thresholds";
public static final String BATTERY_BAR_CURVED_GEOMETRY_OFF = "off"; public static final String BATTERY_BAR_CURVED_GEOMETRY_OFF = "off";
public static final String BATTERY_BAR_CURVED_GEOMETRY_HORIZONTAL = "horizontal";
public static final String BATTERY_BAR_CURVED_GEOMETRY_LENGTH = "length"; public static final String BATTERY_BAR_CURVED_GEOMETRY_LENGTH = "length";
public static final String KEY_CLOCK_ENABLED = "clock_enabled"; public static final String KEY_CLOCK_ENABLED = "clock_enabled";
public static final String KEY_CLOCK_ENABLED_LOCKSCREEN = "clock_enabled_lockscreen"; public static final String KEY_CLOCK_ENABLED_LOCKSCREEN = "clock_enabled_lockscreen";
@@ -173,7 +174,6 @@ public final class SbtSettings {
public static final String KEY_LAYOUT_STATUS_VERTICAL_OFFSET_PX = "layout_status_vertical_offset_px"; public static final String KEY_LAYOUT_STATUS_VERTICAL_OFFSET_PX = "layout_status_vertical_offset_px";
public static final String KEY_LAYOUT_STATUS_ICON_HEIGHT_STEPS = "layout_status_icon_height_steps"; public static final String KEY_LAYOUT_STATUS_ICON_HEIGHT_STEPS = "layout_status_icon_height_steps";
public static final String KEY_SYSTEM_ICON_BLOCKED_MODES = SystemIconRules.PREF_KEY_BLOCKED_MODES; public static final String KEY_SYSTEM_ICON_BLOCKED_MODES = SystemIconRules.PREF_KEY_BLOCKED_MODES;
public static final String KEY_SYSTEM_ICON_HIDE_SLOTS = "system_icon_hide_slots";
public static final String KEY_SYSTEM_ICON_DUAL_SIM_SIGNAL_MODE = "system_icon_dual_sim_signal_mode"; public static final String KEY_SYSTEM_ICON_DUAL_SIM_SIGNAL_MODE = "system_icon_dual_sim_signal_mode";
public static final String SYSTEM_ICON_DUAL_SIM_SEPARATE = "separate"; public static final String SYSTEM_ICON_DUAL_SIM_SEPARATE = "separate";
public static final String SYSTEM_ICON_DUAL_SIM_FIRST = "first"; public static final String SYSTEM_ICON_DUAL_SIM_FIRST = "first";
@@ -285,6 +285,10 @@ public final class SbtSettings {
return KEY_BATTERY_BAR_GEOMETRY_PREFIX + scenarioId; return KEY_BATTERY_BAR_GEOMETRY_PREFIX + scenarioId;
} }
public static String batteryBarScenarioEnabledKey(String scenarioId) {
return KEY_BATTERY_BAR_SCENARIO_ENABLED_PREFIX + scenarioId;
}
private static String suffixedKey(String base, int index) { private static String suffixedKey(String base, int index) {
return indexedKey(base, index); return indexedKey(base, index);
} }
@@ -318,6 +322,7 @@ public final class SbtSettings {
public final String batteryBarCurvedGeometryMode; public final String batteryBarCurvedGeometryMode;
public final Set<String> batteryBarGeometryOverrideEnabledScenarios; public final Set<String> batteryBarGeometryOverrideEnabledScenarios;
public final Map<String, String> batteryBarGeometryOverrides; public final Map<String, String> batteryBarGeometryOverrides;
public final Map<String, Boolean> batteryBarScenarioEnabled;
public final int batteryBarMinLevel; public final int batteryBarMinLevel;
public final int batteryBarMaxLevel; public final int batteryBarMaxLevel;
public final String batteryBarDefaultDischargeColor; public final String batteryBarDefaultDischargeColor;
@@ -451,6 +456,7 @@ public final class SbtSettings {
String batteryBarCurvedGeometryMode, String batteryBarCurvedGeometryMode,
Set<String> batteryBarGeometryOverrideEnabledScenarios, Set<String> batteryBarGeometryOverrideEnabledScenarios,
Map<String, String> batteryBarGeometryOverrides, Map<String, String> batteryBarGeometryOverrides,
Map<String, Boolean> batteryBarScenarioEnabled,
int batteryBarMinLevel, int batteryBarMinLevel,
int batteryBarMaxLevel, int batteryBarMaxLevel,
String batteryBarDefaultDischargeColor, String batteryBarDefaultDischargeColor,
@@ -595,6 +601,7 @@ public final class SbtSettings {
this.batteryBarGeometryOverrideEnabledScenarios = this.batteryBarGeometryOverrideEnabledScenarios =
sanitizeBatteryBarScenarioSet(batteryBarGeometryOverrideEnabledScenarios); sanitizeBatteryBarScenarioSet(batteryBarGeometryOverrideEnabledScenarios);
this.batteryBarGeometryOverrides = sanitizeBatteryBarScenarioMap(batteryBarGeometryOverrides); this.batteryBarGeometryOverrides = sanitizeBatteryBarScenarioMap(batteryBarGeometryOverrides);
this.batteryBarScenarioEnabled = sanitizeBatteryBarScenarioEnabledMap(batteryBarScenarioEnabled);
int clampedMinLevel = clampInt( int clampedMinLevel = clampInt(
batteryBarMinLevel, batteryBarMinLevel,
SbtDefaults.BATTERY_BAR_MIN_LEVEL_MIN, SbtDefaults.BATTERY_BAR_MIN_LEVEL_MIN,
@@ -888,6 +895,7 @@ public final class SbtSettings {
SbtDefaults.BATTERY_BAR_CURVED_GEOMETRY_MODE_DEFAULT, SbtDefaults.BATTERY_BAR_CURVED_GEOMETRY_MODE_DEFAULT,
Collections.emptySet(), Collections.emptySet(),
Collections.emptyMap(), Collections.emptyMap(),
Collections.emptyMap(),
SbtDefaults.BATTERY_BAR_MIN_LEVEL_DEFAULT, SbtDefaults.BATTERY_BAR_MIN_LEVEL_DEFAULT,
SbtDefaults.BATTERY_BAR_MAX_LEVEL_DEFAULT, SbtDefaults.BATTERY_BAR_MAX_LEVEL_DEFAULT,
SbtDefaults.BATTERY_BAR_DEFAULT_DISCHARGE_COLOR_DEFAULT, SbtDefaults.BATTERY_BAR_DEFAULT_DISCHARGE_COLOR_DEFAULT,
@@ -1017,8 +1025,7 @@ public final class SbtSettings {
} }
public static String readBatteryBarCurvedGeometryMode(String mode) { public static String readBatteryBarCurvedGeometryMode(String mode) {
if (BATTERY_BAR_CURVED_GEOMETRY_HORIZONTAL.equals(mode) if (BATTERY_BAR_CURVED_GEOMETRY_LENGTH.equals(mode)) {
|| BATTERY_BAR_CURVED_GEOMETRY_LENGTH.equals(mode)) {
return mode; return mode;
} }
return BATTERY_BAR_CURVED_GEOMETRY_OFF; return BATTERY_BAR_CURVED_GEOMETRY_OFF;
@@ -1227,6 +1234,7 @@ public final class SbtSettings {
SbtDefaults.BATTERY_BAR_CURVED_GEOMETRY_MODE_DEFAULT), SbtDefaults.BATTERY_BAR_CURVED_GEOMETRY_MODE_DEFAULT),
readBatteryBarScenarioSetFromPrefs(prefs), readBatteryBarScenarioSetFromPrefs(prefs),
readBatteryBarScenarioMapFromPrefs(prefs), readBatteryBarScenarioMapFromPrefs(prefs),
readBatteryBarScenarioEnabledMapFromPrefs(prefs),
clampInt(prefs.getInt(KEY_BATTERY_BAR_MIN_LEVEL, SbtDefaults.BATTERY_BAR_MIN_LEVEL_DEFAULT), clampInt(prefs.getInt(KEY_BATTERY_BAR_MIN_LEVEL, SbtDefaults.BATTERY_BAR_MIN_LEVEL_DEFAULT),
SbtDefaults.BATTERY_BAR_MIN_LEVEL_MIN, SbtDefaults.BATTERY_BAR_MIN_LEVEL_MIN,
SbtDefaults.BATTERY_BAR_MIN_LEVEL_MAX), SbtDefaults.BATTERY_BAR_MIN_LEVEL_MAX),
@@ -1316,9 +1324,7 @@ public final class SbtSettings {
readIconContainerCount( readIconContainerCount(
prefs, prefs,
KEY_LAYOUT_NOTIF_UNLOCKED_COUNT, KEY_LAYOUT_NOTIF_UNLOCKED_COUNT,
KEY_LAYOUT_NOTIF_ENABLED_UNLOCKED, SbtDefaults.LAYOUT_NOTIF_UNLOCKED_COUNT_DEFAULT),
SbtDefaults.LAYOUT_NOTIF_UNLOCKED_COUNT_DEFAULT,
SbtDefaults.LAYOUT_NOTIF_ENABLED_UNLOCKED_DEFAULT),
readStringArrayFromPrefs( readStringArrayFromPrefs(
prefs, prefs,
SbtSettings::layoutNotifPositionKey, SbtSettings::layoutNotifPositionKey,
@@ -1334,9 +1340,7 @@ public final class SbtSettings {
readIconContainerCount( readIconContainerCount(
prefs, prefs,
KEY_LAYOUT_NOTIF_LOCK_COUNT, KEY_LAYOUT_NOTIF_LOCK_COUNT,
KEY_LAYOUT_NOTIF_ENABLED_LOCKSCREEN, SbtDefaults.LAYOUT_NOTIF_UNLOCKED_COUNT_DEFAULT),
SbtDefaults.LAYOUT_NOTIF_UNLOCKED_COUNT_DEFAULT,
SbtDefaults.LAYOUT_NOTIF_ENABLED_LOCKSCREEN_DEFAULT),
readStringArrayFromPrefs( readStringArrayFromPrefs(
prefs, prefs,
SbtSettings::layoutLockNotifPositionKey, SbtSettings::layoutLockNotifPositionKey,
@@ -1352,9 +1356,7 @@ public final class SbtSettings {
readIconContainerCount( readIconContainerCount(
prefs, prefs,
KEY_LAYOUT_NOTIF_AOD_COUNT, KEY_LAYOUT_NOTIF_AOD_COUNT,
KEY_LAYOUT_NOTIF_ENABLED_AOD, SbtDefaults.LAYOUT_NOTIF_UNLOCKED_COUNT_DEFAULT),
SbtDefaults.LAYOUT_NOTIF_UNLOCKED_COUNT_DEFAULT,
SbtDefaults.LAYOUT_NOTIF_ENABLED_AOD_DEFAULT),
readStringArrayFromPrefs( readStringArrayFromPrefs(
prefs, prefs,
SbtSettings::layoutAodNotifPositionKey, SbtSettings::layoutAodNotifPositionKey,
@@ -1391,9 +1393,7 @@ public final class SbtSettings {
readIconContainerCount( readIconContainerCount(
prefs, prefs,
KEY_LAYOUT_STATUS_UNLOCKED_COUNT, KEY_LAYOUT_STATUS_UNLOCKED_COUNT,
KEY_LAYOUT_STATUS_ENABLED_UNLOCKED, SbtDefaults.LAYOUT_STATUS_UNLOCKED_COUNT_DEFAULT),
SbtDefaults.LAYOUT_STATUS_UNLOCKED_COUNT_DEFAULT,
SbtDefaults.LAYOUT_STATUS_ENABLED_UNLOCKED_DEFAULT),
readStringArrayFromPrefs( readStringArrayFromPrefs(
prefs, prefs,
SbtSettings::layoutStatusPositionKey, SbtSettings::layoutStatusPositionKey,
@@ -1409,9 +1409,7 @@ public final class SbtSettings {
readIconContainerCount( readIconContainerCount(
prefs, prefs,
KEY_LAYOUT_STATUS_LOCK_COUNT, KEY_LAYOUT_STATUS_LOCK_COUNT,
KEY_LAYOUT_STATUS_ENABLED_LOCKSCREEN, SbtDefaults.LAYOUT_STATUS_UNLOCKED_COUNT_DEFAULT),
SbtDefaults.LAYOUT_STATUS_UNLOCKED_COUNT_DEFAULT,
SbtDefaults.LAYOUT_STATUS_ENABLED_LOCKSCREEN_DEFAULT),
readStringArrayFromPrefs( readStringArrayFromPrefs(
prefs, prefs,
SbtSettings::layoutLockStatusPositionKey, SbtSettings::layoutLockStatusPositionKey,
@@ -1427,9 +1425,7 @@ public final class SbtSettings {
readIconContainerCount( readIconContainerCount(
prefs, prefs,
KEY_LAYOUT_STATUS_AOD_COUNT, KEY_LAYOUT_STATUS_AOD_COUNT,
KEY_LAYOUT_STATUS_ENABLED_AOD, SbtDefaults.LAYOUT_STATUS_UNLOCKED_COUNT_DEFAULT),
SbtDefaults.LAYOUT_STATUS_UNLOCKED_COUNT_DEFAULT,
SbtDefaults.LAYOUT_STATUS_ENABLED_AOD_DEFAULT),
readStringArrayFromPrefs( readStringArrayFromPrefs(
prefs, prefs,
SbtSettings::layoutAodStatusPositionKey, SbtSettings::layoutAodStatusPositionKey,
@@ -1546,6 +1542,7 @@ public final class SbtSettings {
SbtDefaults.BATTERY_BAR_CURVED_GEOMETRY_MODE_DEFAULT), SbtDefaults.BATTERY_BAR_CURVED_GEOMETRY_MODE_DEFAULT),
readBatteryBarScenarioSetFromBundle(bundle), readBatteryBarScenarioSetFromBundle(bundle),
readBatteryBarScenarioMapFromBundle(bundle), readBatteryBarScenarioMapFromBundle(bundle),
readBatteryBarScenarioEnabledMapFromBundle(bundle),
clampInt(bundle.getInt(KEY_BATTERY_BAR_MIN_LEVEL, SbtDefaults.BATTERY_BAR_MIN_LEVEL_DEFAULT), clampInt(bundle.getInt(KEY_BATTERY_BAR_MIN_LEVEL, SbtDefaults.BATTERY_BAR_MIN_LEVEL_DEFAULT),
SbtDefaults.BATTERY_BAR_MIN_LEVEL_MIN, SbtDefaults.BATTERY_BAR_MIN_LEVEL_MIN,
SbtDefaults.BATTERY_BAR_MIN_LEVEL_MAX), SbtDefaults.BATTERY_BAR_MIN_LEVEL_MAX),
@@ -1635,9 +1632,7 @@ public final class SbtSettings {
readIconContainerCount( readIconContainerCount(
bundle, bundle,
KEY_LAYOUT_NOTIF_UNLOCKED_COUNT, KEY_LAYOUT_NOTIF_UNLOCKED_COUNT,
KEY_LAYOUT_NOTIF_ENABLED_UNLOCKED, SbtDefaults.LAYOUT_NOTIF_UNLOCKED_COUNT_DEFAULT),
SbtDefaults.LAYOUT_NOTIF_UNLOCKED_COUNT_DEFAULT,
SbtDefaults.LAYOUT_NOTIF_ENABLED_UNLOCKED_DEFAULT),
readStringArrayFromBundle( readStringArrayFromBundle(
bundle, bundle,
SbtSettings::layoutNotifPositionKey, SbtSettings::layoutNotifPositionKey,
@@ -1653,9 +1648,7 @@ public final class SbtSettings {
readIconContainerCount( readIconContainerCount(
bundle, bundle,
KEY_LAYOUT_NOTIF_LOCK_COUNT, KEY_LAYOUT_NOTIF_LOCK_COUNT,
KEY_LAYOUT_NOTIF_ENABLED_LOCKSCREEN, SbtDefaults.LAYOUT_NOTIF_UNLOCKED_COUNT_DEFAULT),
SbtDefaults.LAYOUT_NOTIF_UNLOCKED_COUNT_DEFAULT,
SbtDefaults.LAYOUT_NOTIF_ENABLED_LOCKSCREEN_DEFAULT),
readStringArrayFromBundle( readStringArrayFromBundle(
bundle, bundle,
SbtSettings::layoutLockNotifPositionKey, SbtSettings::layoutLockNotifPositionKey,
@@ -1671,9 +1664,7 @@ public final class SbtSettings {
readIconContainerCount( readIconContainerCount(
bundle, bundle,
KEY_LAYOUT_NOTIF_AOD_COUNT, KEY_LAYOUT_NOTIF_AOD_COUNT,
KEY_LAYOUT_NOTIF_ENABLED_AOD, SbtDefaults.LAYOUT_NOTIF_UNLOCKED_COUNT_DEFAULT),
SbtDefaults.LAYOUT_NOTIF_UNLOCKED_COUNT_DEFAULT,
SbtDefaults.LAYOUT_NOTIF_ENABLED_AOD_DEFAULT),
readStringArrayFromBundle( readStringArrayFromBundle(
bundle, bundle,
SbtSettings::layoutAodNotifPositionKey, SbtSettings::layoutAodNotifPositionKey,
@@ -1710,9 +1701,7 @@ public final class SbtSettings {
readIconContainerCount( readIconContainerCount(
bundle, bundle,
KEY_LAYOUT_STATUS_UNLOCKED_COUNT, KEY_LAYOUT_STATUS_UNLOCKED_COUNT,
KEY_LAYOUT_STATUS_ENABLED_UNLOCKED, SbtDefaults.LAYOUT_STATUS_UNLOCKED_COUNT_DEFAULT),
SbtDefaults.LAYOUT_STATUS_UNLOCKED_COUNT_DEFAULT,
SbtDefaults.LAYOUT_STATUS_ENABLED_UNLOCKED_DEFAULT),
readStringArrayFromBundle( readStringArrayFromBundle(
bundle, bundle,
SbtSettings::layoutStatusPositionKey, SbtSettings::layoutStatusPositionKey,
@@ -1728,9 +1717,7 @@ public final class SbtSettings {
readIconContainerCount( readIconContainerCount(
bundle, bundle,
KEY_LAYOUT_STATUS_LOCK_COUNT, KEY_LAYOUT_STATUS_LOCK_COUNT,
KEY_LAYOUT_STATUS_ENABLED_LOCKSCREEN, SbtDefaults.LAYOUT_STATUS_UNLOCKED_COUNT_DEFAULT),
SbtDefaults.LAYOUT_STATUS_UNLOCKED_COUNT_DEFAULT,
SbtDefaults.LAYOUT_STATUS_ENABLED_LOCKSCREEN_DEFAULT),
readStringArrayFromBundle( readStringArrayFromBundle(
bundle, bundle,
SbtSettings::layoutLockStatusPositionKey, SbtSettings::layoutLockStatusPositionKey,
@@ -1746,9 +1733,7 @@ public final class SbtSettings {
readIconContainerCount( readIconContainerCount(
bundle, bundle,
KEY_LAYOUT_STATUS_AOD_COUNT, KEY_LAYOUT_STATUS_AOD_COUNT,
KEY_LAYOUT_STATUS_ENABLED_AOD, SbtDefaults.LAYOUT_STATUS_UNLOCKED_COUNT_DEFAULT),
SbtDefaults.LAYOUT_STATUS_UNLOCKED_COUNT_DEFAULT,
SbtDefaults.LAYOUT_STATUS_ENABLED_AOD_DEFAULT),
readStringArrayFromBundle( readStringArrayFromBundle(
bundle, bundle,
SbtSettings::layoutAodStatusPositionKey, SbtSettings::layoutAodStatusPositionKey,
@@ -1822,35 +1807,21 @@ public final class SbtSettings {
private static int readIconContainerCount( private static int readIconContainerCount(
SharedPreferences prefs, SharedPreferences prefs,
String countKey, String countKey,
String legacyEnabledKey, int defaultCount
int defaultCount,
boolean legacyEnabledDefault
) { ) {
int fallback = iconContainerCountFallback( int value = prefs.getInt(countKey, defaultCount);
prefs.getBoolean(legacyEnabledKey, legacyEnabledDefault),
defaultCount);
int value = prefs.getInt(countKey, fallback);
return clampIconContainerCount(value); return clampIconContainerCount(value);
} }
private static int readIconContainerCount( private static int readIconContainerCount(
Bundle bundle, Bundle bundle,
String countKey, String countKey,
String legacyEnabledKey, int defaultCount
int defaultCount,
boolean legacyEnabledDefault
) { ) {
int fallback = iconContainerCountFallback( int value = bundle.getInt(countKey, defaultCount);
bundle.getBoolean(legacyEnabledKey, legacyEnabledDefault),
defaultCount);
int value = bundle.getInt(countKey, fallback);
return clampIconContainerCount(value); return clampIconContainerCount(value);
} }
private static int iconContainerCountFallback(boolean legacyEnabled, int defaultCount) {
return legacyEnabled ? defaultCount : 0;
}
private static String[] readStringArrayFromPrefs( private static String[] readStringArrayFromPrefs(
SharedPreferences prefs, SharedPreferences prefs,
IndexedKey key, IndexedKey key,
@@ -1989,6 +1960,34 @@ public final class SbtSettings {
return result; return result;
} }
private static Map<String, Boolean> readBatteryBarScenarioEnabledMapFromPrefs(SharedPreferences prefs) {
if (prefs == null) {
return Collections.emptyMap();
}
HashMap<String, Boolean> result = new HashMap<>();
for (BatteryBarGeometry.Scenario scenario : BatteryBarGeometry.Scenario.values()) {
String key = batteryBarScenarioEnabledKey(scenario.id);
if (prefs.contains(key)) {
result.put(scenario.id, prefs.getBoolean(key, true));
}
}
return result;
}
private static Map<String, Boolean> readBatteryBarScenarioEnabledMapFromBundle(Bundle bundle) {
if (bundle == null) {
return Collections.emptyMap();
}
HashMap<String, Boolean> result = new HashMap<>();
for (BatteryBarGeometry.Scenario scenario : BatteryBarGeometry.Scenario.values()) {
String key = batteryBarScenarioEnabledKey(scenario.id);
if (bundle.containsKey(key)) {
result.put(scenario.id, bundle.getBoolean(key, true));
}
}
return result;
}
private static Set<String> sanitizeBatteryBarScenarioSet(Set<String> source) { private static Set<String> sanitizeBatteryBarScenarioSet(Set<String> source) {
if (source == null || source.isEmpty()) { if (source == null || source.isEmpty()) {
return Collections.emptySet(); return Collections.emptySet();
@@ -2017,6 +2016,21 @@ public final class SbtSettings {
return result.isEmpty() ? Collections.emptyMap() : Collections.unmodifiableMap(result); return result.isEmpty() ? Collections.emptyMap() : Collections.unmodifiableMap(result);
} }
private static Map<String, Boolean> sanitizeBatteryBarScenarioEnabledMap(Map<String, Boolean> source) {
if (source == null || source.isEmpty()) {
return Collections.emptyMap();
}
HashMap<String, Boolean> result = new HashMap<>();
for (Map.Entry<String, Boolean> entry : source.entrySet()) {
String id = entry.getKey();
Boolean value = entry.getValue();
if (isBatteryBarScenarioId(id) && value != null) {
result.put(id, value);
}
}
return result.isEmpty() ? Collections.emptyMap() : Collections.unmodifiableMap(result);
}
private static boolean isBatteryBarScenarioId(String id) { private static boolean isBatteryBarScenarioId(String id) {
if (id == null) { if (id == null) {
return false; return false;
@@ -2035,9 +2049,7 @@ public final class SbtSettings {
} }
Map<String, Integer> parsed = SystemIconRules.parseBlockedModes( Map<String, Integer> parsed = SystemIconRules.parseBlockedModes(
readStringSetFromPrefs(prefs, KEY_SYSTEM_ICON_BLOCKED_MODES)); readStringSetFromPrefs(prefs, KEY_SYSTEM_ICON_BLOCKED_MODES));
HashMap<String, Integer> merged = new HashMap<>(parsed); return parsed.isEmpty() ? Collections.emptyMap() : parsed;
mergeLegacySystemIconHidden(merged, readStringSetFromPrefs(prefs, KEY_SYSTEM_ICON_HIDE_SLOTS));
return merged.isEmpty() ? Collections.emptyMap() : merged;
} }
private static Map<String, Integer> readSystemIconBlockedModesFromBundle(Bundle bundle) { private static Map<String, Integer> readSystemIconBlockedModesFromBundle(Bundle bundle) {
@@ -2046,20 +2058,7 @@ public final class SbtSettings {
} }
Map<String, Integer> parsed = SystemIconRules.parseBlockedModes( Map<String, Integer> parsed = SystemIconRules.parseBlockedModes(
readStringSetFromBundle(bundle, KEY_SYSTEM_ICON_BLOCKED_MODES)); readStringSetFromBundle(bundle, KEY_SYSTEM_ICON_BLOCKED_MODES));
HashMap<String, Integer> merged = new HashMap<>(parsed); return parsed.isEmpty() ? Collections.emptyMap() : parsed;
mergeLegacySystemIconHidden(merged, readStringSetFromBundle(bundle, KEY_SYSTEM_ICON_HIDE_SLOTS));
return merged.isEmpty() ? Collections.emptyMap() : merged;
}
private static void mergeLegacySystemIconHidden(HashMap<String, Integer> merged, Set<String> legacyHidden) {
if (merged == null || legacyHidden == null || legacyHidden.isEmpty()) {
return;
}
for (String slot : legacyHidden) {
SystemIconRules.setModeBlocked(merged, slot,
SystemIconRules.MODE_AOD | SystemIconRules.MODE_LOCK | SystemIconRules.MODE_UNLOCK,
true);
}
} }
public static void ensureReadable(Context context) { public static void ensureReadable(Context context) {
@@ -107,8 +107,12 @@ public class SbtSettingsProvider extends ContentProvider {
for (BatteryBarGeometry.Scenario scenario : BatteryBarGeometry.Scenario.values()) { for (BatteryBarGeometry.Scenario scenario : BatteryBarGeometry.Scenario.values()) {
String enabledKey = BatteryBarGeometry.enabledKey(scenario); String enabledKey = BatteryBarGeometry.enabledKey(scenario);
String valueKey = BatteryBarGeometry.valueKey(scenario); String valueKey = BatteryBarGeometry.valueKey(scenario);
String scenarioEnabledKey = SbtSettings.batteryBarScenarioEnabledKey(scenario.id);
out.putBoolean(enabledKey, prefs.getBoolean(enabledKey, false)); out.putBoolean(enabledKey, prefs.getBoolean(enabledKey, false));
out.putString(valueKey, prefs.getString(valueKey, null)); out.putString(valueKey, prefs.getString(valueKey, null));
if (prefs.contains(scenarioEnabledKey)) {
out.putBoolean(scenarioEnabledKey, prefs.getBoolean(scenarioEnabledKey, true));
}
} }
out.putInt(SbtSettings.KEY_BATTERY_BAR_MIN_LEVEL, out.putInt(SbtSettings.KEY_BATTERY_BAR_MIN_LEVEL,
prefs.getInt(SbtSettings.KEY_BATTERY_BAR_MIN_LEVEL, SbtDefaults.BATTERY_BAR_MIN_LEVEL_DEFAULT)); prefs.getInt(SbtSettings.KEY_BATTERY_BAR_MIN_LEVEL, SbtDefaults.BATTERY_BAR_MIN_LEVEL_DEFAULT));
@@ -261,11 +265,7 @@ public class SbtSettingsProvider extends ContentProvider {
SbtDefaults.LAYOUT_NOTIF_ENABLED_UNLOCKED_DEFAULT)); SbtDefaults.LAYOUT_NOTIF_ENABLED_UNLOCKED_DEFAULT));
out.putInt(SbtSettings.KEY_LAYOUT_NOTIF_UNLOCKED_COUNT, out.putInt(SbtSettings.KEY_LAYOUT_NOTIF_UNLOCKED_COUNT,
prefs.getInt(SbtSettings.KEY_LAYOUT_NOTIF_UNLOCKED_COUNT, prefs.getInt(SbtSettings.KEY_LAYOUT_NOTIF_UNLOCKED_COUNT,
prefs.getBoolean( SbtDefaults.LAYOUT_NOTIF_UNLOCKED_COUNT_DEFAULT));
SbtSettings.KEY_LAYOUT_NOTIF_ENABLED_UNLOCKED,
SbtDefaults.LAYOUT_NOTIF_ENABLED_UNLOCKED_DEFAULT)
? SbtDefaults.LAYOUT_NOTIF_UNLOCKED_COUNT_DEFAULT
: 0));
out.putString(SbtSettings.KEY_LAYOUT_NOTIF_MIDDLE_SIDE, out.putString(SbtSettings.KEY_LAYOUT_NOTIF_MIDDLE_SIDE,
prefs.getString(SbtSettings.KEY_LAYOUT_NOTIF_MIDDLE_SIDE, prefs.getString(SbtSettings.KEY_LAYOUT_NOTIF_MIDDLE_SIDE,
SbtDefaults.LAYOUT_NOTIF_MIDDLE_SIDE_DEFAULT)); SbtDefaults.LAYOUT_NOTIF_MIDDLE_SIDE_DEFAULT));
@@ -286,11 +286,7 @@ public class SbtSettingsProvider extends ContentProvider {
SbtDefaults.LAYOUT_NOTIF_VERTICAL_OFFSET_PX_DEFAULT); SbtDefaults.LAYOUT_NOTIF_VERTICAL_OFFSET_PX_DEFAULT);
out.putInt(SbtSettings.KEY_LAYOUT_NOTIF_LOCK_COUNT, out.putInt(SbtSettings.KEY_LAYOUT_NOTIF_LOCK_COUNT,
prefs.getInt(SbtSettings.KEY_LAYOUT_NOTIF_LOCK_COUNT, prefs.getInt(SbtSettings.KEY_LAYOUT_NOTIF_LOCK_COUNT,
prefs.getBoolean( SbtDefaults.LAYOUT_NOTIF_UNLOCKED_COUNT_DEFAULT));
SbtSettings.KEY_LAYOUT_NOTIF_ENABLED_LOCKSCREEN,
SbtDefaults.LAYOUT_NOTIF_ENABLED_LOCKSCREEN_DEFAULT)
? SbtDefaults.LAYOUT_NOTIF_UNLOCKED_COUNT_DEFAULT
: 0));
out.putInt(SbtSettings.layoutLockNotifIconHeightKey(), out.putInt(SbtSettings.layoutLockNotifIconHeightKey(),
prefs.getInt(SbtSettings.layoutLockNotifIconHeightKey(), prefs.getInt(SbtSettings.layoutLockNotifIconHeightKey(),
SbtDefaults.LAYOUT_NOTIF_LOCK_ICON_HEIGHT_STEPS_DEFAULT)); SbtDefaults.LAYOUT_NOTIF_LOCK_ICON_HEIGHT_STEPS_DEFAULT));
@@ -305,11 +301,7 @@ public class SbtSettingsProvider extends ContentProvider {
SbtDefaults.LAYOUT_NOTIF_VERTICAL_OFFSET_PX_DEFAULT); SbtDefaults.LAYOUT_NOTIF_VERTICAL_OFFSET_PX_DEFAULT);
out.putInt(SbtSettings.KEY_LAYOUT_NOTIF_AOD_COUNT, out.putInt(SbtSettings.KEY_LAYOUT_NOTIF_AOD_COUNT,
prefs.getInt(SbtSettings.KEY_LAYOUT_NOTIF_AOD_COUNT, prefs.getInt(SbtSettings.KEY_LAYOUT_NOTIF_AOD_COUNT,
prefs.getBoolean( SbtDefaults.LAYOUT_NOTIF_UNLOCKED_COUNT_DEFAULT));
SbtSettings.KEY_LAYOUT_NOTIF_ENABLED_AOD,
SbtDefaults.LAYOUT_NOTIF_ENABLED_AOD_DEFAULT)
? SbtDefaults.LAYOUT_NOTIF_UNLOCKED_COUNT_DEFAULT
: 0));
out.putInt(SbtSettings.layoutAodNotifIconHeightKey(), out.putInt(SbtSettings.layoutAodNotifIconHeightKey(),
prefs.getInt(SbtSettings.layoutAodNotifIconHeightKey(), prefs.getInt(SbtSettings.layoutAodNotifIconHeightKey(),
SbtDefaults.LAYOUT_NOTIF_AOD_ICON_HEIGHT_STEPS_DEFAULT)); SbtDefaults.LAYOUT_NOTIF_AOD_ICON_HEIGHT_STEPS_DEFAULT));
@@ -336,11 +328,7 @@ public class SbtSettingsProvider extends ContentProvider {
SbtDefaults.LAYOUT_STATUS_ENABLED_UNLOCKED_DEFAULT)); SbtDefaults.LAYOUT_STATUS_ENABLED_UNLOCKED_DEFAULT));
out.putInt(SbtSettings.KEY_LAYOUT_STATUS_UNLOCKED_COUNT, out.putInt(SbtSettings.KEY_LAYOUT_STATUS_UNLOCKED_COUNT,
prefs.getInt(SbtSettings.KEY_LAYOUT_STATUS_UNLOCKED_COUNT, prefs.getInt(SbtSettings.KEY_LAYOUT_STATUS_UNLOCKED_COUNT,
prefs.getBoolean( SbtDefaults.LAYOUT_STATUS_UNLOCKED_COUNT_DEFAULT));
SbtSettings.KEY_LAYOUT_STATUS_ENABLED_UNLOCKED,
SbtDefaults.LAYOUT_STATUS_ENABLED_UNLOCKED_DEFAULT)
? SbtDefaults.LAYOUT_STATUS_UNLOCKED_COUNT_DEFAULT
: 0));
out.putString(SbtSettings.KEY_LAYOUT_STATUS_MIDDLE_SIDE, out.putString(SbtSettings.KEY_LAYOUT_STATUS_MIDDLE_SIDE,
prefs.getString(SbtSettings.KEY_LAYOUT_STATUS_MIDDLE_SIDE, prefs.getString(SbtSettings.KEY_LAYOUT_STATUS_MIDDLE_SIDE,
SbtDefaults.LAYOUT_STATUS_MIDDLE_SIDE_DEFAULT)); SbtDefaults.LAYOUT_STATUS_MIDDLE_SIDE_DEFAULT));
@@ -365,11 +353,7 @@ public class SbtSettingsProvider extends ContentProvider {
SbtDefaults.SYSTEM_ICON_DUAL_SIM_SIGNAL_MODE_DEFAULT))); SbtDefaults.SYSTEM_ICON_DUAL_SIM_SIGNAL_MODE_DEFAULT)));
out.putInt(SbtSettings.KEY_LAYOUT_STATUS_LOCK_COUNT, out.putInt(SbtSettings.KEY_LAYOUT_STATUS_LOCK_COUNT,
prefs.getInt(SbtSettings.KEY_LAYOUT_STATUS_LOCK_COUNT, prefs.getInt(SbtSettings.KEY_LAYOUT_STATUS_LOCK_COUNT,
prefs.getBoolean( SbtDefaults.LAYOUT_STATUS_UNLOCKED_COUNT_DEFAULT));
SbtSettings.KEY_LAYOUT_STATUS_ENABLED_LOCKSCREEN,
SbtDefaults.LAYOUT_STATUS_ENABLED_LOCKSCREEN_DEFAULT)
? SbtDefaults.LAYOUT_STATUS_UNLOCKED_COUNT_DEFAULT
: 0));
out.putInt(SbtSettings.layoutLockStatusIconHeightKey(), out.putInt(SbtSettings.layoutLockStatusIconHeightKey(),
prefs.getInt(SbtSettings.layoutLockStatusIconHeightKey(), prefs.getInt(SbtSettings.layoutLockStatusIconHeightKey(),
SbtDefaults.LAYOUT_STATUS_ICON_HEIGHT_STEPS_DEFAULT)); SbtDefaults.LAYOUT_STATUS_ICON_HEIGHT_STEPS_DEFAULT));
@@ -384,11 +368,7 @@ public class SbtSettingsProvider extends ContentProvider {
SbtDefaults.LAYOUT_STATUS_VERTICAL_OFFSET_PX_DEFAULT); SbtDefaults.LAYOUT_STATUS_VERTICAL_OFFSET_PX_DEFAULT);
out.putInt(SbtSettings.KEY_LAYOUT_STATUS_AOD_COUNT, out.putInt(SbtSettings.KEY_LAYOUT_STATUS_AOD_COUNT,
prefs.getInt(SbtSettings.KEY_LAYOUT_STATUS_AOD_COUNT, prefs.getInt(SbtSettings.KEY_LAYOUT_STATUS_AOD_COUNT,
prefs.getBoolean( SbtDefaults.LAYOUT_STATUS_UNLOCKED_COUNT_DEFAULT));
SbtSettings.KEY_LAYOUT_STATUS_ENABLED_AOD,
SbtDefaults.LAYOUT_STATUS_ENABLED_AOD_DEFAULT)
? SbtDefaults.LAYOUT_STATUS_UNLOCKED_COUNT_DEFAULT
: 0));
out.putInt(SbtSettings.layoutAodStatusIconHeightKey(), out.putInt(SbtSettings.layoutAodStatusIconHeightKey(),
prefs.getInt(SbtSettings.layoutAodStatusIconHeightKey(), prefs.getInt(SbtSettings.layoutAodStatusIconHeightKey(),
SbtDefaults.LAYOUT_STATUS_ICON_HEIGHT_STEPS_DEFAULT)); SbtDefaults.LAYOUT_STATUS_ICON_HEIGHT_STEPS_DEFAULT));
@@ -403,7 +383,6 @@ public class SbtSettingsProvider extends ContentProvider {
SbtDefaults.LAYOUT_STATUS_VERTICAL_OFFSET_PX_DEFAULT); SbtDefaults.LAYOUT_STATUS_VERTICAL_OFFSET_PX_DEFAULT);
putStringSetArrayList(out, prefs, SbtSettings.KEY_CLOCK_CAMERA_TYPE_OVERRIDES); putStringSetArrayList(out, prefs, SbtSettings.KEY_CLOCK_CAMERA_TYPE_OVERRIDES);
putStringSetArrayList(out, prefs, SbtSettings.KEY_SYSTEM_ICON_BLOCKED_MODES); putStringSetArrayList(out, prefs, SbtSettings.KEY_SYSTEM_ICON_BLOCKED_MODES);
putStringSetArrayList(out, prefs, SbtSettings.KEY_SYSTEM_ICON_HIDE_SLOTS);
out.putBoolean(SbtSettings.KEY_STATUS_CHIPS_HIDE_ALL, out.putBoolean(SbtSettings.KEY_STATUS_CHIPS_HIDE_ALL,
prefs.getBoolean(SbtSettings.KEY_STATUS_CHIPS_HIDE_ALL, false)); prefs.getBoolean(SbtSettings.KEY_STATUS_CHIPS_HIDE_ALL, false));
out.putBoolean(SbtSettings.KEY_STATUS_CHIPS_HIDE_MEDIA_UNLOCKED, out.putBoolean(SbtSettings.KEY_STATUS_CHIPS_HIDE_MEDIA_UNLOCKED,
File diff suppressed because it is too large Load Diff
@@ -17,6 +17,7 @@ import android.view.inputmethod.EditorInfo;
import android.widget.CheckBox; import android.widget.CheckBox;
import android.widget.EditText; import android.widget.EditText;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import android.widget.RadioButton;
import android.widget.RadioGroup; import android.widget.RadioGroup;
import android.widget.TextView; import android.widget.TextView;
@@ -148,8 +149,6 @@ public final class LayoutFragment extends Fragment {
R.string.layout_notification_position_title, R.string.layout_notification_position_title,
SbtSettings.KEY_LAYOUT_NOTIF_UNLOCKED_COUNT, SbtSettings.KEY_LAYOUT_NOTIF_UNLOCKED_COUNT,
SbtDefaults.LAYOUT_NOTIF_UNLOCKED_COUNT_DEFAULT, SbtDefaults.LAYOUT_NOTIF_UNLOCKED_COUNT_DEFAULT,
SbtSettings.KEY_LAYOUT_NOTIF_ENABLED_UNLOCKED,
SbtDefaults.LAYOUT_NOTIF_ENABLED_UNLOCKED_DEFAULT,
SbtSettings::layoutNotifPositionKey, SbtSettings::layoutNotifPositionKey,
SbtSettings::layoutNotifMiddleSideKey, SbtSettings::layoutNotifMiddleSideKey,
SbtSettings::layoutNotifVerticalOffsetKey, SbtSettings::layoutNotifVerticalOffsetKey,
@@ -166,8 +165,6 @@ public final class LayoutFragment extends Fragment {
R.string.layout_status_position_title, R.string.layout_status_position_title,
SbtSettings.KEY_LAYOUT_STATUS_UNLOCKED_COUNT, SbtSettings.KEY_LAYOUT_STATUS_UNLOCKED_COUNT,
SbtDefaults.LAYOUT_STATUS_UNLOCKED_COUNT_DEFAULT, SbtDefaults.LAYOUT_STATUS_UNLOCKED_COUNT_DEFAULT,
SbtSettings.KEY_LAYOUT_STATUS_ENABLED_UNLOCKED,
SbtDefaults.LAYOUT_STATUS_ENABLED_UNLOCKED_DEFAULT,
SbtSettings::layoutStatusPositionKey, SbtSettings::layoutStatusPositionKey,
SbtSettings::layoutStatusMiddleSideKey, SbtSettings::layoutStatusMiddleSideKey,
SbtSettings::layoutStatusVerticalOffsetKey, SbtSettings::layoutStatusVerticalOffsetKey,
@@ -187,8 +184,6 @@ public final class LayoutFragment extends Fragment {
int sectionTitleId, int sectionTitleId,
String countKey, String countKey,
int countDefault, int countDefault,
String legacyEnabledKey,
boolean legacyEnabledDefault,
SbtSettings.IndexedKey positionKey, SbtSettings.IndexedKey positionKey,
SbtSettings.IndexedKey middleSideKey, SbtSettings.IndexedKey middleSideKey,
SbtSettings.IndexedKey verticalOffsetKey, SbtSettings.IndexedKey verticalOffsetKey,
@@ -223,9 +218,7 @@ public final class LayoutFragment extends Fragment {
int count = ViewTreeSupport.iconContainerCount( int count = ViewTreeSupport.iconContainerCount(
prefs, prefs,
countKey, countKey,
legacyEnabledKey, countDefault);
countDefault,
legacyEnabledDefault);
LayoutXmlCardSupport.setIndexedCardTitle(requireContext(), sourceCard, sectionTitleId, 0, count); LayoutXmlCardSupport.setIndexedCardTitle(requireContext(), sourceCard, sectionTitleId, 0, count);
setCompatPadding(sourceCard, count <= 1); setCompatPadding(sourceCard, count <= 1);
boolean cardsMode = LockedNotificationModeUi.MODE_CARDS.equals( boolean cardsMode = LockedNotificationModeUi.MODE_CARDS.equals(
@@ -246,7 +239,6 @@ public final class LayoutFragment extends Fragment {
requireContext(), requireContext(),
prefs, prefs,
countKey, countKey,
legacyEnabledKey,
value), value),
() -> { () -> {
if (rebuild[0] != null) { if (rebuild[0] != null) {
@@ -868,15 +860,30 @@ public final class LayoutFragment extends Fragment {
} }
private int resolveLeftSideId(RadioGroup group) { private int resolveLeftSideId(RadioGroup group) {
int id = group.getChildCount() > 0 ? group.getChildAt(0).getId() : View.NO_ID; int id = sideButtonId(group, 0);
return id != View.NO_ID ? id : 0; return id != View.NO_ID ? id : 0;
} }
private int resolveRightSideId(RadioGroup group) { private int resolveRightSideId(RadioGroup group) {
int id = group.getChildCount() > 1 ? group.getChildAt(1).getId() : View.NO_ID; int id = sideButtonId(group, 1);
return id != View.NO_ID ? id : resolveLeftSideId(group); return id != View.NO_ID ? id : resolveLeftSideId(group);
} }
private int sideButtonId(RadioGroup group, int radioIndex) {
int seen = 0;
for (int i = 0; i < group.getChildCount(); i++) {
View child = group.getChildAt(i);
if (!(child instanceof RadioButton)) {
continue;
}
if (seen == radioIndex) {
return child.getId();
}
seen++;
}
return View.NO_ID;
}
private void setNumericText(EditText input, int value) { private void setNumericText(EditText input, int value) {
if (input == null) { if (input == null) {
return; return;
@@ -10,6 +10,7 @@ import android.view.ViewGroup;
import android.widget.CheckBox; import android.widget.CheckBox;
import android.widget.EditText; import android.widget.EditText;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import android.widget.RadioButton;
import android.widget.RadioGroup; import android.widget.RadioGroup;
import android.widget.ScrollView; import android.widget.ScrollView;
import android.widget.TextView; import android.widget.TextView;
@@ -173,8 +174,6 @@ abstract class LockedSceneLayoutFragment extends Fragment {
R.id.status_vertical_offset_plus_fast, R.id.status_vertical_offset_plus_fast,
R.id.status_vertical_offset_reset, R.id.status_vertical_offset_reset,
R.string.layout_status_position_title, R.string.layout_status_position_title,
aod ? SbtSettings.KEY_LAYOUT_STATUS_ENABLED_AOD : SbtSettings.KEY_LAYOUT_STATUS_ENABLED_LOCKSCREEN,
aod ? SbtDefaults.LAYOUT_STATUS_ENABLED_AOD_DEFAULT : SbtDefaults.LAYOUT_STATUS_ENABLED_LOCKSCREEN_DEFAULT,
SbtDefaults.LAYOUT_STATUS_POSITION_DEFAULT, SbtDefaults.LAYOUT_STATUS_POSITION_DEFAULT,
SbtDefaults.LAYOUT_STATUS_MIDDLE_SIDE_DEFAULT, SbtDefaults.LAYOUT_STATUS_MIDDLE_SIDE_DEFAULT,
SbtDefaults.LAYOUT_STATUS_VERTICAL_OFFSET_PX_DEFAULT, SbtDefaults.LAYOUT_STATUS_VERTICAL_OFFSET_PX_DEFAULT,
@@ -205,8 +204,6 @@ abstract class LockedSceneLayoutFragment extends Fragment {
R.id.notif_vertical_offset_plus_fast, R.id.notif_vertical_offset_plus_fast,
R.id.notif_vertical_offset_reset, R.id.notif_vertical_offset_reset,
R.string.layout_notification_position_title, R.string.layout_notification_position_title,
aod ? SbtSettings.KEY_LAYOUT_NOTIF_ENABLED_AOD : SbtSettings.KEY_LAYOUT_NOTIF_ENABLED_LOCKSCREEN,
aod ? SbtDefaults.LAYOUT_NOTIF_ENABLED_AOD_DEFAULT : SbtDefaults.LAYOUT_NOTIF_ENABLED_LOCKSCREEN_DEFAULT,
SbtDefaults.LAYOUT_NOTIF_POSITION_DEFAULT, SbtDefaults.LAYOUT_NOTIF_POSITION_DEFAULT,
SbtDefaults.LAYOUT_NOTIF_MIDDLE_SIDE_DEFAULT, SbtDefaults.LAYOUT_NOTIF_MIDDLE_SIDE_DEFAULT,
SbtDefaults.LAYOUT_NOTIF_VERTICAL_OFFSET_PX_DEFAULT, SbtDefaults.LAYOUT_NOTIF_VERTICAL_OFFSET_PX_DEFAULT,
@@ -305,8 +302,6 @@ abstract class LockedSceneLayoutFragment extends Fragment {
int verticalPlusFastId, int verticalPlusFastId,
int verticalResetId, int verticalResetId,
int titleId, int titleId,
String legacyEnabledKey,
boolean legacyEnabledDefault,
String positionDefault, String positionDefault,
String middleSideDefault, String middleSideDefault,
int verticalOffsetDefault, int verticalOffsetDefault,
@@ -324,9 +319,7 @@ abstract class LockedSceneLayoutFragment extends Fragment {
int count = ViewTreeSupport.iconContainerCount( int count = ViewTreeSupport.iconContainerCount(
prefs, prefs,
countKey, countKey,
legacyEnabledKey, 1);
1,
legacyEnabledDefault);
View primary = configuredIconContainerCard( View primary = configuredIconContainerCard(
context, context,
prefs, prefs,
@@ -354,7 +347,6 @@ abstract class LockedSceneLayoutFragment extends Fragment {
verticalOffsetDefault, verticalOffsetDefault,
iconHeightKey, iconHeightKey,
iconHeightDefault, iconHeightDefault,
legacyEnabledKey,
countKey, countKey,
count, count,
rebuild[0]); rebuild[0]);
@@ -390,7 +382,6 @@ abstract class LockedSceneLayoutFragment extends Fragment {
null, null,
0, 0,
null, null,
null,
count, count,
null); null);
setTopMargin(context, copy, 0); setTopMargin(context, copy, 0);
@@ -452,7 +443,6 @@ abstract class LockedSceneLayoutFragment extends Fragment {
int verticalOffsetDefault, int verticalOffsetDefault,
@Nullable String iconHeightKey, @Nullable String iconHeightKey,
int iconHeightDefault, int iconHeightDefault,
@Nullable String legacyEnabledKey,
@Nullable String countKey, @Nullable String countKey,
int count, int count,
@Nullable Runnable onCountChanged @Nullable Runnable onCountChanged
@@ -470,7 +460,6 @@ abstract class LockedSceneLayoutFragment extends Fragment {
context, context,
prefs, prefs,
countKey, countKey,
legacyEnabledKey,
value), value),
onCountChanged), onCountChanged),
insertIndex); insertIndex);
@@ -787,7 +776,7 @@ abstract class LockedSceneLayoutFragment extends Fragment {
private int firstSideId(RadioGroup group, int rightId) { private int firstSideId(RadioGroup group, int rightId) {
for (int i = 0; i < group.getChildCount(); i++) { for (int i = 0; i < group.getChildCount(); i++) {
View child = group.getChildAt(i); View child = group.getChildAt(i);
if (child.getId() != rightId) { if (child instanceof RadioButton && child.getId() != rightId) {
return child.getId(); return child.getId();
} }
} }
@@ -13,6 +13,7 @@ import androidx.activity.OnBackPressedCallback;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.appcompat.app.ActionBarDrawerToggle; import androidx.appcompat.app.ActionBarDrawerToggle;
import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.app.AppCompatActivity;
import androidx.drawerlayout.widget.DrawerLayout;
import androidx.core.graphics.Insets; import androidx.core.graphics.Insets;
import androidx.core.view.GravityCompat; import androidx.core.view.GravityCompat;
import androidx.core.view.ViewCompat; import androidx.core.view.ViewCompat;
@@ -318,13 +319,19 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
permanentNavigationView.setVisibility(View.VISIBLE); permanentNavigationView.setVisibility(View.VISIBLE);
drawerLayout.closeDrawer(GravityCompat.START, false); drawerLayout.closeDrawer(GravityCompat.START, false);
} else { } else {
drawerNavigationView.setVisibility(View.VISIBLE);
drawerLayout.closeDrawer(GravityCompat.START, false); drawerLayout.closeDrawer(GravityCompat.START, false);
permanentNavigationView.setVisibility(View.GONE); permanentNavigationView.setVisibility(View.GONE);
drawerNavigationView.requestLayout();
} }
drawerToggle.syncState(); drawerToggle.syncState();
} }
if (permanentSidebar) {
drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED, GravityCompat.START);
drawerNavigationView.setVisibility(View.GONE);
} else {
drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED, GravityCompat.START);
drawerNavigationView.setVisibility(View.VISIBLE);
drawerNavigationView.requestLayout();
}
updateNavigationHeaderHeight(drawerNavigationView); updateNavigationHeaderHeight(drawerNavigationView);
updateNavigationHeaderHeight(permanentNavigationView); updateNavigationHeaderHeight(permanentNavigationView);
applyPageTitleVisibility(); applyPageTitleVisibility();
@@ -477,8 +477,6 @@ public class SystemIconsFragment extends Fragment {
Set<String> encoded = SystemIconRules.encodeBlockedModes(blockedModes); Set<String> encoded = SystemIconRules.encodeBlockedModes(blockedModes);
prefs.edit() prefs.edit()
.putStringSet(SbtSettings.KEY_SYSTEM_ICON_BLOCKED_MODES, encoded) .putStringSet(SbtSettings.KEY_SYSTEM_ICON_BLOCKED_MODES, encoded)
// Clear legacy key so migration does not keep re-forcing stale global hides.
.putStringSet(SbtSettings.KEY_SYSTEM_ICON_HIDE_SLOTS, Collections.emptySet())
.apply(); .apply();
SbtSettings.ensureReadable(requireContext()); SbtSettings.ensureReadable(requireContext());
} }
@@ -238,25 +238,20 @@ final class ViewTreeSupport {
static int iconContainerCount( static int iconContainerCount(
SharedPreferences prefs, SharedPreferences prefs,
String countKey, String countKey,
String legacyEnabledKey, int defaultCount
int defaultCount,
boolean legacyEnabledDefault
) { ) {
int fallback = prefs.getBoolean(legacyEnabledKey, legacyEnabledDefault) ? defaultCount : 0; return SbtSettings.clampIconContainerCount(prefs.getInt(countKey, defaultCount));
return SbtSettings.clampIconContainerCount(prefs.getInt(countKey, fallback));
} }
static void persistIconContainerCount( static void persistIconContainerCount(
Context context, Context context,
SharedPreferences prefs, SharedPreferences prefs,
String countKey, String countKey,
String legacyEnabledKey,
int count int count
) { ) {
int clamped = SbtSettings.clampIconContainerCount(count); int clamped = SbtSettings.clampIconContainerCount(count);
prefs.edit() prefs.edit()
.putInt(countKey, clamped) .putInt(countKey, clamped)
.putBoolean(legacyEnabledKey, clamped > 0)
.apply(); .apply();
SbtSettings.ensureReadable(context); SbtSettings.ensureReadable(context);
} }
+112 -201
View File
@@ -17,38 +17,6 @@
android:text="@string/battery_bar_title" android:text="@string/battery_bar_title"
android:textAppearance="?attr/textAppearanceHeadline5" /> android:textAppearance="?attr/textAppearanceHeadline5" />
<com.google.android.material.card.MaterialCardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
app:cardUseCompatPadding="true"
app:strokeColor="@color/sbt_card_outline"
app:strokeWidth="1dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="16dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/battery_bar_master_toggle_title"
android:textAppearance="?attr/textAppearanceSubtitle1"
android:textAllCaps="true"
android:letterSpacing="0.03"
android:textStyle="bold" />
<com.google.android.material.switchmaterial.SwitchMaterial
android:id="@+id/battery_bar_enabled_switch"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="@string/battery_bar_enabled" />
</LinearLayout>
</com.google.android.material.card.MaterialCardView>
<LinearLayout <LinearLayout
android:id="@+id/battery_bar_geometry_section" android:id="@+id/battery_bar_geometry_section"
android:layout_width="match_parent" android:layout_width="match_parent"
@@ -72,18 +40,45 @@
<TextView <TextView
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="@string/battery_bar_position_title" android:text="@string/battery_bar_base_settings_title"
android:textAppearance="?attr/textAppearanceSubtitle1" android:textAppearance="?attr/textAppearanceSubtitle1"
android:textAllCaps="true" android:textAllCaps="true"
android:letterSpacing="0.03" android:letterSpacing="0.03"
android:textStyle="bold" /> android:textStyle="bold" />
<com.google.android.material.switchmaterial.SwitchMaterial
android:id="@+id/battery_bar_enabled_switch"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="@string/battery_bar_enabled" />
<LinearLayout
android:id="@+id/battery_bar_base_controls"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:text="@string/battery_bar_position_title"
android:textAppearance="?attr/textAppearanceBody2" />
<RadioGroup <RadioGroup
android:id="@+id/battery_bar_position_group" android:id="@+id/battery_bar_position_group"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="8dp"> android:layout_marginTop="8dp">
<RadioButton
android:id="@+id/battery_bar_curved_geometry_length"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="36dp"
android:text="@string/battery_bar_curved_geometry_length" />
<RadioButton <RadioButton
android:id="@+id/battery_bar_position_top" android:id="@+id/battery_bar_position_top"
android:layout_width="match_parent" android:layout_width="match_parent"
@@ -103,145 +98,8 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="16dp" android:layout_marginTop="16dp"
android:text="@string/battery_bar_thickness_title"
android:textAppearance="?attr/textAppearanceBody2" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:gravity="center_vertical"
android:orientation="horizontal">
<com.google.android.material.button.MaterialButton
android:id="@+id/battery_bar_thickness_minus"
style="?attr/materialButtonOutlinedStyle"
android:layout_width="40dp"
android:layout_height="wrap_content"
android:text="-" />
<EditText
android:id="@+id/battery_bar_thickness_input"
android:layout_width="72dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:ems="3"
android:gravity="center"
android:importantForAutofill="no"
android:inputType="number"
android:maxLines="1"
android:singleLine="true" />
<com.google.android.material.button.MaterialButton
android:id="@+id/battery_bar_thickness_plus"
style="?attr/materialButtonOutlinedStyle"
android:layout_width="40dp"
android:layout_height="wrap_content"
android:text="+" />
</LinearLayout>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="@string/battery_bar_edge_offset_title"
android:textAppearance="?attr/textAppearanceBody2" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:gravity="center_vertical"
android:orientation="horizontal">
<com.google.android.material.button.MaterialButton
android:id="@+id/battery_bar_edge_offset_minus"
style="?attr/materialButtonOutlinedStyle"
android:layout_width="40dp"
android:layout_height="wrap_content"
android:text="-" />
<EditText
android:id="@+id/battery_bar_edge_offset_input"
android:layout_width="72dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:ems="3"
android:gravity="center"
android:importantForAutofill="no"
android:inputType="number"
android:maxLines="1"
android:singleLine="true" />
<com.google.android.material.button.MaterialButton
android:id="@+id/battery_bar_edge_offset_plus"
style="?attr/materialButtonOutlinedStyle"
android:layout_width="40dp"
android:layout_height="wrap_content"
android:text="+" />
</LinearLayout>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="@string/battery_bar_curved_geometry_title"
android:textAppearance="?attr/textAppearanceBody2" />
<RadioGroup
android:id="@+id/battery_bar_curved_geometry_group"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp">
<RadioButton
android:id="@+id/battery_bar_curved_geometry_off"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="36dp"
android:text="@string/battery_bar_curved_geometry_off" />
<RadioButton
android:id="@+id/battery_bar_curved_geometry_horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="36dp"
android:text="@string/battery_bar_curved_geometry_horizontal" />
<RadioButton
android:id="@+id/battery_bar_curved_geometry_length"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="36dp"
android:text="@string/battery_bar_curved_geometry_length" />
</RadioGroup>
</LinearLayout>
</com.google.android.material.card.MaterialCardView>
<com.google.android.material.card.MaterialCardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
app:cardUseCompatPadding="true"
app:strokeColor="@color/sbt_card_outline"
app:strokeWidth="1dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="16dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/battery_bar_alignment_title" android:text="@string/battery_bar_alignment_title"
android:textAppearance="?attr/textAppearanceSubtitle1" android:textAppearance="?attr/textAppearanceBody2" />
android:textAllCaps="true"
android:letterSpacing="0.03"
android:textStyle="bold" />
<LinearLayout <LinearLayout
android:id="@+id/battery_bar_alignment_row" android:id="@+id/battery_bar_alignment_row"
@@ -334,48 +192,101 @@
app:srcCompat="@drawable/sbt_align_rtl" /> app:srcCompat="@drawable/sbt_align_rtl" />
</LinearLayout> </LinearLayout>
</LinearLayout> </LinearLayout>
</LinearLayout>
</com.google.android.material.card.MaterialCardView>
<com.google.android.material.card.MaterialCardView <TextView
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="16dp" android:layout_marginTop="16dp"
app:cardUseCompatPadding="true" android:text="@string/battery_bar_thickness_title"
app:strokeColor="@color/sbt_card_outline"
app:strokeWidth="1dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="16dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:letterSpacing="0.03"
android:text="@string/battery_bar_scenario_overrides_title"
android:textAllCaps="true"
android:textAppearance="?attr/textAppearanceSubtitle1"
android:textStyle="bold" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="@string/battery_bar_scenario_overrides_hint"
android:textAppearance="?attr/textAppearanceBody2" /> android:textAppearance="?attr/textAppearanceBody2" />
<LinearLayout <LinearLayout
android:id="@+id/battery_bar_scenario_overrides_container" android:layout_width="wrap_content"
android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="8dp" android:layout_marginTop="8dp"
android:orientation="vertical" /> android:gravity="center_vertical"
android:orientation="horizontal">
<com.google.android.material.button.MaterialButton
android:id="@+id/battery_bar_thickness_minus"
style="?attr/materialButtonOutlinedStyle"
android:layout_width="40dp"
android:layout_height="wrap_content"
android:text="-" />
<EditText
android:id="@+id/battery_bar_thickness_input"
android:layout_width="72dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:ems="3"
android:gravity="center"
android:importantForAutofill="no"
android:inputType="number"
android:maxLines="1"
android:singleLine="true" />
<com.google.android.material.button.MaterialButton
android:id="@+id/battery_bar_thickness_plus"
style="?attr/materialButtonOutlinedStyle"
android:layout_width="40dp"
android:layout_height="wrap_content"
android:text="+" />
</LinearLayout>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="@string/battery_bar_edge_offset_title"
android:textAppearance="?attr/textAppearanceBody2" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:gravity="center_vertical"
android:orientation="horizontal">
<com.google.android.material.button.MaterialButton
android:id="@+id/battery_bar_edge_offset_minus"
style="?attr/materialButtonOutlinedStyle"
android:layout_width="40dp"
android:layout_height="wrap_content"
android:text="-" />
<EditText
android:id="@+id/battery_bar_edge_offset_input"
android:layout_width="72dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:ems="3"
android:gravity="center"
android:importantForAutofill="no"
android:inputType="number"
android:maxLines="1"
android:singleLine="true" />
<com.google.android.material.button.MaterialButton
android:id="@+id/battery_bar_edge_offset_plus"
style="?attr/materialButtonOutlinedStyle"
android:layout_width="40dp"
android:layout_height="wrap_content"
android:text="+" />
</LinearLayout>
</LinearLayout>
</LinearLayout> </LinearLayout>
</com.google.android.material.card.MaterialCardView> </com.google.android.material.card.MaterialCardView>
<LinearLayout
android:id="@+id/battery_bar_scenario_cards_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" />
<com.google.android.material.card.MaterialCardView <com.google.android.material.card.MaterialCardView
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
+4 -12
View File
@@ -134,10 +134,11 @@
<string name="status_chips_hide_battery_label">Hide charging battery chip (unlocked)</string> <string name="status_chips_hide_battery_label">Hide charging battery chip (unlocked)</string>
<string name="misc_title">Misc</string> <string name="misc_title">Misc</string>
<string name="battery_bar_title">Battery bar</string> <string name="battery_bar_title">Battery bar</string>
<string name="battery_bar_master_toggle_title">Master toggle</string> <string name="battery_bar_base_settings_title">Base settings</string>
<string name="battery_bar_enabled">Enable battery bar</string> <string name="battery_bar_enabled">Enable battery bar</string>
<string name="battery_bar_use_base_settings">Use base settings</string>
<string name="battery_bar_position_title">Position</string> <string name="battery_bar_position_title">Position</string>
<string name="battery_bar_position_top">Top</string> <string name="battery_bar_position_top">Top edge of screen</string>
<string name="battery_bar_position_bottom">Bottom of status bar</string> <string name="battery_bar_position_bottom">Bottom of status bar</string>
<string name="battery_bar_alignment_title">Alignment</string> <string name="battery_bar_alignment_title">Alignment</string>
<string name="battery_bar_alignment_ltr">&#8594;</string> <string name="battery_bar_alignment_ltr">&#8594;</string>
@@ -145,19 +146,10 @@
<string name="battery_bar_alignment_center">&#8596;</string> <string name="battery_bar_alignment_center">&#8596;</string>
<string name="battery_bar_thickness_title">Thickness (dp)</string> <string name="battery_bar_thickness_title">Thickness (dp)</string>
<string name="battery_bar_edge_offset_title">Edge offset (dp)</string> <string name="battery_bar_edge_offset_title">Edge offset (dp)</string>
<string name="battery_bar_curved_geometry_title">Curved top geometry</string> <string name="battery_bar_curved_geometry_length">Follow screen edges</string>
<string name="battery_bar_curved_geometry_off">Off</string>
<string name="battery_bar_curved_geometry_horizontal">On, horizontal position only</string>
<string name="battery_bar_curved_geometry_length">On, actual curve length</string>
<string name="battery_bar_scenario_overrides_title">Scenario overrides</string>
<string name="battery_bar_scenario_overrides_hint">Optional geometry overrides. Disabled scenarios use the default geometry above.</string>
<string name="battery_bar_scenario_group_unlocked">Unlocked</string>
<string name="battery_bar_scenario_group_transparent">Transparent statusbar</string> <string name="battery_bar_scenario_group_transparent">Transparent statusbar</string>
<string name="battery_bar_scenario_group_fullscreen">Fullscreen</string> <string name="battery_bar_scenario_group_fullscreen">Fullscreen</string>
<string name="battery_bar_lockscreen_override">Lockscreen</string> <string name="battery_bar_lockscreen_override">Lockscreen</string>
<string name="battery_bar_edit_override">Edit</string>
<string name="battery_bar_override_dialog_title">Edit %1$s geometry</string>
<string name="battery_bar_override_summary">%1$s, %2$s, %3$ddp thick</string>
<string name="battery_bar_mapping_title">Battery mapping</string> <string name="battery_bar_mapping_title">Battery mapping</string>
<string name="battery_bar_mapping_min_label">...0 at %1$d%%</string> <string name="battery_bar_mapping_min_label">...0 at %1$d%%</string>
<string name="battery_bar_mapping_max_label">...full at %1$d%%</string> <string name="battery_bar_mapping_max_label">...full at %1$d%%</string>
+1 -1
View File
@@ -1 +1 @@
version=0.2 version=0.4