Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7354b30d authored by Alan Viverette's avatar Alan Viverette
Browse files

Add layer width, height, gravity, and RTL insets for LayerDrawable

Bug: 18473819
Change-Id: Iae8e3dbd3fcc7f4c2f08b266c69d40036e75dfb6
parent ad575295
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -529,6 +529,7 @@ package android {
    field public static final int ellipsize = 16842923; // 0x10100ab
    field public static final int ems = 16843096; // 0x1010158
    field public static final int enabled = 16842766; // 0x101000e
    field public static final int end = 16843997; // 0x10104dd
    field public static final int endColor = 16843166; // 0x101019e
    field public static final deprecated int endYear = 16843133; // 0x101017d
    field public static final int enterFadeDuration = 16843532; // 0x101030c
@@ -1128,6 +1129,7 @@ package android {
    field public static final int stackFromBottom = 16843005; // 0x10100fd
    field public static final int stackViewStyle = 16843838; // 0x101043e
    field public static final int starStyle = 16842882; // 0x1010082
    field public static final int start = 16843996; // 0x10104dc
    field public static final int startColor = 16843165; // 0x101019d
    field public static final int startDelay = 16843746; // 0x10103e2
    field public static final int startOffset = 16843198; // 0x10101be
@@ -11946,6 +11948,9 @@ package android.graphics.drawable {
    method public android.graphics.drawable.Drawable findDrawableByLayerId(int);
    method public android.graphics.drawable.Drawable getDrawable(int);
    method public int getId(int);
    method public int getLayerGravity(int);
    method public int getLayerHeight(int);
    method public int getLayerWidth(int);
    method public int getNumberOfLayers();
    method public int getOpacity();
    method public int getPaddingMode();
@@ -11955,7 +11960,10 @@ package android.graphics.drawable {
    method public void setColorFilter(android.graphics.ColorFilter);
    method public boolean setDrawableByLayerId(int, android.graphics.drawable.Drawable);
    method public void setId(int, int);
    method public void setLayerGravity(int, int);
    method public void setLayerInset(int, int, int, int, int);
    method public void setLayerInsetRelative(int, int, int, int, int);
    method public void setLayerSize(int, int, int);
    method public void setOpacity(int);
    method public void setPaddingMode(int);
    method public void unscheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable);
+8 −0
Original line number Diff line number Diff line
@@ -601,6 +601,7 @@ package android {
    field public static final int ellipsize = 16842923; // 0x10100ab
    field public static final int ems = 16843096; // 0x1010158
    field public static final int enabled = 16842766; // 0x101000e
    field public static final int end = 16843997; // 0x10104dd
    field public static final int endColor = 16843166; // 0x101019e
    field public static final deprecated int endYear = 16843133; // 0x101017d
    field public static final int enterFadeDuration = 16843532; // 0x101030c
@@ -1204,6 +1205,7 @@ package android {
    field public static final int stackFromBottom = 16843005; // 0x10100fd
    field public static final int stackViewStyle = 16843838; // 0x101043e
    field public static final int starStyle = 16842882; // 0x1010082
    field public static final int start = 16843996; // 0x10104dc
    field public static final int startColor = 16843165; // 0x101019d
    field public static final int startDelay = 16843746; // 0x10103e2
    field public static final int startOffset = 16843198; // 0x10101be
@@ -12214,6 +12216,9 @@ package android.graphics.drawable {
    method public android.graphics.drawable.Drawable findDrawableByLayerId(int);
    method public android.graphics.drawable.Drawable getDrawable(int);
    method public int getId(int);
    method public int getLayerGravity(int);
    method public int getLayerHeight(int);
    method public int getLayerWidth(int);
    method public int getNumberOfLayers();
    method public int getOpacity();
    method public int getPaddingMode();
@@ -12223,7 +12228,10 @@ package android.graphics.drawable {
    method public void setColorFilter(android.graphics.ColorFilter);
    method public boolean setDrawableByLayerId(int, android.graphics.drawable.Drawable);
    method public void setId(int, int);
    method public void setLayerGravity(int, int);
    method public void setLayerInset(int, int, int, int, int);
    method public void setLayerInsetRelative(int, int, int, int, int);
    method public void setLayerSize(int, int, int);
    method public void setOpacity(int);
    method public void setPaddingMode(int);
    method public void unscheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable);
+21 −4
Original line number Diff line number Diff line
@@ -5078,14 +5078,31 @@

    <!-- Describes an item (or child) of a LayerDrawable. -->
    <declare-styleable name="LayerDrawableItem">
        <!-- Left coordinate of the layer. -->
        <!-- Left inset to apply to the layer. -->
        <attr name="left" />
        <!-- Top coordinate of the layer. -->
        <!-- Top inset to apply to the layer. -->
        <attr name="top" />
        <!-- Right coordinate of the layer. -->
        <!-- Right inset to apply to the layer. -->
        <attr name="right" />
        <!-- Bottom coordinate of the layer. -->
        <!-- Bottom inset to apply to the layer. -->
        <attr name="bottom" />
        <!-- Start inset to apply to the layer. Overrides {@code left} or
             {@code right} depending on layout direction. -->
        <attr name="start" format="dimension" />
        <!-- End inset to apply to the layer. Overrides {@code left} or
             {@code right} depending on layout direction. -->
        <attr name="end" format="dimension" />
        <!-- Width of the layer. Defaults to the layer's intrinsic width. -->
        <attr name="width" />
        <!-- Height of the layer. Defaults to the layer's intrinsic height -->
        <attr name="height" />
        <!-- Gravity used to align the layer within its container. If no value
             is specified, the default behavior depends on whether an explicit
             width or height has been set, If no dimension is set, gravity in
             that direction defaults to {@code fill_horizontal} or
             {@code fill_vertical}; otherwise, it defaults to {@code left} or
             {@code top}. -->
        <attr name="gravity" />
        <!-- Drawable used to render the layer. -->
        <attr name="drawable" />
        <!-- Identifier of the layer. This can be used to retrieve the layer
+2 −0
Original line number Diff line number Diff line
@@ -2611,6 +2611,8 @@
  <public type="attr" name="trackTint" />
  <public type="attr" name="trackTintMode" />
  <public type="attr" name="resizeableActivity" />
  <public type="attr" name="start" />
  <public type="attr" name="end" />

  <public type="style" name="Widget.Material.Button.Colored" />

+217 −7
Original line number Diff line number Diff line
@@ -29,6 +29,8 @@ import android.graphics.PixelFormat;
import android.graphics.PorterDuff.Mode;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.LayoutDirection;
import android.view.Gravity;
import android.view.View;

import com.android.internal.R;
@@ -54,6 +56,11 @@ import java.util.Collection;
 * @attr ref android.R.styleable#LayerDrawableItem_top
 * @attr ref android.R.styleable#LayerDrawableItem_right
 * @attr ref android.R.styleable#LayerDrawableItem_bottom
 * @attr ref android.R.styleable#LayerDrawableItem_start
 * @attr ref android.R.styleable#LayerDrawableItem_end
 * @attr ref android.R.styleable#LayerDrawableItem_width
 * @attr ref android.R.styleable#LayerDrawableItem_height
 * @attr ref android.R.styleable#LayerDrawableItem_gravity
 * @attr ref android.R.styleable#LayerDrawableItem_drawable
 * @attr ref android.R.styleable#LayerDrawableItem_id
*/
@@ -73,6 +80,9 @@ public class LayerDrawable extends Drawable implements Drawable.Callback {
     */
    public static final int PADDING_MODE_STACK = 1;

    /** Value used for undefined start and end insets. */
    private static final int UNDEFINED_INSET = Integer.MIN_VALUE;

    LayerState mLayerState;

    private int mOpacityOverride = PixelFormat.UNKNOWN;
@@ -231,6 +241,16 @@ public class LayerDrawable extends Drawable implements Drawable.Callback {
                R.styleable.LayerDrawableItem_right, layer.mInsetR);
        layer.mInsetB = a.getDimensionPixelOffset(
                R.styleable.LayerDrawableItem_bottom, layer.mInsetB);
        layer.mInsetS = a.getDimensionPixelOffset(
                R.styleable.LayerDrawableItem_start, layer.mInsetS);
        layer.mInsetE = a.getDimensionPixelOffset(
                R.styleable.LayerDrawableItem_end, layer.mInsetE);
        layer.mWidth = a.getDimensionPixelSize(
                R.styleable.LayerDrawableItem_width, layer.mWidth);
        layer.mHeight = a.getDimensionPixelSize(
                R.styleable.LayerDrawableItem_height, layer.mHeight);
        layer.mGravity = a.getInteger(
                R.styleable.LayerDrawableItem_gravity, layer.mGravity);
        layer.mId = a.getResourceId(R.styleable.LayerDrawableItem_id, layer.mId);

        final Drawable dr = a.getDrawable(R.styleable.LayerDrawableItem_drawable);
@@ -446,6 +466,89 @@ public class LayerDrawable extends Drawable implements Drawable.Callback {
        return false;
    }

    /**
     * Sets an explicit size for the specified layer.
     * <p>
     * <strong>Note:</strong> Setting an explicit layer size changes the
     * default layer gravity behavior. See {@link #setLayerGravity(int, int)}
     * for more information.
     *
     * @param index the index of the drawable to adjust
     * @param w width in pixels, or -1 to use the intrinsic width
     * @param h height in pixels, or -1 to use the intrinsic height
     *
     * @see #getLayerWidth(int)
     * @see #getLayerHeight(int)
     * @attr ref android.R.styleable#LayerDrawableItem_width
     * @attr ref android.R.styleable#LayerDrawableItem_height
     */
    public void setLayerSize(int index, int w, int h) {
        final ChildDrawable childDrawable = mLayerState.mChildren[index];
        childDrawable.mWidth = w;
        childDrawable.mHeight = h;
    }

    /**
     * @param index the index of the drawable to adjust
     * @return the explicit width of the layer, or -1 if not specified
     *
     * @see #setLayerSize(int, int, int)
     * @attr ref android.R.styleable#LayerDrawableItem_width
     */
    public int getLayerWidth(int index) {
        final ChildDrawable childDrawable = mLayerState.mChildren[index];
        return childDrawable.mWidth;
    }

    /**
     * @param index the index of the drawable to adjust
     * @return the explicit height of the layer, or -1 if not specified
     *
     * @see #setLayerSize(int, int, int)
     * @attr ref android.R.styleable#LayerDrawableItem_height
     */
    public int getLayerHeight(int index) {
        final ChildDrawable childDrawable = mLayerState.mChildren[index];
        return childDrawable.mHeight;
    }

    /**
     * Sets the gravity used to position or stretch the specified layer within
     * its container. Gravity is applied after any layer insets (see
     * {@link #setLayerInset(int, int, int, int, int)}) or padding (see
     * {@link #setPaddingMode(int)}).
     * <p>
     * If gravity is specified as {@link Gravity#NO_GRAVITY}, the default
     * behavior depends on whether an explicit width or height has been set
     * (see {@link #setLayerSize(int, int, int)}), If a dimension is not set,
     * gravity in that direction defaults to {@link Gravity#FILL_HORIZONTAL} or
     * {@link Gravity#FILL_VERTICAL}; otherwise, gravity in that direction
     * defaults to {@link Gravity#LEFT} or {@link Gravity#TOP}.
     *
     * @param index the index of the drawable to adjust
     * @param gravity the gravity to set for the layer
     *
     * @see #getLayerGravity(int)
     * @attr ref android.R.styleable#LayerDrawableItem_gravity
     */
    public void setLayerGravity(int index, int gravity) {
        final ChildDrawable childDrawable = mLayerState.mChildren[index];
        childDrawable.mGravity = gravity;
    }

    /**
     * @param index the index of the layer
     * @return the gravity used to position or stretch the specified layer
     *         within its container
     *
     * @see #setLayerGravity(int, int)
     * @attr ref android.R.styleable#LayerDrawableItem_gravity
     */
    public int getLayerGravity(int index) {
        final ChildDrawable childDrawable = mLayerState.mChildren[index];
        return childDrawable.mGravity;
    }

    /**
     * Specifies the insets in pixels for the drawable at the specified index.
     *
@@ -454,13 +557,43 @@ public class LayerDrawable extends Drawable implements Drawable.Callback {
     * @param t number of pixels to add to the top bound
     * @param r number of pixels to subtract from the right bound
     * @param b number of pixels to subtract from the bottom bound
     *
     * @attr ref android.R.styleable#LayerDrawableItem_left
     * @attr ref android.R.styleable#LayerDrawableItem_top
     * @attr ref android.R.styleable#LayerDrawableItem_right
     * @attr ref android.R.styleable#LayerDrawableItem_bottom
     */
    public void setLayerInset(int index, int l, int t, int r, int b) {
        setLayerInsetInternal(index, l, t, r, b, UNDEFINED_INSET, UNDEFINED_INSET);
    }

    /**
     * Specifies the relative insets in pixels for the drawable at the
     * specified index.
     *
     * @param index the index of the drawable to adjust
     * @param s number of pixels to inset from the start bound
     * @param t number of pixels to inset from the top bound
     * @param e number of pixels to inset from the end bound
     * @param b number of pixels to inset from the bottom bound
     *
     * @attr ref android.R.styleable#LayerDrawableItem_start
     * @attr ref android.R.styleable#LayerDrawableItem_top
     * @attr ref android.R.styleable#LayerDrawableItem_end
     * @attr ref android.R.styleable#LayerDrawableItem_bottom
     */
    public void setLayerInsetRelative(int index, int s, int t, int e, int b) {
        setLayerInsetInternal(index, 0, t, 0, b, s, e);
    }

    private void setLayerInsetInternal(int index, int l, int t, int r, int b, int s, int e) {
        final ChildDrawable childDrawable = mLayerState.mChildren[index];
        childDrawable.mInsetL = l;
        childDrawable.mInsetT = t;
        childDrawable.mInsetR = r;
        childDrawable.mInsetB = b;
        childDrawable.mInsetS = s;
        childDrawable.mInsetE = e;
    }

    /**
@@ -770,7 +903,7 @@ public class LayerDrawable extends Drawable implements Drawable.Callback {
        }

        if (paddingChanged) {
            onBoundsChange(getBounds());
            updateLayerBounds(getBounds());
        }

        return changed;
@@ -795,7 +928,7 @@ public class LayerDrawable extends Drawable implements Drawable.Callback {
        }

        if (paddingChanged) {
            onBoundsChange(getBounds());
            updateLayerBounds(getBounds());
        }

        return changed;
@@ -803,18 +936,50 @@ public class LayerDrawable extends Drawable implements Drawable.Callback {

    @Override
    protected void onBoundsChange(Rect bounds) {
        updateLayerBounds(bounds);
    }

    private void updateLayerBounds(Rect bounds) {
        int padL = 0;
        int padT = 0;
        int padR = 0;
        int padB = 0;

        final Rect outRect = mTmpRect;
        final int layoutDirection = getLayoutDirection();
        final boolean nest = mLayerState.mPaddingMode == PADDING_MODE_NEST;
        final ChildDrawable[] array = mLayerState.mChildren;
        final int N = mLayerState.mNum;
        for (int i = 0; i < N; i++) {
            final ChildDrawable r = array[i];
            r.mDrawable.setBounds(bounds.left + r.mInsetL + padL, bounds.top + r.mInsetT + padT,
                    bounds.right - r.mInsetR - padR, bounds.bottom - r.mInsetB - padB);
            final Drawable d = r.mDrawable;
            final Rect container = d.getBounds();

            // Take the resolved layout direction into account. If start / end
            // padding are defined, they will be resolved (hence overriding) to
            // left / right or right / left depending on the resolved layout
            // direction. If start / end padding are not defined, use the
            // left / right ones.
            final int insetL, insetR;
            if (layoutDirection == LayoutDirection.RTL) {
                insetL = r.mInsetE == UNDEFINED_INSET ? r.mInsetL : r.mInsetE;
                insetR = r.mInsetS == UNDEFINED_INSET ? r.mInsetR : r.mInsetS;
            } else {
                insetL = r.mInsetS == UNDEFINED_INSET ? r.mInsetL : r.mInsetS;
                insetR = r.mInsetE == UNDEFINED_INSET ? r.mInsetR : r.mInsetE;
            }

            // Establish containing region based on aggregate padding and
            // requested insets for the current layer.
            container.set(bounds.left + insetL + padL, bounds.top + r.mInsetT + padT,
                    bounds.right - insetR - padR, bounds.bottom - r.mInsetB - padB);

            // Apply resolved gravity to drawable based on resolved size.
            final int gravity = resolveGravity(r.mGravity, r.mWidth, r.mHeight);
            final int w = r.mWidth < 0 ? d.getIntrinsicWidth() : r.mWidth;
            final int h = r.mHeight < 0 ? d.getIntrinsicHeight() : r.mHeight;
            Gravity.apply(gravity, w, h, container, outRect, layoutDirection);
            d.setBounds(outRect);

            if (nest) {
                padL += mPaddingL[i];
@@ -825,6 +990,38 @@ public class LayerDrawable extends Drawable implements Drawable.Callback {
        }
    }

    /**
     * Resolves layer gravity given explicit gravity and dimensions.
     * <p>
     * If the client hasn't specified a gravity but has specified an explicit
     * dimension, defaults to START or TOP. Otherwise, defaults to FILL to
     * preserve legacy behavior.
     *
     * @param gravity
     * @param width
     * @param height
     * @return
     */
    private int resolveGravity(int gravity, int width, int height) {
        if (!Gravity.isHorizontal(gravity)) {
            if (width < 0) {
                gravity |= Gravity.FILL_HORIZONTAL;
            } else {
                gravity |= Gravity.START;
            }
        }

        if (!Gravity.isVertical(gravity)) {
            if (height < 0) {
                gravity |= Gravity.FILL_VERTICAL;
            } else {
                gravity |= Gravity.TOP;
            }
        }

        return gravity;
    }

    @Override
    public int getIntrinsicWidth() {
        int width = -1;
@@ -836,7 +1033,8 @@ public class LayerDrawable extends Drawable implements Drawable.Callback {
        final int N = mLayerState.mNum;
        for (int i = 0; i < N; i++) {
            final ChildDrawable r = array[i];
            final int w = r.mDrawable.getIntrinsicWidth() + r.mInsetL + r.mInsetR + padL + padR;
            final int minWidth = r.mWidth < 0 ? r.mDrawable.getIntrinsicWidth() : r.mWidth;
            final int w = minWidth + r.mInsetL + r.mInsetR + padL + padR;
            if (w > width) {
                width = w;
            }
@@ -861,7 +1059,8 @@ public class LayerDrawable extends Drawable implements Drawable.Callback {
        final int N = mLayerState.mNum;
        for (int i = 0; i < N; i++) {
            final ChildDrawable r = array[i];
            int h = r.mDrawable.getIntrinsicHeight() + r.mInsetT + r.mInsetB + padT + padB;
            final int minHeight = r.mHeight < 0 ? r.mDrawable.getIntrinsicHeight() : r.mHeight;
            final int h = minHeight + r.mInsetT + r.mInsetB + padT + padB;
            if (h > height) {
                height = h;
            }
@@ -948,18 +1147,24 @@ public class LayerDrawable extends Drawable implements Drawable.Callback {
    /** @hide */
    @Override
    public void setLayoutDirection(int layoutDirection) {
        super.setLayoutDirection(layoutDirection);
        final ChildDrawable[] array = mLayerState.mChildren;
        final int N = mLayerState.mNum;
        for (int i = 0; i < N; i++) {
            array[i].mDrawable.setLayoutDirection(layoutDirection);
        }
        super.setLayoutDirection(layoutDirection);
        updateLayerBounds(getBounds());
    }

    static class ChildDrawable {
        public Drawable mDrawable;
        public int[] mThemeAttrs;
        public int mInsetL, mInsetT, mInsetR, mInsetB;
        public int mInsetS = UNDEFINED_INSET;
        public int mInsetE = UNDEFINED_INSET;
        public int mWidth = -1;
        public int mHeight = -1;
        public int mGravity = Gravity.NO_GRAVITY;
        public int mId = View.NO_ID;

        ChildDrawable() {
@@ -981,6 +1186,11 @@ public class LayerDrawable extends Drawable implements Drawable.Callback {
            mInsetT = orig.mInsetT;
            mInsetR = orig.mInsetR;
            mInsetB = orig.mInsetB;
            mInsetS = orig.mInsetS;
            mInsetE = orig.mInsetE;
            mWidth = orig.mWidth;
            mHeight = orig.mHeight;
            mGravity = orig.mGravity;
            mId = orig.mId;
        }
    }