Handle Samsung charging battery chip

This commit is contained in:
ajp_anton
2026-06-17 11:03:38 +00:00
parent 044b6368b8
commit f16e1a8ad5
12 changed files with 423 additions and 4 deletions
@@ -154,8 +154,17 @@ final class BatteryBarController {
return result; return result;
}); });
XposedHookSupport.hookAllMethodsIfExists(framework, View.class, "setAlpha", chain -> { XposedHookSupport.hookAllMethodsIfExists(framework, View.class, "setAlpha", chain -> {
Object result = chain.proceed();
Object target = chain.getThisObject(); Object target = chain.getThisObject();
Object alphaArg = chain.getArgs() != null && !chain.getArgs().isEmpty()
? chain.getArgs().get(0)
: null;
if (target instanceof View root
&& alphaArg instanceof Float alpha
&& roots.contains(root)
&& shouldBlockChargingChipRootAlpha(root, alpha)) {
return null;
}
Object result = chain.proceed();
if (target instanceof View root && roots.contains(root)) { if (target instanceof View root && roots.contains(root)) {
applyBatteryBarAfterRootTransform(root); applyBatteryBarAfterRootTransform(root);
} }
@@ -271,6 +280,7 @@ final class BatteryBarController {
} }
int result = 17; int result = 17;
result = 31 * result + root.getVisibility(); result = 31 * result + root.getVisibility();
result = 31 * result + Float.floatToIntBits(root.getAlpha());
result = 31 * result + Float.floatToIntBits(root.getY()); result = 31 * result + Float.floatToIntBits(root.getY());
result = 31 * result + Float.floatToIntBits(root.getTranslationY()); result = 31 * result + Float.floatToIntBits(root.getTranslationY());
result = 31 * result + root.getWidth(); result = 31 * result + root.getWidth();
@@ -378,11 +388,11 @@ final class BatteryBarController {
return; return;
} }
int color = resolveBarColor(root, settings); int color = resolveBarColor(root, settings);
BatteryBarGeometry.Scenario scenario = scenarioForRoot(root);
if (!shouldRenderOnRoot(root)) { if (!shouldRenderOnRoot(root)) {
removeBatteryBarView(root); removeBatteryBarView(root);
return; return;
} }
BatteryBarGeometry.Scenario scenario = scenarioForRoot(root);
boolean transientStatusBarReveal = isFullscreenScenario(scenario) boolean transientStatusBarReveal = isFullscreenScenario(scenario)
&& shouldRenderVisibleFullscreenBar(root); && shouldRenderVisibleFullscreenBar(root);
if (transientStatusBarReveal) { if (transientStatusBarReveal) {
@@ -593,6 +603,14 @@ final class BatteryBarController {
return true; return true;
} }
private boolean shouldBlockChargingChipRootAlpha(View root, float alpha) {
return alpha < 0.99f
&& isPhoneRoot(root)
&& isUnlockedScene()
&& !isFullscreenSystemBarState()
&& hasSamsungBatteryStatusChip(root);
}
private boolean isUnlockedScene() { private boolean isUnlockedScene() {
SceneKey scene = runtimeContext.getModeStateRepository().getActiveScene(); SceneKey scene = runtimeContext.getModeStateRepository().getActiveScene();
return scene == null || scene.isUnlocked(); return scene == null || scene.isUnlocked();
@@ -758,6 +776,32 @@ final class BatteryBarController {
return bottom <= 0f || top >= screenHeight || right <= 0f || left >= screenWidth; return bottom <= 0f || top >= screenHeight || right <= 0f || left >= screenWidth;
} }
private boolean hasSamsungBatteryStatusChip(View root) {
if (!(root != null && root.getRootView() instanceof ViewGroup rootView)) {
return false;
}
return findSamsungBatteryStatusChip(rootView) != null;
}
private View findSamsungBatteryStatusChip(View view) {
if (view == null) {
return null;
}
if (view.getClass().getName().contains("SamsungBatteryStatusChip")) {
return view;
}
if (!(view instanceof ViewGroup group)) {
return null;
}
for (int i = 0; i < group.getChildCount(); i++) {
View found = findSamsungBatteryStatusChip(group.getChildAt(i));
if (found != null) {
return found;
}
}
return null;
}
private static Integer asInteger(Object value) { private static Integer asInteger(Object value) {
return value instanceof Integer integer ? integer : null; return value instanceof Integer integer ? integer : null;
} }
@@ -414,6 +414,9 @@ final class StockLayoutCanvasController {
if (shouldSuppressTrackedStatusChipAlpha(view, alpha)) { if (shouldSuppressTrackedStatusChipAlpha(view, alpha)) {
return null; return null;
} }
if (shouldSuppressSamsungBatteryStatusChipAlpha(view, alpha)) {
return null;
}
if (shouldCaptureAodVisualAlpha(view)) { if (shouldCaptureAodVisualAlpha(view)) {
rememberAodPluginVisualAlpha(view, alpha); rememberAodPluginVisualAlpha(view, alpha);
} }
@@ -424,6 +427,9 @@ final class StockLayoutCanvasController {
Object target = chain.getThisObject(); Object target = chain.getThisObject();
Object visibilityArg = firstArg(chain.getArgs()); Object visibilityArg = firstArg(chain.getArgs());
if (target instanceof View view && visibilityArg instanceof Integer visibility) { if (target instanceof View view && visibilityArg instanceof Integer visibility) {
if (shouldSuppressSamsungBatteryStatusChipVisibility(view, visibility)) {
return null;
}
if (shouldSuppressTrackedStatusChipVisibility(view, visibility)) { if (shouldSuppressTrackedStatusChipVisibility(view, visibility)) {
return null; return null;
} }
@@ -3286,6 +3292,9 @@ final class StockLayoutCanvasController {
if (confirmedAodPluginViews.contains(view)) { if (confirmedAodPluginViews.contains(view)) {
return true; return true;
} }
if (isSamsungBatteryStatusChipSurface(view)) {
return true;
}
String idName = ViewIdNames.idName(view); String idName = ViewIdNames.idName(view);
if (TARGET_ID_NAMES.contains(idName)) { if (TARGET_ID_NAMES.contains(idName)) {
return true; return true;
@@ -3300,6 +3309,41 @@ final class StockLayoutCanvasController {
return containsAny(className, TARGET_CLASS_SUBSTRINGS); return containsAny(className, TARGET_CLASS_SUBSTRINGS);
} }
private boolean isSamsungBatteryStatusChipSurface(View view) {
return view != null && view.getClass().getName().contains("SamsungBatteryStatusChip");
}
private boolean shouldSuppressSamsungBatteryStatusChipAlpha(View view, float alpha) {
if (alpha <= 0f || ownHiddenViewAlphaWriteDepth > 0 || !isSamsungBatteryStatusChipSurface(view)) {
return false;
}
if (!shouldSuppressSamsungBatteryStatusChip(view)) {
return false;
}
hideView(view, true);
return true;
}
private boolean shouldSuppressSamsungBatteryStatusChipVisibility(View view, int visibility) {
if (visibility != View.VISIBLE
|| ownHiddenViewAlphaWriteDepth > 0
|| !isSamsungBatteryStatusChipSurface(view)) {
return false;
}
if (!shouldSuppressSamsungBatteryStatusChip(view)) {
return false;
}
hideView(view, true);
return true;
}
private boolean shouldSuppressSamsungBatteryStatusChip(View view) {
if (view == null || !view.isAttachedToWindow() || !isLayoutEnabled(view.getContext())) {
return false;
}
return true;
}
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;
@@ -34,6 +34,10 @@ final class SnapshotIconFilter {
} }
ArrayList<SnapshotPlacement> filtered = new ArrayList<>(placements.size()); ArrayList<SnapshotPlacement> filtered = new ArrayList<>(placements.size());
for (SnapshotPlacement placement : placements) { for (SnapshotPlacement placement : placements) {
if (isChargingBatteryChipPlacement(placement)) {
filtered.add(placement);
continue;
}
if (!isStatusBlocked(placement, settings.systemIconBlockedModes, mode)) { if (!isStatusBlocked(placement, settings.systemIconBlockedModes, mode)) {
filtered.add(placement); filtered.add(placement);
} }
@@ -109,6 +113,11 @@ final class SnapshotIconFilter {
return false; return false;
} }
private static boolean isChargingBatteryChipPlacement(SnapshotPlacement placement) {
return placement != null
&& SnapshotKeys.CHARGING_BATTERY_CHIP.equals(placement.key);
}
private static AppIconRules.ExceptionRule matchingExceptionRule( private static AppIconRules.ExceptionRule matchingExceptionRule(
SnapshotPlacement placement, SnapshotPlacement placement,
ArrayList<AppIconRules.ExceptionRule> rules ArrayList<AppIconRules.ExceptionRule> rules
@@ -36,6 +36,7 @@ final class SnapshotKeys {
static final String OVERFLOW_DOT = "statusbartweak:overflow_dot"; static final String OVERFLOW_DOT = "statusbartweak:overflow_dot";
static final String EMPTY_CHIP = "statusbartweak:empty_chip"; static final String EMPTY_CHIP = "statusbartweak:empty_chip";
static final String EMPTY_ICON_CONTAINER = "statusbartweak:empty_icon_container"; static final String EMPTY_ICON_CONTAINER = "statusbartweak:empty_icon_container";
static final String CHARGING_BATTERY_CHIP = "statusbartweak:charging_battery_chip";
private SnapshotKeys() { private SnapshotKeys() {
} }
@@ -1,15 +1,19 @@
package se.ajpanton.statusbartweak.runtime.render; package se.ajpanton.statusbartweak.runtime.render;
import android.content.Context; import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.graphics.Canvas; import android.graphics.Canvas;
import android.graphics.Color; import android.graphics.Color;
import android.graphics.Paint; import android.graphics.Paint;
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.drawable.BitmapDrawable; import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.os.BatteryManager;
import android.text.TextUtils; import android.text.TextUtils;
import android.os.SystemClock; import android.os.SystemClock;
import android.view.View; import android.view.View;
@@ -34,6 +38,7 @@ import se.ajpanton.statusbartweak.runtime.NotificationKeyReflection;
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;
import se.ajpanton.statusbartweak.runtime.settings.BroadcastReceiverSupport;
final class SnapshotRenderer { final class SnapshotRenderer {
private static final long TRANSITION_SIGNAL_HOLD_MS = 700L; private static final long TRANSITION_SIGNAL_HOLD_MS = 700L;
@@ -336,6 +341,7 @@ final class SnapshotRenderer {
private boolean shouldTrimContent(SnapshotSource source) { private boolean shouldTrimContent(SnapshotSource source) {
return trimViewContentForCollision return trimViewContentForCollision
&& source != null && source != null
&& !SnapshotKeys.CHARGING_BATTERY_CHIP.equals(source.keyHint())
&& (source.mode() == SnapshotMode.VIEW || source.mode() == SnapshotMode.STATUS_CHIP); && (source.mode() == SnapshotMode.VIEW || source.mode() == SnapshotMode.STATUS_CHIP);
} }
@@ -713,6 +719,10 @@ final class SnapshotRenderer {
if (offsetX != 0) { if (offsetX != 0) {
canvas.translate(-offsetX, 0); canvas.translate(-offsetX, 0);
} }
if (isChargingBatteryChipSource(source)) {
drawChargingBatteryChip(source, bitmap);
return;
}
View sourceView = source.view(); View sourceView = source.view();
if (sourceView == null) { if (sourceView == null) {
return; return;
@@ -823,6 +833,152 @@ final class SnapshotRenderer {
&& source.mode() != SnapshotMode.STATUS_CHIP; && source.mode() != SnapshotMode.STATUS_CHIP;
} }
private boolean isChargingBatteryChipSource(SnapshotSource source) {
return source != null && SnapshotKeys.CHARGING_BATTERY_CHIP.equals(source.keyHint());
}
private void drawChargingBatteryChip(SnapshotSource source, Bitmap bitmap) {
if (source == null
|| bitmap == null
|| bitmap.isRecycled()
|| bitmap.getWidth() <= 0
|| bitmap.getHeight() <= 0) {
return;
}
bitmap.eraseColor(Color.TRANSPARENT);
int width = bitmap.getWidth();
int height = bitmap.getHeight();
float inset = Math.max(1f, height * 0.05f);
RectF pill = new RectF(inset, inset, width - inset, height - inset);
float radius = pill.height() / 2f;
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG);
paint.setColor(Color.argb(235, 42, 45, 49));
Canvas canvas = new Canvas(bitmap);
canvas.drawRoundRect(pill, radius, radius, paint);
int level = chargingBatteryLevel(source.view());
float gaugeWidth = Math.min(pill.width(), Math.max(height * 1.35f, pill.width() * 0.42f));
float fillRight = pill.left + gaugeWidth * Math.max(0f, Math.min(100f, level)) / 100f;
if (fillRight > pill.left) {
Path clip = new Path();
clip.addRoundRect(pill, radius, radius, Path.Direction.CW);
int save = canvas.save();
canvas.clipPath(clip);
paint.setColor(Color.rgb(42, 220, 103));
canvas.drawRect(pill.left, pill.top, fillRight, pill.bottom, paint);
canvas.restoreToCount(save);
}
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(Math.max(1f, height * 0.035f));
paint.setColor(Color.argb(120, 255, 255, 255));
canvas.drawRoundRect(pill, radius, radius, paint);
paint.setStyle(Paint.Style.FILL);
drawChargingBolt(canvas, paint, pill.left + height * 0.48f, height / 2f, height * 0.55f);
String text = chargingBatteryText(source.view(), level);
paint.setTextAlign(Paint.Align.RIGHT);
paint.setFakeBoldText(true);
paint.setColor(Color.WHITE);
paint.setTextSize(Math.max(1f, height * 0.42f));
Paint.FontMetrics metrics = paint.getFontMetrics();
float baseline = height / 2f - (metrics.ascent + metrics.descent) / 2f;
canvas.drawText(text, pill.right - Math.max(2f, height * 0.18f), baseline, paint);
paint.setFakeBoldText(false);
}
private void drawChargingBolt(Canvas canvas, Paint paint, float centerX, float centerY, float size) {
float half = size / 2f;
Path bolt = new Path();
bolt.moveTo(centerX + half * 0.10f, centerY - half);
bolt.lineTo(centerX - half * 0.42f, centerY + half * 0.08f);
bolt.lineTo(centerX - half * 0.04f, centerY + half * 0.08f);
bolt.lineTo(centerX - half * 0.18f, centerY + half);
bolt.lineTo(centerX + half * 0.44f, centerY - half * 0.18f);
bolt.lineTo(centerX + half * 0.04f, centerY - half * 0.18f);
bolt.close();
paint.setColor(Color.WHITE);
paint.setStyle(Paint.Style.FILL);
canvas.drawPath(bolt, paint);
}
private String chargingBatteryText(View source, int fallbackLevel) {
CharSequence text = findChargingBatteryText(source);
if (text != null && text.length() > 0) {
return text.toString();
}
return Math.max(0, Math.min(100, fallbackLevel)) + "%";
}
private int chargingBatteryLevel(View source) {
CharSequence text = findChargingBatteryText(source);
int parsed = parsePercent(text);
if (parsed >= 0) {
return parsed;
}
Integer stickyLevel = stickyBatteryLevel(source != null ? source.getContext() : null);
return stickyLevel != null ? stickyLevel : 100;
}
private Integer stickyBatteryLevel(Context context) {
if (context == null) {
return null;
}
Intent intent = BroadcastReceiverSupport.readExportedSticky(
context,
BroadcastReceiverSupport.filter(Intent.ACTION_BATTERY_CHANGED));
if (intent == null) {
return null;
}
int level = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
int scale = intent.getIntExtra(BatteryManager.EXTRA_SCALE, 100);
if (level < 0 || scale <= 0) {
return null;
}
return Math.max(0, Math.min(100, Math.round(level * 100f / scale)));
}
private CharSequence findChargingBatteryText(View source) {
if (source == null) {
return null;
}
if (source instanceof TextView textView) {
CharSequence text = textView.getText();
if (parsePercent(text) >= 0) {
return text;
}
}
if (!(source instanceof ViewGroup group)) {
return null;
}
for (int i = 0; i < group.getChildCount(); i++) {
CharSequence text = findChargingBatteryText(group.getChildAt(i));
if (text != null && text.length() > 0) {
return text;
}
}
return null;
}
private int parsePercent(CharSequence text) {
if (text == null) {
return -1;
}
int value = 0;
boolean found = false;
for (int i = 0; i < text.length(); i++) {
char c = text.charAt(i);
if (c >= '0' && c <= '9') {
value = value * 10 + c - '0';
found = true;
} else if (found) {
break;
}
}
return found ? Math.max(0, Math.min(100, value)) : -1;
}
private boolean isTintableMonochrome(Bitmap bitmap) { private boolean isTintableMonochrome(Bitmap bitmap) {
int coloredPixels = 0; int coloredPixels = 0;
int monochromePixels = 0; int monochromePixels = 0;
@@ -1112,7 +1112,9 @@ final class UnlockedLayoutPlanner {
if (bounds == null || bounds.height <= 0) { if (bounds == null || bounds.height <= 0) {
continue; continue;
} }
int width = Math.max(1, Math.round((float) bounds.width * targetHeight / bounds.height)); int width = isChargingBatteryChipPlacement(placement)
? chargingBatteryChipWidth(targetHeight)
: Math.max(1, Math.round((float) bounds.width * targetHeight / bounds.height));
int bottom = bounds.top + bounds.height; int bottom = bounds.top + bounds.height;
Bounds resized = new Bounds(bounds.left, bottom - targetHeight, width, targetHeight); Bounds resized = new Bounds(bounds.left, bottom - targetHeight, width, targetHeight);
result.add(new SnapshotPlacement( result.add(new SnapshotPlacement(
@@ -1130,6 +1132,15 @@ final class UnlockedLayoutPlanner {
return result; return result;
} }
private boolean isChargingBatteryChipPlacement(SnapshotPlacement placement) {
return placement != null
&& SnapshotKeys.CHARGING_BATTERY_CHIP.equals(placement.key);
}
private int chargingBatteryChipWidth(int height) {
return Math.max(1, Math.round(Math.max(1, height) * 2.7f));
}
private Bounds sourceRenderBoundsForResize(SnapshotPlacement placement) { private Bounds sourceRenderBoundsForResize(SnapshotPlacement placement) {
if (placement == null || placement.source == null || placement.bounds == null) { if (placement == null || placement.source == null || placement.bounds == null) {
return placement != null ? placement.sourceRenderBounds : null; return placement != null ? placement.sourceRenderBounds : null;
@@ -1,7 +1,10 @@
package se.ajpanton.statusbartweak.runtime.render; package se.ajpanton.statusbartweak.runtime.render;
import android.content.Context;
import android.content.Intent;
import android.graphics.Rect; import android.graphics.Rect;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.os.BatteryManager;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.ImageView; import android.widget.ImageView;
@@ -23,6 +26,7 @@ import se.ajpanton.statusbartweak.runtime.mode.NotificationDisplayStyle;
import se.ajpanton.statusbartweak.runtime.mode.SceneKey; import se.ajpanton.statusbartweak.runtime.mode.SceneKey;
import se.ajpanton.statusbartweak.runtime.notifications.NotificationActiveKeyStore; import se.ajpanton.statusbartweak.runtime.notifications.NotificationActiveKeyStore;
import se.ajpanton.statusbartweak.runtime.notifications.NotificationUnreadTracker; import se.ajpanton.statusbartweak.runtime.notifications.NotificationUnreadTracker;
import se.ajpanton.statusbartweak.runtime.settings.BroadcastReceiverSupport;
import se.ajpanton.statusbartweak.shell.settings.SbtDefaults; import se.ajpanton.statusbartweak.shell.settings.SbtDefaults;
import se.ajpanton.statusbartweak.shell.settings.SbtSettings; import se.ajpanton.statusbartweak.shell.settings.SbtSettings;
@@ -74,6 +78,7 @@ final class UnlockedStockSourceCollector {
if (anchors.battery != null && !ViewGeometry.isDescendantOf(anchors.battery, anchors.statusRoot)) { if (anchors.battery != null && !ViewGeometry.isDescendantOf(anchors.battery, anchors.statusRoot)) {
collectStatusSnapshotViews(anchors.battery, statusIcons); collectStatusSnapshotViews(anchors.battery, statusIcons);
} }
addSamsungBatteryStatusChipSource(root, statusIcons, settings);
selectDualSimStatusSignals(statusIcons, settings); selectDualSimStatusSignals(statusIcons, settings);
normalizeStatusIconSourceBounds(root, statusIcons); normalizeStatusIconSourceBounds(root, statusIcons);
if (scene != null && scene.isAod()) { if (scene != null && scene.isAod()) {
@@ -185,6 +190,7 @@ final class UnlockedStockSourceCollector {
: 0; : 0;
int statusSourceSignature = sourceLayoutListSignature( int statusSourceSignature = sourceLayoutListSignature(
previousIcons != null ? previousIcons.statusIcons : null); previousIcons != null ? previousIcons.statusIcons : null);
statusSourceSignature = 31 * statusSourceSignature + batteryChargingSignature(root);
if (scene != null && scene.isAod()) { if (scene != null && scene.isAod()) {
statusSourceSignature = 31 * statusSourceSignature statusSourceSignature = 31 * statusSourceSignature
+ aodLayoutAnchorSignature(root, anchors, scene); + aodLayoutAnchorSignature(root, anchors, scene);
@@ -880,6 +886,132 @@ final class UnlockedStockSourceCollector {
} }
} }
private void addSamsungBatteryStatusChipSource(
View root,
ArrayList<SnapshotSource> sources,
SbtSettings settings
) {
if (root == null
|| sources == null
|| settings == null
|| settings.statusChipsHideAll
|| settings.statusChipsHideBattery
|| !isDevicePlugged(root.getContext())) {
return;
}
View chip = samsungBatteryStatusChip(root);
if (chip == null) {
return;
}
removeBatteryStatusSources(sources);
Bounds bounds = ViewGeometry.boundsRelativeTo(root, chip);
sources.add(new SnapshotSource(
chip,
SnapshotMode.STATUS_CHIP,
SnapshotKeys.CHARGING_BATTERY_CHIP,
validBounds(bounds) ? bounds : null));
}
private View samsungBatteryStatusChip(View root) {
if (root == null) {
return null;
}
ArrayDeque<View> queue = new ArrayDeque<>();
queue.add(root);
while (!queue.isEmpty()) {
View view = queue.removeFirst();
if (isSamsungBatteryStatusChip(view) && hasUsableSamsungBatteryStatusChipBounds(root, view)) {
return view;
}
if (view instanceof ViewGroup group) {
for (int i = 0; i < group.getChildCount(); i++) {
View child = group.getChildAt(i);
if (child != null) {
queue.addLast(child);
}
}
}
}
return null;
}
private boolean hasUsableSamsungBatteryStatusChipBounds(View root, View view) {
if (root == null
|| view == null
|| view == root
|| !view.isAttachedToWindow()
|| view.getVisibility() != View.VISIBLE
|| (view.getAlpha() <= 0f && !hasVisibleStatusChipContent(view))) {
return false;
}
Bounds bounds = ViewGeometry.boundsRelativeTo(root, view);
return validBounds(bounds)
&& bounds.top >= 0
&& bounds.top <= root.getHeight()
&& bounds.width < root.getWidth() / 2;
}
private boolean validBounds(Bounds bounds) {
return bounds != null && bounds.width > 0 && bounds.height > 0;
}
private void removeBatteryStatusSources(ArrayList<SnapshotSource> sources) {
if (sources == null || sources.isEmpty()) {
return;
}
for (int i = sources.size() - 1; i >= 0; i--) {
SnapshotSource source = sources.get(i);
if (isBatteryStatusSource(source)) {
sources.remove(i);
}
}
}
private boolean isBatteryStatusSource(SnapshotSource source) {
View view = source != null ? source.view() : null;
StringBuilder sb = new StringBuilder();
append(sb, source != null ? source.keyHint() : null);
append(sb, reflectString(view, "getSlot", "mSlot", "slot"));
append(sb, view != null ? ViewIdNames.idName(view) : null);
append(sb, view != null ? view.getClass().getName() : null);
return sb.toString().toLowerCase(Locale.ROOT).contains("battery");
}
private boolean isSamsungBatteryStatusChip(View view) {
return view != null && view.getClass().getName().contains("SamsungBatteryStatusChip");
}
private int batteryChargingSignature(View root) {
return root != null && isDevicePlugged(root.getContext()) ? 1 : 0;
}
private boolean isDevicePlugged(Context context) {
Intent intent = batteryIntent(context);
if (intent == null) {
return false;
}
int status = intent.getIntExtra(BatteryManager.EXTRA_STATUS, -1);
return intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0) != 0
|| status == BatteryManager.BATTERY_STATUS_CHARGING
|| status == BatteryManager.BATTERY_STATUS_FULL;
}
private Intent batteryIntent(Context context) {
if (context == null) {
return null;
}
return BroadcastReceiverSupport.readExportedSticky(
context,
BroadcastReceiverSupport.filter(Intent.ACTION_BATTERY_CHANGED));
}
private void append(StringBuilder sb, String value) {
if (sb == null || value == null || value.isEmpty()) {
return;
}
sb.append(';').append(value);
}
private int normalizedStatusIconWidth(int drawableWidth, int iconHeight) { private int normalizedStatusIconWidth(int drawableWidth, int iconHeight) {
return Math.max(1, drawableWidth + statusIconHorizontalPadding(iconHeight)); return Math.max(1, drawableWidth + statusIconHorizontalPadding(iconHeight));
} }
@@ -1556,7 +1688,8 @@ final class UnlockedStockSourceCollector {
settings.statusChipsHideAll, settings.statusChipsHideAll,
settings.statusChipsHideMediaUnlocked, settings.statusChipsHideMediaUnlocked,
settings.statusChipsHideNavUnlocked, settings.statusChipsHideNavUnlocked,
settings.statusChipsHideCallUnlocked); settings.statusChipsHideCallUnlocked,
settings.statusChipsHideBattery);
} }
} }
@@ -64,6 +64,7 @@ public final class SbtSettings {
public static final String KEY_STATUS_CHIPS_HIDE_MEDIA_UNLOCKED = "status_chips_hide_media_unlocked"; public static final String KEY_STATUS_CHIPS_HIDE_MEDIA_UNLOCKED = "status_chips_hide_media_unlocked";
public static final String KEY_STATUS_CHIPS_HIDE_NAV_UNLOCKED = "status_chips_hide_nav_unlocked"; public static final String KEY_STATUS_CHIPS_HIDE_NAV_UNLOCKED = "status_chips_hide_nav_unlocked";
public static final String KEY_STATUS_CHIPS_HIDE_CALL = "status_chips_hide_call"; public static final String KEY_STATUS_CHIPS_HIDE_CALL = "status_chips_hide_call";
public static final String KEY_STATUS_CHIPS_HIDE_BATTERY = "status_chips_hide_battery";
public static final String KEY_AOD_KEEP_VISIBLE_DURING_CALL = "aod_keep_visible_during_call"; public static final String KEY_AOD_KEEP_VISIBLE_DURING_CALL = "aod_keep_visible_during_call";
public static final String KEY_BATTERY_LOCKSCREEN_UNPLUGGED_PERCENT = "battery_lockscreen_unplugged_percent"; public static final String KEY_BATTERY_LOCKSCREEN_UNPLUGGED_PERCENT = "battery_lockscreen_unplugged_percent";
public static final String KEY_BATTERY_AOD_UNPLUGGED_PERCENT = "battery_aod_unplugged_percent"; public static final String KEY_BATTERY_AOD_UNPLUGGED_PERCENT = "battery_aod_unplugged_percent";
@@ -408,6 +409,7 @@ public final class SbtSettings {
public final boolean statusChipsHideMediaUnlocked; public final boolean statusChipsHideMediaUnlocked;
public final boolean statusChipsHideNavUnlocked; public final boolean statusChipsHideNavUnlocked;
public final boolean statusChipsHideCallUnlocked; public final boolean statusChipsHideCallUnlocked;
public final boolean statusChipsHideBattery;
public final Map<String, Integer> appIconBlockedModes; public final Map<String, Integer> appIconBlockedModes;
public final Map<String, ArrayList<AppIconRules.ExceptionRule>> appIconExceptionRules; public final Map<String, ArrayList<AppIconRules.ExceptionRule>> appIconExceptionRules;
public final String lockedNotificationMode; public final String lockedNotificationMode;
@@ -540,6 +542,7 @@ public final class SbtSettings {
boolean statusChipsHideMediaUnlocked, boolean statusChipsHideMediaUnlocked,
boolean statusChipsHideNavUnlocked, boolean statusChipsHideNavUnlocked,
boolean statusChipsHideCallUnlocked, boolean statusChipsHideCallUnlocked,
boolean statusChipsHideBattery,
Map<String, Integer> appIconBlockedModes, Map<String, Integer> appIconBlockedModes,
Map<String, ArrayList<AppIconRules.ExceptionRule>> appIconExceptionRules, Map<String, ArrayList<AppIconRules.ExceptionRule>> appIconExceptionRules,
String lockedNotificationMode, String lockedNotificationMode,
@@ -827,6 +830,7 @@ public final class SbtSettings {
this.statusChipsHideMediaUnlocked = statusChipsHideMediaUnlocked; this.statusChipsHideMediaUnlocked = statusChipsHideMediaUnlocked;
this.statusChipsHideNavUnlocked = statusChipsHideNavUnlocked; this.statusChipsHideNavUnlocked = statusChipsHideNavUnlocked;
this.statusChipsHideCallUnlocked = statusChipsHideCallUnlocked; this.statusChipsHideCallUnlocked = statusChipsHideCallUnlocked;
this.statusChipsHideBattery = statusChipsHideBattery;
this.appIconBlockedModes = appIconBlockedModes != null this.appIconBlockedModes = appIconBlockedModes != null
? Collections.unmodifiableMap(new HashMap<>(appIconBlockedModes)) ? Collections.unmodifiableMap(new HashMap<>(appIconBlockedModes))
: Collections.emptyMap(); : Collections.emptyMap();
@@ -975,6 +979,7 @@ public final class SbtSettings {
false, false,
false, false,
false, false,
false,
Collections.emptyMap(), Collections.emptyMap(),
Collections.emptyMap(), Collections.emptyMap(),
"dot", "dot",
@@ -1422,6 +1427,7 @@ public final class SbtSettings {
prefs.getBoolean(KEY_STATUS_CHIPS_HIDE_MEDIA_UNLOCKED, false), prefs.getBoolean(KEY_STATUS_CHIPS_HIDE_MEDIA_UNLOCKED, false),
prefs.getBoolean(KEY_STATUS_CHIPS_HIDE_NAV_UNLOCKED, false), prefs.getBoolean(KEY_STATUS_CHIPS_HIDE_NAV_UNLOCKED, false),
prefs.getBoolean(KEY_STATUS_CHIPS_HIDE_CALL, false), prefs.getBoolean(KEY_STATUS_CHIPS_HIDE_CALL, false),
prefs.getBoolean(KEY_STATUS_CHIPS_HIDE_BATTERY, false),
AppIconRules.parseBlockedModes(readStringSetFromPrefs( AppIconRules.parseBlockedModes(readStringSetFromPrefs(
prefs, prefs,
KEY_APP_ICON_BLOCKED_MODES)), KEY_APP_ICON_BLOCKED_MODES)),
@@ -1740,6 +1746,7 @@ public final class SbtSettings {
bundle.getBoolean(KEY_STATUS_CHIPS_HIDE_MEDIA_UNLOCKED, false), bundle.getBoolean(KEY_STATUS_CHIPS_HIDE_MEDIA_UNLOCKED, false),
bundle.getBoolean(KEY_STATUS_CHIPS_HIDE_NAV_UNLOCKED, false), bundle.getBoolean(KEY_STATUS_CHIPS_HIDE_NAV_UNLOCKED, false),
bundle.getBoolean(KEY_STATUS_CHIPS_HIDE_CALL, false), bundle.getBoolean(KEY_STATUS_CHIPS_HIDE_CALL, false),
bundle.getBoolean(KEY_STATUS_CHIPS_HIDE_BATTERY, false),
AppIconRules.parseBlockedModes(readStringSetFromBundle( AppIconRules.parseBlockedModes(readStringSetFromBundle(
bundle, bundle,
KEY_APP_ICON_BLOCKED_MODES)), KEY_APP_ICON_BLOCKED_MODES)),
@@ -412,6 +412,8 @@ public class SbtSettingsProvider extends ContentProvider {
prefs.getBoolean(SbtSettings.KEY_STATUS_CHIPS_HIDE_NAV_UNLOCKED, false)); prefs.getBoolean(SbtSettings.KEY_STATUS_CHIPS_HIDE_NAV_UNLOCKED, false));
out.putBoolean(SbtSettings.KEY_STATUS_CHIPS_HIDE_CALL, out.putBoolean(SbtSettings.KEY_STATUS_CHIPS_HIDE_CALL,
prefs.getBoolean(SbtSettings.KEY_STATUS_CHIPS_HIDE_CALL, false)); prefs.getBoolean(SbtSettings.KEY_STATUS_CHIPS_HIDE_CALL, false));
out.putBoolean(SbtSettings.KEY_STATUS_CHIPS_HIDE_BATTERY,
prefs.getBoolean(SbtSettings.KEY_STATUS_CHIPS_HIDE_BATTERY, false));
putStringCollectionArrayList( putStringCollectionArrayList(
out, out,
SbtSettings.KEY_APP_ICON_BLOCKED_MODES, SbtSettings.KEY_APP_ICON_BLOCKED_MODES,
@@ -45,6 +45,11 @@ public class StatusChipsFragment extends Fragment {
SbtSettings.KEY_STATUS_CHIPS_HIDE_CALL, SbtSettings.KEY_STATUS_CHIPS_HIDE_CALL,
false, false,
true); true);
ViewTreeSupport.bindBooleanPreference(requireContext(), prefs, root,
R.id.status_chips_hide_battery_switch,
SbtSettings.KEY_STATUS_CHIPS_HIDE_BATTERY,
false,
true);
return root; return root;
} }
} }
@@ -47,6 +47,12 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="@string/status_chips_hide_call_unlocked_label" /> android:text="@string/status_chips_hide_call_unlocked_label" />
<com.google.android.material.switchmaterial.SwitchMaterial
android:id="@+id/status_chips_hide_battery_switch"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/status_chips_hide_battery_label" />
</LinearLayout> </LinearLayout>
</com.google.android.material.card.MaterialCardView> </com.google.android.material.card.MaterialCardView>
+1
View File
@@ -131,6 +131,7 @@
<string name="status_chips_hide_media_unlocked_label">Hide media chip (unlocked)</string> <string name="status_chips_hide_media_unlocked_label">Hide media chip (unlocked)</string>
<string name="status_chips_hide_navigation_unlocked_label">Hide navigation chip (unlocked)</string> <string name="status_chips_hide_navigation_unlocked_label">Hide navigation chip (unlocked)</string>
<string name="status_chips_hide_call_unlocked_label">Hide call chip (unlocked)</string> <string name="status_chips_hide_call_unlocked_label">Hide call chip (unlocked)</string>
<string name="status_chips_hide_battery_label">Hide charging battery chip</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_master_toggle_title">Master toggle</string>