Commit 19595661 authored by Boris Sazonov's avatar Boris Sazonov Committed by Commit Bot

[Android] Implement LayerDrawableCompat and createLayerDrawable

This CL adds ApiCompatibilityUtils.createLayerDrawable and
LayerDrawableCompat. createLayerDrawable creates LayerDrawableCompat on
Android K and earlier versions and falls back to regular LayerDrawable
on newer versions. LayerDrawableCompat overrides mutate() method to work
around an issue in LayerDrawable.mutate() when the bounds of child
drawables aren't properly copied during the mutation. This issue would
force ImageView to appear empty if it contains a LayerDrawable and this
drawable is mutated.

Bug: 890317
Change-Id: I3479a304917df1873645ccfda7102475981eff5b
Reviewed-on: https://chromium-review.googlesource.com/1251544Reviewed-by: default avatarTed Choc <tedchoc@chromium.org>
Reviewed-by: default avatarYaron Friedman <yfriedman@chromium.org>
Commit-Queue: Boris Sazonov <bsazonov@chromium.org>
Cr-Commit-Position: refs/heads/master@{#595161}
parent a4285863
...@@ -21,6 +21,7 @@ import android.graphics.Color; ...@@ -21,6 +21,7 @@ import android.graphics.Color;
import android.graphics.ColorFilter; import android.graphics.ColorFilter;
import android.graphics.Rect; import android.graphics.Rect;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.graphics.drawable.LayerDrawable;
import android.graphics.drawable.VectorDrawable; import android.graphics.drawable.VectorDrawable;
import android.net.Uri; import android.net.Uri;
import android.os.Build; import android.os.Build;
...@@ -711,4 +712,52 @@ public class ApiCompatibilityUtils { ...@@ -711,4 +712,52 @@ public class ApiCompatibilityUtils {
view.setAccessibilityTraversalBefore(viewFocusedAfter); view.setAccessibilityTraversalBefore(viewFocusedAfter);
} }
} }
/**
* Creates regular LayerDrawable on Android L+. On older versions creates a helper class that
* fixes issues around {@link LayerDrawable#mutate()}. See https://crbug.com/890317 for details.
* @param layers A list of drawables to use as layers in this new drawable.
*/
public static LayerDrawable createLayerDrawable(@NonNull Drawable[] layers) {
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT) {
return new LayerDrawableCompat(layers);
}
return new LayerDrawable(layers);
}
private static class LayerDrawableCompat extends LayerDrawable {
private boolean mMutated;
LayerDrawableCompat(@NonNull Drawable[] layers) {
super(layers);
}
@Override
public Drawable mutate() {
// LayerDrawable in Android K loses bounds of layers, so this method works around that.
if (mMutated) {
// This object has already been mutated and shouldn't have any shared state.
return this;
}
// Save bounds before mutation.
Rect[] oldBounds = new Rect[getNumberOfLayers()];
for (int i = 0; i < getNumberOfLayers(); i++) {
oldBounds[i] = getDrawable(i).getBounds();
}
Drawable superResult = super.mutate();
if (superResult != this) {
// Unexpected, LayerDrawable.mutate() always returns this.
return superResult;
}
// Restore the saved bounds.
for (int i = 0; i < getNumberOfLayers(); i++) {
getDrawable(i).setBounds(oldBounds[i]);
}
mMutated = true;
return this;
}
}
} }
...@@ -9,7 +9,6 @@ import android.graphics.Bitmap; ...@@ -9,7 +9,6 @@ import android.graphics.Bitmap;
import android.graphics.Color; import android.graphics.Color;
import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.graphics.drawable.LayerDrawable;
import android.os.SystemClock; import android.os.SystemClock;
import android.support.annotation.IntDef; import android.support.annotation.IntDef;
...@@ -84,7 +83,7 @@ public class ThumbnailGradient { ...@@ -84,7 +83,7 @@ public class ThumbnailGradient {
? R.drawable.thumbnail_gradient_top_left ? R.drawable.thumbnail_gradient_top_left
: R.drawable.thumbnail_gradient_top_right); : R.drawable.thumbnail_gradient_top_right);
return new LayerDrawable( return ApiCompatibilityUtils.createLayerDrawable(
new Drawable[] {new BitmapDrawable(resources, bitmap), gradient}); new Drawable[] {new BitmapDrawable(resources, bitmap), gradient});
} }
......
...@@ -84,10 +84,10 @@ public abstract class PromoDialog extends AlwaysDismissedDialog ...@@ -84,10 +84,10 @@ public abstract class PromoDialog extends AlwaysDismissedDialog
* Force the promo dialog to have a fully opaque background hiding any underlying content. * Force the promo dialog to have a fully opaque background hiding any underlying content.
*/ */
protected void forceOpaqueBackground() { protected void forceOpaqueBackground() {
LayerDrawable background = new LayerDrawable(new Drawable[] { LayerDrawable background = ApiCompatibilityUtils.createLayerDrawable(
new ColorDrawable(Color.WHITE), new Drawable[] {new ColorDrawable(Color.WHITE),
new ColorDrawable(ApiCompatibilityUtils.getColor( new ColorDrawable(ApiCompatibilityUtils.getColor(
getContext().getResources(), R.color.modal_dialog_scrim_color))}); getContext().getResources(), R.color.modal_dialog_scrim_color))});
mScrimView.setBackground(background); mScrimView.setBackground(background);
} }
......
...@@ -9,6 +9,7 @@ import android.graphics.drawable.Drawable; ...@@ -9,6 +9,7 @@ import android.graphics.drawable.Drawable;
import android.graphics.drawable.LayerDrawable; import android.graphics.drawable.LayerDrawable;
import android.view.View; import android.view.View;
import org.chromium.base.ApiCompatibilityUtils;
import org.chromium.base.ContextUtils; import org.chromium.base.ContextUtils;
import org.chromium.chrome.R; import org.chromium.chrome.R;
...@@ -49,9 +50,9 @@ public class ViewHighlighter { ...@@ -49,9 +50,9 @@ public class ViewHighlighter {
background = background.getConstantState().newDrawable(resources); background = background.getConstantState().newDrawable(resources);
} }
LayerDrawable drawable = LayerDrawable drawable = ApiCompatibilityUtils.createLayerDrawable(background == null
new LayerDrawable(background == null ? new Drawable[] {pulseDrawable} ? new Drawable[] {pulseDrawable}
: new Drawable[] {background, pulseDrawable}); : new Drawable[] {background, pulseDrawable});
view.setBackground(drawable); view.setBackground(drawable);
view.setTag(R.id.highlight_state, true); view.setTag(R.id.highlight_state, true);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment