Fix unlocked tint refresh
This commit is contained in:
+20
-6
@@ -22,21 +22,30 @@ public final class ClockLayoutTextFactory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static Model build(TextView source, SbtSettings settings) {
|
public static Model build(TextView source, SbtSettings settings) {
|
||||||
|
return build(source, settings, source != null ? source.getCurrentTextColor() : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Model build(TextView source, SbtSettings settings, int referenceColor) {
|
||||||
Context context = source != null ? source.getContext() : null;
|
Context context = source != null ? source.getContext() : null;
|
||||||
if (context == null || settings == null) {
|
if (context == null || settings == null) {
|
||||||
return Model.empty();
|
return Model.empty();
|
||||||
}
|
}
|
||||||
CacheKey cacheKey = cacheKey(context, source, settings);
|
CacheKey cacheKey = cacheKey(context, source, settings, referenceColor);
|
||||||
CachedModel cached = MODEL_CACHE.get(source);
|
CachedModel cached = MODEL_CACHE.get(source);
|
||||||
if (cached != null && cached.key.equals(cacheKey)) {
|
if (cached != null && cached.key.equals(cacheKey)) {
|
||||||
return cached.model;
|
return cached.model;
|
||||||
}
|
}
|
||||||
Model model = buildUncached(context, source, settings);
|
Model model = buildUncached(context, source, settings, referenceColor);
|
||||||
MODEL_CACHE.put(source, new CachedModel(cacheKey, model));
|
MODEL_CACHE.put(source, new CachedModel(cacheKey, model));
|
||||||
return model;
|
return model;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Model buildUncached(Context context, TextView source, SbtSettings settings) {
|
private static Model buildUncached(
|
||||||
|
Context context,
|
||||||
|
TextView source,
|
||||||
|
SbtSettings settings,
|
||||||
|
int referenceColor
|
||||||
|
) {
|
||||||
if (!hasCustomClockTextEnabled(settings)) {
|
if (!hasCustomClockTextEnabled(settings)) {
|
||||||
ArrayList<Row> rows = new ArrayList<>();
|
ArrayList<Row> rows = new ArrayList<>();
|
||||||
CharSequence text = source.getText();
|
CharSequence text = source.getText();
|
||||||
@@ -49,7 +58,7 @@ public final class ClockLayoutTextFactory {
|
|||||||
&& !settings.clockCustomFormat.isEmpty()) {
|
&& !settings.clockCustomFormat.isEmpty()) {
|
||||||
ClockParsedPattern parsedPattern = PATTERN_PARSER.parse(settings.clockCustomFormat);
|
ClockParsedPattern parsedPattern = PATTERN_PARSER.parse(settings.clockCustomFormat);
|
||||||
ArrayList<ClockTextRenderer.LayoutRowResult> renderedRows =
|
ArrayList<ClockTextRenderer.LayoutRowResult> renderedRows =
|
||||||
TEXT_RENDERER.renderLayoutRows(context, parsedPattern, source.getCurrentTextColor());
|
TEXT_RENDERER.renderLayoutRows(context, parsedPattern, referenceColor);
|
||||||
ArrayList<Row> rows = new ArrayList<>();
|
ArrayList<Row> rows = new ArrayList<>();
|
||||||
StringBuilder description = new StringBuilder();
|
StringBuilder description = new StringBuilder();
|
||||||
for (int i = 0; i < renderedRows.size(); i++) {
|
for (int i = 0; i < renderedRows.size(); i++) {
|
||||||
@@ -73,7 +82,12 @@ public final class ClockLayoutTextFactory {
|
|||||||
return new Model(rows, text != null ? text.toString() : "", settings.clockShowSeconds);
|
return new Model(rows, text != null ? text.toString() : "", settings.clockShowSeconds);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static CacheKey cacheKey(Context context, TextView source, SbtSettings settings) {
|
private static CacheKey cacheKey(
|
||||||
|
Context context,
|
||||||
|
TextView source,
|
||||||
|
SbtSettings settings,
|
||||||
|
int referenceColor
|
||||||
|
) {
|
||||||
String pattern = settings.clockCustomFormat != null ? settings.clockCustomFormat : "";
|
String pattern = settings.clockCustomFormat != null ? settings.clockCustomFormat : "";
|
||||||
boolean customPattern = settings.clockCustomFormatEnabled && !pattern.isEmpty();
|
boolean customPattern = settings.clockCustomFormatEnabled && !pattern.isEmpty();
|
||||||
boolean generatedText = hasCustomClockTextEnabled(settings);
|
boolean generatedText = hasCustomClockTextEnabled(settings);
|
||||||
@@ -85,7 +99,7 @@ public final class ClockLayoutTextFactory {
|
|||||||
return new CacheKey(
|
return new CacheKey(
|
||||||
localeFor(context).toLanguageTag(),
|
localeFor(context).toLanguageTag(),
|
||||||
System.currentTimeMillis() / divisor,
|
System.currentTimeMillis() / divisor,
|
||||||
source.getCurrentTextColor(),
|
referenceColor,
|
||||||
settings.clockShowSeconds,
|
settings.clockShowSeconds,
|
||||||
settings.clockShowDatePrefix,
|
settings.clockShowDatePrefix,
|
||||||
customPattern,
|
customPattern,
|
||||||
|
|||||||
+10
@@ -193,6 +193,16 @@ final class StockLayoutCanvasController {
|
|||||||
removeDebugOverlay(root);
|
removeDebugOverlay(root);
|
||||||
}
|
}
|
||||||
hideTrackedUnlockedStockSurfaces(root);
|
hideTrackedUnlockedStockSurfaces(root);
|
||||||
|
UnlockedHosts unlockedHosts = unlockedHostsByRoot.get(root);
|
||||||
|
if (unlockedHosts != null) {
|
||||||
|
unlockedIconRenderController.refreshUnlockedAppearance(
|
||||||
|
root,
|
||||||
|
unlockedHosts.clockHost,
|
||||||
|
unlockedHosts.chipHost,
|
||||||
|
unlockedHosts.statusHost,
|
||||||
|
unlockedHosts.notificationHost,
|
||||||
|
activeScene);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+28
-1
@@ -1,5 +1,7 @@
|
|||||||
package se.ajpanton.statusbartweak.runtime.render;
|
package se.ajpanton.statusbartweak.runtime.render;
|
||||||
|
|
||||||
|
import android.text.Spanned;
|
||||||
|
import android.text.style.ForegroundColorSpan;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.FrameLayout;
|
import android.widget.FrameLayout;
|
||||||
@@ -47,7 +49,7 @@ final class ClockProxyRenderer {
|
|||||||
if (copyTextStyleIfChanged(placement.source, view)) {
|
if (copyTextStyleIfChanged(placement.source, view)) {
|
||||||
hostChanged = true;
|
hostChanged = true;
|
||||||
}
|
}
|
||||||
if (!String.valueOf(view.getText()).contentEquals(row.text)) {
|
if (!sameTextAndColorSpans(view.getText(), row.text)) {
|
||||||
view.setText(row.text);
|
view.setText(row.text);
|
||||||
hostChanged = true;
|
hostChanged = true;
|
||||||
}
|
}
|
||||||
@@ -87,6 +89,31 @@ final class ClockProxyRenderer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static boolean sameTextAndColorSpans(CharSequence current, CharSequence desired) {
|
||||||
|
if (!String.valueOf(current).contentEquals(String.valueOf(desired))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return colorSpanSignature(current) == colorSpanSignature(desired);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int colorSpanSignature(CharSequence text) {
|
||||||
|
if (!(text instanceof Spanned spanned)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
ForegroundColorSpan[] spans = spanned.getSpans(0, spanned.length(), ForegroundColorSpan.class);
|
||||||
|
if (spans == null || spans.length == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int result = 17;
|
||||||
|
for (ForegroundColorSpan span : spans) {
|
||||||
|
result = 31 * result + span.getForegroundColor();
|
||||||
|
result = 31 * result + spanned.getSpanStart(span);
|
||||||
|
result = 31 * result + spanned.getSpanEnd(span);
|
||||||
|
result = 31 * result + spanned.getSpanFlags(span);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
void clear(ViewGroup host) {
|
void clear(ViewGroup host) {
|
||||||
if (host == null) {
|
if (host == null) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
+131
@@ -0,0 +1,131 @@
|
|||||||
|
package se.ajpanton.statusbartweak.runtime.render;
|
||||||
|
|
||||||
|
import android.content.res.ColorStateList;
|
||||||
|
import android.graphics.Color;
|
||||||
|
import android.graphics.ColorFilter;
|
||||||
|
import android.graphics.PorterDuff;
|
||||||
|
import android.graphics.drawable.Drawable;
|
||||||
|
import android.view.View;
|
||||||
|
import android.widget.ImageView;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import se.ajpanton.statusbartweak.runtime.hooks.ReflectionSupport;
|
||||||
|
|
||||||
|
final class SnapshotAppearanceSignature {
|
||||||
|
private static final int NO_COLOR = 0;
|
||||||
|
|
||||||
|
private static final String[] COLOR_FIELD_NAMES = {
|
||||||
|
"mIconColor",
|
||||||
|
"mDecorColor",
|
||||||
|
"mStaticDrawableColor",
|
||||||
|
"mIconTint",
|
||||||
|
"mTint",
|
||||||
|
"mTintColor",
|
||||||
|
"mCurrentColor",
|
||||||
|
"mCurrentIconColor"
|
||||||
|
};
|
||||||
|
|
||||||
|
private SnapshotAppearanceSignature() {
|
||||||
|
}
|
||||||
|
|
||||||
|
static int view(View view) {
|
||||||
|
if (view == null) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int result = 17;
|
||||||
|
result = 31 * result + java.util.Arrays.hashCode(view.getDrawableState());
|
||||||
|
if (view instanceof TextView textView) {
|
||||||
|
result = 31 * result + textView.getCurrentTextColor();
|
||||||
|
result = 31 * result + textView.getTextColors().hashCode();
|
||||||
|
}
|
||||||
|
if (view instanceof ImageView imageView) {
|
||||||
|
result = 31 * result + drawable(imageView.getDrawable());
|
||||||
|
result = 31 * result + colorStateList(imageView.getImageTintList());
|
||||||
|
PorterDuff.Mode tintMode = imageView.getImageTintMode();
|
||||||
|
result = 31 * result + (tintMode != null ? tintMode.hashCode() : 0);
|
||||||
|
ColorFilter colorFilter = imageView.getColorFilter();
|
||||||
|
result = 31 * result + (colorFilter != null ? System.identityHashCode(colorFilter) : 0);
|
||||||
|
}
|
||||||
|
result = 31 * result + reflectedColor(view, COLOR_FIELD_NAMES);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int drawable(Drawable drawable) {
|
||||||
|
if (drawable == null) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int result = 17;
|
||||||
|
result = 31 * result + System.identityHashCode(drawable);
|
||||||
|
result = 31 * result + drawable.getLevel();
|
||||||
|
result = 31 * result + drawable.getAlpha();
|
||||||
|
result = 31 * result + java.util.Arrays.hashCode(drawable.getState());
|
||||||
|
ColorFilter colorFilter = drawable.getColorFilter();
|
||||||
|
result = 31 * result + (colorFilter != null ? System.identityHashCode(colorFilter) : 0);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int preferredColor(View view, int fallbackColor) {
|
||||||
|
if (view == null) {
|
||||||
|
return fallbackColor;
|
||||||
|
}
|
||||||
|
if (view instanceof TextView textView) {
|
||||||
|
return textView.getCurrentTextColor();
|
||||||
|
}
|
||||||
|
if (view instanceof ImageView imageView) {
|
||||||
|
int tintColor = colorStateListColor(imageView.getImageTintList(), view, NO_COLOR);
|
||||||
|
if (isOpaqueColor(tintColor)) {
|
||||||
|
return tintColor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int reflectedColor = reflectedColor(view, COLOR_FIELD_NAMES);
|
||||||
|
if (isOpaqueColor(reflectedColor)) {
|
||||||
|
return reflectedColor;
|
||||||
|
}
|
||||||
|
return fallbackColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int reflectedColor(Object target, String[] fieldNames) {
|
||||||
|
for (String fieldName : fieldNames) {
|
||||||
|
Object value = ReflectionSupport.getFieldValue(target, fieldName);
|
||||||
|
int color = colorValue(value, NO_COLOR);
|
||||||
|
if (isOpaqueColor(color)) {
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NO_COLOR;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int colorValue(Object value, int fallbackColor) {
|
||||||
|
if (value instanceof Integer integer) {
|
||||||
|
return integer;
|
||||||
|
}
|
||||||
|
if (value instanceof ColorStateList colorStateList) {
|
||||||
|
return colorStateList.getDefaultColor();
|
||||||
|
}
|
||||||
|
return fallbackColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int colorStateListColor(ColorStateList colorStateList, View view, int fallbackColor) {
|
||||||
|
if (colorStateList == null) {
|
||||||
|
return fallbackColor;
|
||||||
|
}
|
||||||
|
return colorStateList.getColorForState(
|
||||||
|
view != null ? view.getDrawableState() : null,
|
||||||
|
colorStateList.getDefaultColor());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isOpaqueColor(int color) {
|
||||||
|
return Color.alpha(color) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int colorStateList(ColorStateList colorStateList) {
|
||||||
|
if (colorStateList == null) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int result = 17;
|
||||||
|
result = 31 * result + colorStateList.getDefaultColor();
|
||||||
|
result = 31 * result + (colorStateList.isStateful() ? 1 : 0);
|
||||||
|
result = 31 * result + colorStateList.hashCode();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
package se.ajpanton.statusbartweak.runtime.render;
|
package se.ajpanton.statusbartweak.runtime.render;
|
||||||
|
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
|
import android.graphics.Color;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
@@ -34,6 +35,7 @@ final class SnapshotPlacement {
|
|||||||
final String key;
|
final String key;
|
||||||
final boolean signal;
|
final boolean signal;
|
||||||
final boolean overflowDot;
|
final boolean overflowDot;
|
||||||
|
final int overflowDotColor;
|
||||||
final HeldSignal heldSignal;
|
final HeldSignal heldSignal;
|
||||||
final Bounds contentBounds;
|
final Bounds contentBounds;
|
||||||
final int sourceOffsetX;
|
final int sourceOffsetX;
|
||||||
@@ -47,12 +49,36 @@ final class SnapshotPlacement {
|
|||||||
HeldSignal heldSignal,
|
HeldSignal heldSignal,
|
||||||
Bounds contentBounds,
|
Bounds contentBounds,
|
||||||
int sourceOffsetX
|
int sourceOffsetX
|
||||||
|
) {
|
||||||
|
this(
|
||||||
|
source,
|
||||||
|
bounds,
|
||||||
|
key,
|
||||||
|
signal,
|
||||||
|
overflowDot,
|
||||||
|
Color.WHITE,
|
||||||
|
heldSignal,
|
||||||
|
contentBounds,
|
||||||
|
sourceOffsetX);
|
||||||
|
}
|
||||||
|
|
||||||
|
SnapshotPlacement(
|
||||||
|
SnapshotSource source,
|
||||||
|
Bounds bounds,
|
||||||
|
String key,
|
||||||
|
boolean signal,
|
||||||
|
boolean overflowDot,
|
||||||
|
int overflowDotColor,
|
||||||
|
HeldSignal heldSignal,
|
||||||
|
Bounds contentBounds,
|
||||||
|
int sourceOffsetX
|
||||||
) {
|
) {
|
||||||
this.source = source;
|
this.source = source;
|
||||||
this.bounds = bounds;
|
this.bounds = bounds;
|
||||||
this.key = key;
|
this.key = key;
|
||||||
this.signal = signal;
|
this.signal = signal;
|
||||||
this.overflowDot = overflowDot;
|
this.overflowDot = overflowDot;
|
||||||
|
this.overflowDotColor = overflowDotColor;
|
||||||
this.heldSignal = heldSignal;
|
this.heldSignal = heldSignal;
|
||||||
this.contentBounds = contentBounds;
|
this.contentBounds = contentBounds;
|
||||||
this.sourceOffsetX = sourceOffsetX;
|
this.sourceOffsetX = sourceOffsetX;
|
||||||
@@ -78,6 +104,10 @@ final class SnapshotPlacement {
|
|||||||
return overflowDot;
|
return overflowDot;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int overflowDotColor() {
|
||||||
|
return overflowDotColor;
|
||||||
|
}
|
||||||
|
|
||||||
HeldSignal heldSignal() {
|
HeldSignal heldSignal() {
|
||||||
return heldSignal;
|
return heldSignal;
|
||||||
}
|
}
|
||||||
@@ -102,6 +132,7 @@ record SnapshotRenderState(
|
|||||||
int height,
|
int height,
|
||||||
boolean signal,
|
boolean signal,
|
||||||
boolean overflowDot,
|
boolean overflowDot,
|
||||||
|
int overflowDotColor,
|
||||||
int sourceOffsetX,
|
int sourceOffsetX,
|
||||||
String heldSignalKey,
|
String heldSignalKey,
|
||||||
int heldBitmapId,
|
int heldBitmapId,
|
||||||
|
|||||||
@@ -176,7 +176,7 @@ final class SnapshotRenderer {
|
|||||||
|| !desiredState.equals(statesByProxy.get(proxy));
|
|| !desiredState.equals(statesByProxy.get(proxy));
|
||||||
if (bitmapChanged) {
|
if (bitmapChanged) {
|
||||||
if (placement.overflowDot()) {
|
if (placement.overflowDot()) {
|
||||||
drawOverflowDot(bitmap);
|
drawOverflowDot(bitmap, placement.overflowDotColor());
|
||||||
} else if (placement.heldSignal() != null) {
|
} else if (placement.heldSignal() != null) {
|
||||||
drawHeldSignal(placement.heldSignal(), bitmap);
|
drawHeldSignal(placement.heldSignal(), bitmap);
|
||||||
} else if (placement.source() != null) {
|
} else if (placement.source() != null) {
|
||||||
@@ -471,6 +471,7 @@ final class SnapshotRenderer {
|
|||||||
bounds.height,
|
bounds.height,
|
||||||
placement.signal(),
|
placement.signal(),
|
||||||
placement.overflowDot(),
|
placement.overflowDot(),
|
||||||
|
placement.overflowDotColor(),
|
||||||
placement.sourceOffsetX(),
|
placement.sourceOffsetX(),
|
||||||
placement.heldSignal() != null ? placement.heldSignal().key : "",
|
placement.heldSignal() != null ? placement.heldSignal().key : "",
|
||||||
placement.heldSignal() != null ? System.identityHashCode(placement.heldSignal().bitmap) : 0,
|
placement.heldSignal() != null ? System.identityHashCode(placement.heldSignal().bitmap) : 0,
|
||||||
@@ -493,6 +494,7 @@ final class SnapshotRenderer {
|
|||||||
CharSequence contentDescription = view.getContentDescription();
|
CharSequence contentDescription = view.getContentDescription();
|
||||||
result = 31 * result + (contentDescription != null ? contentDescription.toString().hashCode() : 0);
|
result = 31 * result + (contentDescription != null ? contentDescription.toString().hashCode() : 0);
|
||||||
result = 31 * result + java.util.Arrays.hashCode(view.getDrawableState());
|
result = 31 * result + java.util.Arrays.hashCode(view.getDrawableState());
|
||||||
|
result = 31 * result + SnapshotAppearanceSignature.view(view);
|
||||||
if (view instanceof TextView textView) {
|
if (view instanceof TextView textView) {
|
||||||
CharSequence text = textView.getText();
|
CharSequence text = textView.getText();
|
||||||
result = 31 * result + (text != null ? text.toString().hashCode() : 0);
|
result = 31 * result + (text != null ? text.toString().hashCode() : 0);
|
||||||
@@ -500,7 +502,7 @@ final class SnapshotRenderer {
|
|||||||
result = 31 * result + Float.floatToIntBits(textView.getTextSize());
|
result = 31 * result + Float.floatToIntBits(textView.getTextSize());
|
||||||
}
|
}
|
||||||
if (view instanceof ImageView imageView) {
|
if (view instanceof ImageView imageView) {
|
||||||
result = 31 * result + drawableSignature(imageView.getDrawable());
|
result = 31 * result + SnapshotAppearanceSignature.drawable(imageView.getDrawable());
|
||||||
}
|
}
|
||||||
if (view instanceof ViewGroup group) {
|
if (view instanceof ViewGroup group) {
|
||||||
result = 31 * result + group.getChildCount();
|
result = 31 * result + group.getChildCount();
|
||||||
@@ -516,10 +518,7 @@ final class SnapshotRenderer {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
int result = 17;
|
int result = 17;
|
||||||
result = 31 * result + System.identityHashCode(drawable);
|
result = 31 * result + SnapshotAppearanceSignature.drawable(drawable);
|
||||||
result = 31 * result + drawable.getLevel();
|
|
||||||
result = 31 * result + drawable.getAlpha();
|
|
||||||
result = 31 * result + java.util.Arrays.hashCode(drawable.getState());
|
|
||||||
Rect bounds = drawable.getBounds();
|
Rect bounds = drawable.getBounds();
|
||||||
result = 31 * result + bounds.left;
|
result = 31 * result + bounds.left;
|
||||||
result = 31 * result + bounds.top;
|
result = 31 * result + bounds.top;
|
||||||
@@ -570,7 +569,7 @@ final class SnapshotRenderer {
|
|||||||
canvas.drawBitmap(heldSignal.bitmap, src, dst, null);
|
canvas.drawBitmap(heldSignal.bitmap, src, dst, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void drawOverflowDot(Bitmap bitmap) {
|
private void drawOverflowDot(Bitmap bitmap, int color) {
|
||||||
bitmap.eraseColor(Color.TRANSPARENT);
|
bitmap.eraseColor(Color.TRANSPARENT);
|
||||||
int base = Math.min(bitmap.getWidth(), bitmap.getHeight());
|
int base = Math.min(bitmap.getWidth(), bitmap.getHeight());
|
||||||
if (base <= 0) {
|
if (base <= 0) {
|
||||||
@@ -578,7 +577,7 @@ final class SnapshotRenderer {
|
|||||||
}
|
}
|
||||||
float radius = Math.max(1f, base * 0.16f);
|
float radius = Math.max(1f, base * 0.16f);
|
||||||
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||||
paint.setColor(Color.WHITE);
|
paint.setColor(color);
|
||||||
Canvas canvas = new Canvas(bitmap);
|
Canvas canvas = new Canvas(bitmap);
|
||||||
canvas.drawCircle(bitmap.getWidth() / 2f, bitmap.getHeight() / 2f, radius, paint);
|
canvas.drawCircle(bitmap.getWidth() / 2f, bitmap.getHeight() / 2f, radius, paint);
|
||||||
}
|
}
|
||||||
|
|||||||
+2
@@ -190,6 +190,7 @@ final class UnlockedChipPlacementController {
|
|||||||
placement.key,
|
placement.key,
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
|
placement.overflowDotColor,
|
||||||
null,
|
null,
|
||||||
placement.contentBounds,
|
placement.contentBounds,
|
||||||
placement.sourceOffsetX));
|
placement.sourceOffsetX));
|
||||||
@@ -211,6 +212,7 @@ final class UnlockedChipPlacementController {
|
|||||||
placement.key,
|
placement.key,
|
||||||
placement.signal,
|
placement.signal,
|
||||||
placement.overflowDot,
|
placement.overflowDot,
|
||||||
|
placement.overflowDotColor,
|
||||||
placement.heldSignal,
|
placement.heldSignal,
|
||||||
placement.contentBounds,
|
placement.contentBounds,
|
||||||
placement.sourceOffsetX));
|
placement.sourceOffsetX));
|
||||||
|
|||||||
+234
-1
@@ -34,6 +34,7 @@ public final class UnlockedIconSnapshotRenderController {
|
|||||||
private final WeakHashMap<View, LayoutPlan> lastLayoutPlanByRoot = new WeakHashMap<>();
|
private final WeakHashMap<View, LayoutPlan> lastLayoutPlanByRoot = new WeakHashMap<>();
|
||||||
private final WeakHashMap<View, Integer> lastClockGeometryByRoot = new WeakHashMap<>();
|
private final WeakHashMap<View, Integer> lastClockGeometryByRoot = new WeakHashMap<>();
|
||||||
private final WeakHashMap<View, Integer> lastClockSourceGeometryByRoot = new WeakHashMap<>();
|
private final WeakHashMap<View, Integer> lastClockSourceGeometryByRoot = new WeakHashMap<>();
|
||||||
|
private final WeakHashMap<View, Integer> lastClockAppearanceByRoot = new WeakHashMap<>();
|
||||||
|
|
||||||
public UnlockedIconSnapshotRenderController() {
|
public UnlockedIconSnapshotRenderController() {
|
||||||
statusRenderer = new SnapshotRenderer(true, true, false);
|
statusRenderer = new SnapshotRenderer(true, true, false);
|
||||||
@@ -164,6 +165,8 @@ public final class UnlockedIconSnapshotRenderController {
|
|||||||
lastLayoutPlanByRoot.put(root, layoutPlan);
|
lastLayoutPlanByRoot.put(root, layoutPlan);
|
||||||
lastClockGeometryByRoot.put(root, currentClockGeometry != null ? currentClockGeometry : 0);
|
lastClockGeometryByRoot.put(root, currentClockGeometry != null ? currentClockGeometry : 0);
|
||||||
lastClockSourceGeometryByRoot.put(root, currentClockSourceGeometry);
|
lastClockSourceGeometryByRoot.put(root, currentClockSourceGeometry);
|
||||||
|
layoutPlan = withCurrentDotColors(layoutPlan, collectedIcons);
|
||||||
|
lastLayoutPlanByRoot.put(root, layoutPlan);
|
||||||
if (settings.clockEnabledUnlocked && layoutPlan.clockPlacement != null) {
|
if (settings.clockEnabledUnlocked && layoutPlan.clockPlacement != null) {
|
||||||
clockRenderer.render(clockHost, layoutPlan.clockPlacement);
|
clockRenderer.render(clockHost, layoutPlan.clockPlacement);
|
||||||
} else {
|
} else {
|
||||||
@@ -187,6 +190,47 @@ public final class UnlockedIconSnapshotRenderController {
|
|||||||
return new RenderResult(true, stockSourcesChanged, chipSourcesChanged);
|
return new RenderResult(true, stockSourcesChanged, chipSourcesChanged);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void refreshUnlockedAppearance(
|
||||||
|
View root,
|
||||||
|
ViewGroup clockHost,
|
||||||
|
ViewGroup chipHost,
|
||||||
|
ViewGroup statusHost,
|
||||||
|
ViewGroup notificationHost,
|
||||||
|
SceneKey scene
|
||||||
|
) {
|
||||||
|
if (root == null || scene == null || !scene.isUnlocked() || !root.isAttachedToWindow()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
LayoutPlan layoutPlan = lastLayoutPlanByRoot.get(root);
|
||||||
|
if (layoutPlan == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
SbtSettings settings = RuntimeSettingsCache.get(root.getContext());
|
||||||
|
CollectedIcons collectedIcons = lastCollectedIconsByRoot.get(root);
|
||||||
|
LayoutPlan updatedPlan = withCurrentDotColors(layoutPlan, collectedIcons);
|
||||||
|
if (updatedPlan != layoutPlan) {
|
||||||
|
lastLayoutPlanByRoot.put(root, updatedPlan);
|
||||||
|
layoutPlan = updatedPlan;
|
||||||
|
}
|
||||||
|
if (settings.layoutChipEnabledUnlocked && layoutPlan.chipPlacements != null) {
|
||||||
|
chipRenderer.renderPlacements(chipHost, layoutPlan.chipPlacements);
|
||||||
|
}
|
||||||
|
if (settings.layoutStatusEnabledUnlocked && layoutPlan.statusPlacements != null) {
|
||||||
|
statusRenderer.renderPlacements(statusHost, layoutPlan.statusPlacements);
|
||||||
|
}
|
||||||
|
if (settings.layoutNotifEnabledUnlocked && layoutPlan.notificationPlacements != null) {
|
||||||
|
notificationRenderer.renderPlacements(notificationHost, layoutPlan.notificationPlacements);
|
||||||
|
}
|
||||||
|
updatedPlan = withCurrentClockAppearance(root, layoutPlan, collectedIcons, settings);
|
||||||
|
if (updatedPlan != layoutPlan) {
|
||||||
|
lastLayoutPlanByRoot.put(root, updatedPlan);
|
||||||
|
layoutPlan = updatedPlan;
|
||||||
|
}
|
||||||
|
if (settings.clockEnabledUnlocked && layoutPlan.clockPlacement != null) {
|
||||||
|
clockRenderer.render(clockHost, layoutPlan.clockPlacement);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void layoutHostToRoot(View root, ViewGroup host) {
|
private void layoutHostToRoot(View root, ViewGroup host) {
|
||||||
if (root == null || host == null || root.getWidth() <= 0 || root.getHeight() <= 0) {
|
if (root == null || host == null || root.getWidth() <= 0 || root.getHeight() <= 0) {
|
||||||
return;
|
return;
|
||||||
@@ -205,6 +249,180 @@ public final class UnlockedIconSnapshotRenderController {
|
|||||||
host.layout(0, 0, root.getWidth(), root.getHeight());
|
host.layout(0, 0, root.getWidth(), root.getHeight());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private LayoutPlan withCurrentDotColors(LayoutPlan plan, CollectedIcons icons) {
|
||||||
|
if (plan == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
ArrayList<SnapshotPlacement> status = withCurrentDotColors(
|
||||||
|
plan.statusPlacements,
|
||||||
|
icons != null ? icons.statusIcons : null);
|
||||||
|
ArrayList<SnapshotPlacement> notifications = withCurrentDotColors(
|
||||||
|
plan.notificationPlacements,
|
||||||
|
icons != null ? icons.notificationIcons : null);
|
||||||
|
if (status == plan.statusPlacements && notifications == plan.notificationPlacements) {
|
||||||
|
return plan;
|
||||||
|
}
|
||||||
|
return new LayoutPlan(
|
||||||
|
plan.clockPlacement,
|
||||||
|
plan.chipPlacements,
|
||||||
|
status,
|
||||||
|
notifications);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ArrayList<SnapshotPlacement> withCurrentDotColors(
|
||||||
|
ArrayList<SnapshotPlacement> placements,
|
||||||
|
ArrayList<SnapshotSource> fallbackSources
|
||||||
|
) {
|
||||||
|
if (placements == null || placements.isEmpty()) {
|
||||||
|
return placements;
|
||||||
|
}
|
||||||
|
int color = dotColor(placements, fallbackSources);
|
||||||
|
if (color == 0) {
|
||||||
|
return placements;
|
||||||
|
}
|
||||||
|
ArrayList<SnapshotPlacement> updated = null;
|
||||||
|
for (int i = 0; i < placements.size(); i++) {
|
||||||
|
SnapshotPlacement placement = placements.get(i);
|
||||||
|
if (!placement.overflowDot || placement.overflowDotColor == color) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (updated == null) {
|
||||||
|
updated = new ArrayList<>(placements);
|
||||||
|
}
|
||||||
|
updated.set(i, new SnapshotPlacement(
|
||||||
|
placement.source,
|
||||||
|
placement.bounds,
|
||||||
|
placement.key,
|
||||||
|
placement.signal,
|
||||||
|
placement.overflowDot,
|
||||||
|
color,
|
||||||
|
placement.heldSignal,
|
||||||
|
placement.contentBounds,
|
||||||
|
placement.sourceOffsetX));
|
||||||
|
}
|
||||||
|
return updated != null ? updated : placements;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int dotColor(
|
||||||
|
ArrayList<SnapshotPlacement> placements,
|
||||||
|
ArrayList<SnapshotSource> fallbackSources
|
||||||
|
) {
|
||||||
|
for (SnapshotPlacement placement : placements) {
|
||||||
|
if (placement != null && placement.source != null) {
|
||||||
|
int color = sourceColor(placement.source);
|
||||||
|
if (color != 0) {
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (fallbackSources != null) {
|
||||||
|
for (SnapshotSource source : fallbackSources) {
|
||||||
|
int color = sourceColor(source);
|
||||||
|
if (color != 0) {
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int sourceColor(SnapshotSource source) {
|
||||||
|
if (source == null || source.view() == null) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int color = SnapshotAppearanceSignature.preferredColor(
|
||||||
|
source.view(),
|
||||||
|
android.graphics.Color.TRANSPARENT);
|
||||||
|
return android.graphics.Color.alpha(color) != 0 ? color : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private LayoutPlan withCurrentClockAppearance(
|
||||||
|
View root,
|
||||||
|
LayoutPlan plan,
|
||||||
|
CollectedIcons icons,
|
||||||
|
SbtSettings settings
|
||||||
|
) {
|
||||||
|
if (root == null
|
||||||
|
|| plan == null
|
||||||
|
|| plan.clockPlacement == null
|
||||||
|
|| !settings.clockEnabledUnlocked) {
|
||||||
|
return plan;
|
||||||
|
}
|
||||||
|
ClockPlacement previous = plan.clockPlacement;
|
||||||
|
int referenceColor = clockReferenceColor(previous, icons);
|
||||||
|
int signature = clockAppearanceSignature(previous, referenceColor, settings);
|
||||||
|
Integer lastSignature = lastClockAppearanceByRoot.get(root);
|
||||||
|
if (lastSignature != null && lastSignature == signature) {
|
||||||
|
return plan;
|
||||||
|
}
|
||||||
|
ClockPlacement updatedClock = clockPlacementWithTextFromModel(
|
||||||
|
previous,
|
||||||
|
previous.source,
|
||||||
|
settings,
|
||||||
|
referenceColor);
|
||||||
|
lastClockAppearanceByRoot.put(root, signature);
|
||||||
|
if (updatedClock == null) {
|
||||||
|
return plan;
|
||||||
|
}
|
||||||
|
return plan.withClockPlacement(updatedClock);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int clockReferenceColor(ClockPlacement placement, CollectedIcons icons) {
|
||||||
|
if (icons != null && icons.statusIcons != null) {
|
||||||
|
for (SnapshotSource source : icons.statusIcons) {
|
||||||
|
int color = sourceColor(source);
|
||||||
|
if (color != 0) {
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (icons != null && icons.notificationIcons != null) {
|
||||||
|
for (SnapshotSource source : icons.notificationIcons) {
|
||||||
|
int color = sourceColor(source);
|
||||||
|
if (color != 0) {
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (placement != null && placement.source != null) {
|
||||||
|
return placement.source.getCurrentTextColor();
|
||||||
|
}
|
||||||
|
return android.graphics.Color.WHITE;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int clockAppearanceSignature(
|
||||||
|
ClockPlacement placement,
|
||||||
|
int referenceColor,
|
||||||
|
SbtSettings settings
|
||||||
|
) {
|
||||||
|
int result = 17;
|
||||||
|
result = 31 * result + referenceColor;
|
||||||
|
result = 31 * result + clockTextSettingsSignature(settings);
|
||||||
|
if (placement != null && placement.source != null) {
|
||||||
|
result = 31 * result + placement.source.getCurrentTextColor();
|
||||||
|
}
|
||||||
|
if (placement != null && placement.rows != null) {
|
||||||
|
result = 31 * result + placement.rows.size();
|
||||||
|
for (ClockRow row : placement.rows) {
|
||||||
|
result = 31 * result + row.rowIndex;
|
||||||
|
result = 31 * result + row.segment.ordinal();
|
||||||
|
result = 31 * result + (row.text != null ? row.text.toString().hashCode() : 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int clockTextSettingsSignature(SbtSettings settings) {
|
||||||
|
if (settings == null) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return java.util.Objects.hash(
|
||||||
|
settings.clockShowSeconds,
|
||||||
|
settings.clockShowDatePrefix,
|
||||||
|
settings.clockCustomFormatEnabled,
|
||||||
|
settings.clockCustomFormat);
|
||||||
|
}
|
||||||
|
|
||||||
public void clearAll() {
|
public void clearAll() {
|
||||||
clockRenderer.clearAll();
|
clockRenderer.clearAll();
|
||||||
statusRenderer.clearAll();
|
statusRenderer.clearAll();
|
||||||
@@ -218,6 +436,7 @@ public final class UnlockedIconSnapshotRenderController {
|
|||||||
lastLayoutPlanByRoot.clear();
|
lastLayoutPlanByRoot.clear();
|
||||||
lastClockGeometryByRoot.clear();
|
lastClockGeometryByRoot.clear();
|
||||||
lastClockSourceGeometryByRoot.clear();
|
lastClockSourceGeometryByRoot.clear();
|
||||||
|
lastClockAppearanceByRoot.clear();
|
||||||
chipPlacementController.clear();
|
chipPlacementController.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -228,6 +447,7 @@ public final class UnlockedIconSnapshotRenderController {
|
|||||||
lastCollectedIconsByRoot.clear();
|
lastCollectedIconsByRoot.clear();
|
||||||
lastLayoutPlanByRoot.clear();
|
lastLayoutPlanByRoot.clear();
|
||||||
lastClockGeometryByRoot.clear();
|
lastClockGeometryByRoot.clear();
|
||||||
|
lastClockAppearanceByRoot.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isClockOnlySignatureChange(
|
private boolean isClockOnlySignatureChange(
|
||||||
@@ -368,6 +588,19 @@ public final class UnlockedIconSnapshotRenderController {
|
|||||||
ClockPlacement previousPlacement,
|
ClockPlacement previousPlacement,
|
||||||
TextView source,
|
TextView source,
|
||||||
SbtSettings settings
|
SbtSettings settings
|
||||||
|
) {
|
||||||
|
return clockPlacementWithTextFromModel(
|
||||||
|
previousPlacement,
|
||||||
|
source,
|
||||||
|
settings,
|
||||||
|
source != null ? source.getCurrentTextColor() : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ClockPlacement clockPlacementWithTextFromModel(
|
||||||
|
ClockPlacement previousPlacement,
|
||||||
|
TextView source,
|
||||||
|
SbtSettings settings,
|
||||||
|
int referenceColor
|
||||||
) {
|
) {
|
||||||
if (previousPlacement == null
|
if (previousPlacement == null
|
||||||
|| previousPlacement.rows == null
|
|| previousPlacement.rows == null
|
||||||
@@ -375,7 +608,7 @@ public final class UnlockedIconSnapshotRenderController {
|
|||||||
|| settings == null) {
|
|| settings == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
ClockLayoutTextFactory.Model model = ClockLayoutTextFactory.build(source, settings);
|
ClockLayoutTextFactory.Model model = ClockLayoutTextFactory.build(source, settings, referenceColor);
|
||||||
if (model == null || model.isEmpty()) {
|
if (model == null || model.isEmpty()) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -493,11 +493,40 @@ final class UnlockedLayoutBand extends StatusBarLayoutSolver.LayoutBand {
|
|||||||
SnapshotKeys.OVERFLOW_DOT + ":" + kind.name().toLowerCase(java.util.Locale.ROOT),
|
SnapshotKeys.OVERFLOW_DOT + ":" + kind.name().toLowerCase(java.util.Locale.ROOT),
|
||||||
false,
|
false,
|
||||||
true,
|
true,
|
||||||
|
dotColor(),
|
||||||
null,
|
null,
|
||||||
new Bounds(0, 0, Math.max(1, width), Math.max(1, height)),
|
new Bounds(0, 0, Math.max(1, width), Math.max(1, height)),
|
||||||
0);
|
0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private int dotColor() {
|
||||||
|
for (SnapshotPlacement placement : activePlacements()) {
|
||||||
|
int color = sourceColor(placement);
|
||||||
|
if (color != 0) {
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (rawPlacements != null) {
|
||||||
|
for (SnapshotPlacement placement : rawPlacements) {
|
||||||
|
int color = sourceColor(placement);
|
||||||
|
if (color != 0) {
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return android.graphics.Color.WHITE;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int sourceColor(SnapshotPlacement placement) {
|
||||||
|
if (placement == null || placement.source == null || placement.source.view() == null) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int color = SnapshotAppearanceSignature.preferredColor(
|
||||||
|
placement.source.view(),
|
||||||
|
android.graphics.Color.TRANSPARENT);
|
||||||
|
return android.graphics.Color.alpha(color) != 0 ? color : 0;
|
||||||
|
}
|
||||||
|
|
||||||
private SnapshotPlacement emptyIconContainerPlacement() {
|
private SnapshotPlacement emptyIconContainerPlacement() {
|
||||||
int height = Math.max(1, dotHeight(activePlacements()));
|
int height = Math.max(1, dotHeight(activePlacements()));
|
||||||
return new SnapshotPlacement(
|
return new SnapshotPlacement(
|
||||||
@@ -548,6 +577,7 @@ final class UnlockedLayoutBand extends StatusBarLayoutSolver.LayoutBand {
|
|||||||
placement.key,
|
placement.key,
|
||||||
placement.signal,
|
placement.signal,
|
||||||
placement.overflowDot,
|
placement.overflowDot,
|
||||||
|
placement.overflowDotColor,
|
||||||
placement.heldSignal,
|
placement.heldSignal,
|
||||||
clippedContent,
|
clippedContent,
|
||||||
placement.sourceOffsetX + removeLeft);
|
placement.sourceOffsetX + removeLeft);
|
||||||
|
|||||||
@@ -218,6 +218,7 @@ final class UnlockedLayoutPlanner {
|
|||||||
placement.key,
|
placement.key,
|
||||||
placement.signal,
|
placement.signal,
|
||||||
placement.overflowDot,
|
placement.overflowDot,
|
||||||
|
placement.overflowDotColor,
|
||||||
placement.heldSignal,
|
placement.heldSignal,
|
||||||
placement.contentBounds,
|
placement.contentBounds,
|
||||||
placement.sourceOffsetX));
|
placement.sourceOffsetX));
|
||||||
|
|||||||
+2
-4
@@ -2,7 +2,6 @@ package se.ajpanton.statusbartweak.runtime.render;
|
|||||||
|
|
||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
import android.graphics.drawable.Drawable;
|
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
@@ -636,19 +635,18 @@ final class UnlockedStockSourceCollector {
|
|||||||
: 0);
|
: 0);
|
||||||
}
|
}
|
||||||
if (view instanceof ImageView imageView) {
|
if (view instanceof ImageView imageView) {
|
||||||
result = 31 * result + drawableSignature(imageView.getDrawable());
|
result = 31 * result + drawableLayoutSignature(imageView.getDrawable());
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int drawableSignature(Drawable drawable) {
|
private static int drawableLayoutSignature(android.graphics.drawable.Drawable drawable) {
|
||||||
if (drawable == null) {
|
if (drawable == null) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
int result = 17;
|
int result = 17;
|
||||||
result = 31 * result + System.identityHashCode(drawable);
|
result = 31 * result + System.identityHashCode(drawable);
|
||||||
result = 31 * result + drawable.getLevel();
|
result = 31 * result + drawable.getLevel();
|
||||||
result = 31 * result + drawable.getAlpha();
|
|
||||||
result = 31 * result + java.util.Arrays.hashCode(drawable.getState());
|
result = 31 * result + java.util.Arrays.hashCode(drawable.getState());
|
||||||
Rect bounds = drawable.getBounds();
|
Rect bounds = drawable.getBounds();
|
||||||
result = 31 * result + bounds.left;
|
result = 31 * result + bounds.left;
|
||||||
|
|||||||
Reference in New Issue
Block a user