Handle Samsung charging battery chip
This commit is contained in:
+46
-2
@@ -154,8 +154,17 @@ final class BatteryBarController {
|
||||
return result;
|
||||
});
|
||||
XposedHookSupport.hookAllMethodsIfExists(framework, View.class, "setAlpha", chain -> {
|
||||
Object result = chain.proceed();
|
||||
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)) {
|
||||
applyBatteryBarAfterRootTransform(root);
|
||||
}
|
||||
@@ -271,6 +280,7 @@ final class BatteryBarController {
|
||||
}
|
||||
int result = 17;
|
||||
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.getTranslationY());
|
||||
result = 31 * result + root.getWidth();
|
||||
@@ -378,11 +388,11 @@ final class BatteryBarController {
|
||||
return;
|
||||
}
|
||||
int color = resolveBarColor(root, settings);
|
||||
BatteryBarGeometry.Scenario scenario = scenarioForRoot(root);
|
||||
if (!shouldRenderOnRoot(root)) {
|
||||
removeBatteryBarView(root);
|
||||
return;
|
||||
}
|
||||
BatteryBarGeometry.Scenario scenario = scenarioForRoot(root);
|
||||
boolean transientStatusBarReveal = isFullscreenScenario(scenario)
|
||||
&& shouldRenderVisibleFullscreenBar(root);
|
||||
if (transientStatusBarReveal) {
|
||||
@@ -593,6 +603,14 @@ final class BatteryBarController {
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean shouldBlockChargingChipRootAlpha(View root, float alpha) {
|
||||
return alpha < 0.99f
|
||||
&& isPhoneRoot(root)
|
||||
&& isUnlockedScene()
|
||||
&& !isFullscreenSystemBarState()
|
||||
&& hasSamsungBatteryStatusChip(root);
|
||||
}
|
||||
|
||||
private boolean isUnlockedScene() {
|
||||
SceneKey scene = runtimeContext.getModeStateRepository().getActiveScene();
|
||||
return scene == null || scene.isUnlocked();
|
||||
@@ -758,6 +776,32 @@ final class BatteryBarController {
|
||||
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) {
|
||||
return value instanceof Integer integer ? integer : null;
|
||||
}
|
||||
|
||||
+44
@@ -414,6 +414,9 @@ final class StockLayoutCanvasController {
|
||||
if (shouldSuppressTrackedStatusChipAlpha(view, alpha)) {
|
||||
return null;
|
||||
}
|
||||
if (shouldSuppressSamsungBatteryStatusChipAlpha(view, alpha)) {
|
||||
return null;
|
||||
}
|
||||
if (shouldCaptureAodVisualAlpha(view)) {
|
||||
rememberAodPluginVisualAlpha(view, alpha);
|
||||
}
|
||||
@@ -424,6 +427,9 @@ final class StockLayoutCanvasController {
|
||||
Object target = chain.getThisObject();
|
||||
Object visibilityArg = firstArg(chain.getArgs());
|
||||
if (target instanceof View view && visibilityArg instanceof Integer visibility) {
|
||||
if (shouldSuppressSamsungBatteryStatusChipVisibility(view, visibility)) {
|
||||
return null;
|
||||
}
|
||||
if (shouldSuppressTrackedStatusChipVisibility(view, visibility)) {
|
||||
return null;
|
||||
}
|
||||
@@ -3286,6 +3292,9 @@ final class StockLayoutCanvasController {
|
||||
if (confirmedAodPluginViews.contains(view)) {
|
||||
return true;
|
||||
}
|
||||
if (isSamsungBatteryStatusChipSurface(view)) {
|
||||
return true;
|
||||
}
|
||||
String idName = ViewIdNames.idName(view);
|
||||
if (TARGET_ID_NAMES.contains(idName)) {
|
||||
return true;
|
||||
@@ -3300,6 +3309,41 @@ final class StockLayoutCanvasController {
|
||||
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) {
|
||||
if (view == null || view.getVisibility() != View.VISIBLE) {
|
||||
return false;
|
||||
|
||||
@@ -34,6 +34,10 @@ final class SnapshotIconFilter {
|
||||
}
|
||||
ArrayList<SnapshotPlacement> filtered = new ArrayList<>(placements.size());
|
||||
for (SnapshotPlacement placement : placements) {
|
||||
if (isChargingBatteryChipPlacement(placement)) {
|
||||
filtered.add(placement);
|
||||
continue;
|
||||
}
|
||||
if (!isStatusBlocked(placement, settings.systemIconBlockedModes, mode)) {
|
||||
filtered.add(placement);
|
||||
}
|
||||
@@ -109,6 +113,11 @@ final class SnapshotIconFilter {
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean isChargingBatteryChipPlacement(SnapshotPlacement placement) {
|
||||
return placement != null
|
||||
&& SnapshotKeys.CHARGING_BATTERY_CHIP.equals(placement.key);
|
||||
}
|
||||
|
||||
private static AppIconRules.ExceptionRule matchingExceptionRule(
|
||||
SnapshotPlacement placement,
|
||||
ArrayList<AppIconRules.ExceptionRule> rules
|
||||
|
||||
@@ -36,6 +36,7 @@ final class SnapshotKeys {
|
||||
static final String OVERFLOW_DOT = "statusbartweak:overflow_dot";
|
||||
static final String EMPTY_CHIP = "statusbartweak:empty_chip";
|
||||
static final String EMPTY_ICON_CONTAINER = "statusbartweak:empty_icon_container";
|
||||
static final String CHARGING_BATTERY_CHIP = "statusbartweak:charging_battery_chip";
|
||||
|
||||
private SnapshotKeys() {
|
||||
}
|
||||
|
||||
@@ -1,15 +1,19 @@
|
||||
package se.ajpanton.statusbartweak.runtime.render;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Path;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.RectF;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.BatteryManager;
|
||||
import android.text.TextUtils;
|
||||
import android.os.SystemClock;
|
||||
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.hooks.ReflectionSupport;
|
||||
import se.ajpanton.statusbartweak.runtime.layoutsolver.StatusBarLayoutSolver.Bounds;
|
||||
import se.ajpanton.statusbartweak.runtime.settings.BroadcastReceiverSupport;
|
||||
|
||||
final class SnapshotRenderer {
|
||||
private static final long TRANSITION_SIGNAL_HOLD_MS = 700L;
|
||||
@@ -336,6 +341,7 @@ final class SnapshotRenderer {
|
||||
private boolean shouldTrimContent(SnapshotSource source) {
|
||||
return trimViewContentForCollision
|
||||
&& source != null
|
||||
&& !SnapshotKeys.CHARGING_BATTERY_CHIP.equals(source.keyHint())
|
||||
&& (source.mode() == SnapshotMode.VIEW || source.mode() == SnapshotMode.STATUS_CHIP);
|
||||
}
|
||||
|
||||
@@ -713,6 +719,10 @@ final class SnapshotRenderer {
|
||||
if (offsetX != 0) {
|
||||
canvas.translate(-offsetX, 0);
|
||||
}
|
||||
if (isChargingBatteryChipSource(source)) {
|
||||
drawChargingBatteryChip(source, bitmap);
|
||||
return;
|
||||
}
|
||||
View sourceView = source.view();
|
||||
if (sourceView == null) {
|
||||
return;
|
||||
@@ -823,6 +833,152 @@ final class SnapshotRenderer {
|
||||
&& 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) {
|
||||
int coloredPixels = 0;
|
||||
int monochromePixels = 0;
|
||||
|
||||
+12
-1
@@ -1112,7 +1112,9 @@ final class UnlockedLayoutPlanner {
|
||||
if (bounds == null || bounds.height <= 0) {
|
||||
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;
|
||||
Bounds resized = new Bounds(bounds.left, bottom - targetHeight, width, targetHeight);
|
||||
result.add(new SnapshotPlacement(
|
||||
@@ -1130,6 +1132,15 @@ final class UnlockedLayoutPlanner {
|
||||
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) {
|
||||
if (placement == null || placement.source == null || placement.bounds == null) {
|
||||
return placement != null ? placement.sourceRenderBounds : null;
|
||||
|
||||
+134
-1
@@ -1,7 +1,10 @@
|
||||
package se.ajpanton.statusbartweak.runtime.render;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.BatteryManager;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
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.notifications.NotificationActiveKeyStore;
|
||||
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.SbtSettings;
|
||||
|
||||
@@ -74,6 +78,7 @@ final class UnlockedStockSourceCollector {
|
||||
if (anchors.battery != null && !ViewGeometry.isDescendantOf(anchors.battery, anchors.statusRoot)) {
|
||||
collectStatusSnapshotViews(anchors.battery, statusIcons);
|
||||
}
|
||||
addSamsungBatteryStatusChipSource(root, statusIcons, settings);
|
||||
selectDualSimStatusSignals(statusIcons, settings);
|
||||
normalizeStatusIconSourceBounds(root, statusIcons);
|
||||
if (scene != null && scene.isAod()) {
|
||||
@@ -185,6 +190,7 @@ final class UnlockedStockSourceCollector {
|
||||
: 0;
|
||||
int statusSourceSignature = sourceLayoutListSignature(
|
||||
previousIcons != null ? previousIcons.statusIcons : null);
|
||||
statusSourceSignature = 31 * statusSourceSignature + batteryChargingSignature(root);
|
||||
if (scene != null && scene.isAod()) {
|
||||
statusSourceSignature = 31 * statusSourceSignature
|
||||
+ 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) {
|
||||
return Math.max(1, drawableWidth + statusIconHorizontalPadding(iconHeight));
|
||||
}
|
||||
@@ -1556,7 +1688,8 @@ final class UnlockedStockSourceCollector {
|
||||
settings.statusChipsHideAll,
|
||||
settings.statusChipsHideMediaUnlocked,
|
||||
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_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_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_BATTERY_LOCKSCREEN_UNPLUGGED_PERCENT = "battery_lockscreen_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 statusChipsHideNavUnlocked;
|
||||
public final boolean statusChipsHideCallUnlocked;
|
||||
public final boolean statusChipsHideBattery;
|
||||
public final Map<String, Integer> appIconBlockedModes;
|
||||
public final Map<String, ArrayList<AppIconRules.ExceptionRule>> appIconExceptionRules;
|
||||
public final String lockedNotificationMode;
|
||||
@@ -540,6 +542,7 @@ public final class SbtSettings {
|
||||
boolean statusChipsHideMediaUnlocked,
|
||||
boolean statusChipsHideNavUnlocked,
|
||||
boolean statusChipsHideCallUnlocked,
|
||||
boolean statusChipsHideBattery,
|
||||
Map<String, Integer> appIconBlockedModes,
|
||||
Map<String, ArrayList<AppIconRules.ExceptionRule>> appIconExceptionRules,
|
||||
String lockedNotificationMode,
|
||||
@@ -827,6 +830,7 @@ public final class SbtSettings {
|
||||
this.statusChipsHideMediaUnlocked = statusChipsHideMediaUnlocked;
|
||||
this.statusChipsHideNavUnlocked = statusChipsHideNavUnlocked;
|
||||
this.statusChipsHideCallUnlocked = statusChipsHideCallUnlocked;
|
||||
this.statusChipsHideBattery = statusChipsHideBattery;
|
||||
this.appIconBlockedModes = appIconBlockedModes != null
|
||||
? Collections.unmodifiableMap(new HashMap<>(appIconBlockedModes))
|
||||
: Collections.emptyMap();
|
||||
@@ -975,6 +979,7 @@ public final class SbtSettings {
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
Collections.emptyMap(),
|
||||
Collections.emptyMap(),
|
||||
"dot",
|
||||
@@ -1422,6 +1427,7 @@ public final class SbtSettings {
|
||||
prefs.getBoolean(KEY_STATUS_CHIPS_HIDE_MEDIA_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_BATTERY, false),
|
||||
AppIconRules.parseBlockedModes(readStringSetFromPrefs(
|
||||
prefs,
|
||||
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_NAV_UNLOCKED, false),
|
||||
bundle.getBoolean(KEY_STATUS_CHIPS_HIDE_CALL, false),
|
||||
bundle.getBoolean(KEY_STATUS_CHIPS_HIDE_BATTERY, false),
|
||||
AppIconRules.parseBlockedModes(readStringSetFromBundle(
|
||||
bundle,
|
||||
KEY_APP_ICON_BLOCKED_MODES)),
|
||||
|
||||
@@ -412,6 +412,8 @@ public class SbtSettingsProvider extends ContentProvider {
|
||||
prefs.getBoolean(SbtSettings.KEY_STATUS_CHIPS_HIDE_NAV_UNLOCKED, false));
|
||||
out.putBoolean(SbtSettings.KEY_STATUS_CHIPS_HIDE_CALL,
|
||||
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(
|
||||
out,
|
||||
SbtSettings.KEY_APP_ICON_BLOCKED_MODES,
|
||||
|
||||
@@ -45,6 +45,11 @@ public class StatusChipsFragment extends Fragment {
|
||||
SbtSettings.KEY_STATUS_CHIPS_HIDE_CALL,
|
||||
false,
|
||||
true);
|
||||
ViewTreeSupport.bindBooleanPreference(requireContext(), prefs, root,
|
||||
R.id.status_chips_hide_battery_switch,
|
||||
SbtSettings.KEY_STATUS_CHIPS_HIDE_BATTERY,
|
||||
false,
|
||||
true);
|
||||
return root;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,6 +47,12 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
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>
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
||||
|
||||
@@ -131,6 +131,7 @@
|
||||
<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_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="battery_bar_title">Battery bar</string>
|
||||
<string name="battery_bar_master_toggle_title">Master toggle</string>
|
||||
|
||||
Reference in New Issue
Block a user