Support animated notification icon snapshots

This commit is contained in:
ajp_anton
2026-06-22 14:39:17 +00:00
parent 8e7e825516
commit 1fa5fd24b1
@@ -11,6 +11,7 @@ import android.graphics.Path;
import android.graphics.PorterDuff; import android.graphics.PorterDuff;
import android.graphics.Rect; import android.graphics.Rect;
import android.graphics.RectF; import android.graphics.RectF;
import android.graphics.drawable.AnimationDrawable;
import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.os.BatteryManager; import android.os.BatteryManager;
@@ -239,9 +240,24 @@ final class SnapshotRenderer {
proxy.setTag(key); proxy.setTag(key);
proxyChanged = true; proxyChanged = true;
} }
SnapshotRenderState desiredState = renderStateFor(placement);
Drawable animatedDrawable = animatedNotificationDrawable(placement);
if (animatedDrawable != null) {
SnapshotRenderState currentState = statesByProxy.get(proxy);
boolean drawableChanged = !(proxy.getDrawable() instanceof AnimationDrawable)
|| !canReuseAnimatedProxy(currentState, desiredState);
if (drawableChanged) {
Drawable proxyDrawable = newDrawableInstance(animatedDrawable);
proxy.setImageDrawable(proxyDrawable);
proxyChanged = true;
}
startAnimationIfNeeded(proxy.getDrawable());
if (!desiredState.equals(currentState)) {
statesByProxy.put(proxy, desiredState);
}
} else {
BitmapResult bitmapResult = bitmapFor(proxy, bounds); BitmapResult bitmapResult = bitmapFor(proxy, bounds);
Bitmap bitmap = bitmapResult.bitmap(); Bitmap bitmap = bitmapResult.bitmap();
SnapshotRenderState desiredState = renderStateFor(placement);
boolean bitmapChanged = bitmapResult.created() boolean bitmapChanged = bitmapResult.created()
|| !desiredState.equals(statesByProxy.get(proxy)); || !desiredState.equals(statesByProxy.get(proxy));
if (bitmapChanged) { if (bitmapChanged) {
@@ -269,6 +285,7 @@ final class SnapshotRenderer {
proxy.setImageBitmap(bitmap); proxy.setImageBitmap(bitmap);
proxyChanged = true; proxyChanged = true;
} }
}
if (proxy.getAlpha() != 1f) { if (proxy.getAlpha() != 1f) {
proxy.setAlpha(1f); proxy.setAlpha(1f);
proxyChanged = true; proxyChanged = true;
@@ -305,6 +322,52 @@ final class SnapshotRenderer {
return renderedBounds; return renderedBounds;
} }
private boolean canReuseAnimatedProxy(
SnapshotRenderState currentState,
SnapshotRenderState desiredState
) {
return currentState != null
&& desiredState != null
&& Objects.equals(currentState.key(), desiredState.key())
&& currentState.width() == desiredState.width()
&& currentState.height() == desiredState.height()
&& currentState.signal() == desiredState.signal()
&& currentState.overflowDot() == desiredState.overflowDot()
&& currentState.overflowDotColor() == desiredState.overflowDotColor()
&& currentState.sourceOffsetX() == desiredState.sourceOffsetX()
&& currentState.sourceRenderBoundsSignature() == desiredState.sourceRenderBoundsSignature()
&& Objects.equals(currentState.heldSignalKey(), desiredState.heldSignalKey())
&& currentState.heldBitmapId() == desiredState.heldBitmapId()
&& currentState.sourceMode() == desiredState.sourceMode()
&& currentState.tintSignature() == desiredState.tintSignature();
}
private Drawable animatedNotificationDrawable(SnapshotPlacement placement) {
if (placement == null
|| placement.source() == null
|| placement.source().mode() != SnapshotMode.NOTIFICATION_DRAWABLE
|| !(placement.source().view() instanceof ImageView imageView)) {
return null;
}
Drawable drawable = imageView.getDrawable();
return drawable instanceof AnimationDrawable ? drawable : null;
}
private Drawable newDrawableInstance(Drawable drawable) {
Drawable.ConstantState constantState = drawable != null ? drawable.getConstantState() : null;
if (constantState != null) {
return constantState.newDrawable().mutate();
}
return drawable != null ? drawable.mutate() : null;
}
private void startAnimationIfNeeded(Drawable drawable) {
if (drawable instanceof AnimationDrawable animationDrawable && !animationDrawable.isRunning()) {
animationDrawable.setVisible(true, true);
animationDrawable.start();
}
}
void clear(ViewGroup host) { void clear(ViewGroup host) {
LinkedHashMap<String, ImageView> proxies = proxiesByHost.remove(host); LinkedHashMap<String, ImageView> proxies = proxiesByHost.remove(host);
if (proxies == null) { if (proxies == null) {