Support animated notification icon snapshots
This commit is contained in:
@@ -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,35 +240,51 @@ final class SnapshotRenderer {
|
|||||||
proxy.setTag(key);
|
proxy.setTag(key);
|
||||||
proxyChanged = true;
|
proxyChanged = true;
|
||||||
}
|
}
|
||||||
BitmapResult bitmapResult = bitmapFor(proxy, bounds);
|
|
||||||
Bitmap bitmap = bitmapResult.bitmap();
|
|
||||||
SnapshotRenderState desiredState = renderStateFor(placement);
|
SnapshotRenderState desiredState = renderStateFor(placement);
|
||||||
boolean bitmapChanged = bitmapResult.created()
|
Drawable animatedDrawable = animatedNotificationDrawable(placement);
|
||||||
|| !desiredState.equals(statesByProxy.get(proxy));
|
if (animatedDrawable != null) {
|
||||||
if (bitmapChanged) {
|
SnapshotRenderState currentState = statesByProxy.get(proxy);
|
||||||
if (placement.overflowDot()) {
|
boolean drawableChanged = !(proxy.getDrawable() instanceof AnimationDrawable)
|
||||||
drawOverflowDot(bitmap, placement.overflowDotColor(), placement.sourceOffsetX());
|
|| !canReuseAnimatedProxy(currentState, desiredState);
|
||||||
} else if (placement.heldSignal() != null) {
|
if (drawableChanged) {
|
||||||
drawHeldSignal(placement.heldSignal(), bitmap);
|
Drawable proxyDrawable = newDrawableInstance(animatedDrawable);
|
||||||
} else if (placement.source() != null
|
proxy.setImageDrawable(proxyDrawable);
|
||||||
&& placement.source().mode() == SnapshotMode.APP_ICON) {
|
proxyChanged = true;
|
||||||
drawAppIcon(host.getContext(), placement.source(), bitmap);
|
}
|
||||||
} else if (placement.source() != null) {
|
startAnimationIfNeeded(proxy.getDrawable());
|
||||||
drawSnapshot(placement, bitmap);
|
if (!desiredState.equals(currentState)) {
|
||||||
applyStatusBarTintTarget(placement.source(), bitmap);
|
statesByProxy.put(proxy, desiredState);
|
||||||
normalizeSemiTransparentDarkIcon(bitmap);
|
}
|
||||||
if (placement.signal()) {
|
} else {
|
||||||
saveHeldSignal(key, bounds, bitmap);
|
BitmapResult bitmapResult = bitmapFor(proxy, bounds);
|
||||||
|
Bitmap bitmap = bitmapResult.bitmap();
|
||||||
|
boolean bitmapChanged = bitmapResult.created()
|
||||||
|
|| !desiredState.equals(statesByProxy.get(proxy));
|
||||||
|
if (bitmapChanged) {
|
||||||
|
if (placement.overflowDot()) {
|
||||||
|
drawOverflowDot(bitmap, placement.overflowDotColor(), placement.sourceOffsetX());
|
||||||
|
} else if (placement.heldSignal() != null) {
|
||||||
|
drawHeldSignal(placement.heldSignal(), bitmap);
|
||||||
|
} else if (placement.source() != null
|
||||||
|
&& placement.source().mode() == SnapshotMode.APP_ICON) {
|
||||||
|
drawAppIcon(host.getContext(), placement.source(), bitmap);
|
||||||
|
} else if (placement.source() != null) {
|
||||||
|
drawSnapshot(placement, bitmap);
|
||||||
|
applyStatusBarTintTarget(placement.source(), bitmap);
|
||||||
|
normalizeSemiTransparentDarkIcon(bitmap);
|
||||||
|
if (placement.signal()) {
|
||||||
|
saveHeldSignal(key, bounds, bitmap);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
bitmap.eraseColor(Color.TRANSPARENT);
|
||||||
}
|
}
|
||||||
} else {
|
statesByProxy.put(proxy, desiredState);
|
||||||
bitmap.eraseColor(Color.TRANSPARENT);
|
proxyChanged = true;
|
||||||
|
}
|
||||||
|
if (proxy.getDrawable() == null) {
|
||||||
|
proxy.setImageBitmap(bitmap);
|
||||||
|
proxyChanged = true;
|
||||||
}
|
}
|
||||||
statesByProxy.put(proxy, desiredState);
|
|
||||||
proxyChanged = true;
|
|
||||||
}
|
|
||||||
if (proxy.getDrawable() == null) {
|
|
||||||
proxy.setImageBitmap(bitmap);
|
|
||||||
proxyChanged = true;
|
|
||||||
}
|
}
|
||||||
if (proxy.getAlpha() != 1f) {
|
if (proxy.getAlpha() != 1f) {
|
||||||
proxy.setAlpha(1f);
|
proxy.setAlpha(1f);
|
||||||
@@ -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) {
|
||||||
|
|||||||
Reference in New Issue
Block a user