From 1557fd7809078e421f751efc7d2539b3efdc54b2 Mon Sep 17 00:00:00 2001 From: Philip Milne Date: Wed, 4 Apr 2012 23:41:34 -0700 Subject: Fix for bug 6110465. Add layout bound metadata to 9-patch files and make layouts take them into account. This CL contains a proposed API for dealing with layout bounds. This solution exposes: 1. Class: Insets - for storing layout Insets (and later possibly padding). 2. Methods: View:(get/set)LayoutInsets() - for storing layoutBounds. 3. Methods: ViewGroup:(get/set)LayoutMode() - for controlling layoutMode. It also iuncudes the changes to GridLayout to support layout bounds. Change-Id: I60c836b6530b61c5abf37f93ee9c44aad73573f1 --- graphics/java/android/graphics/Insets.java | 114 +++++++++++++++++++++ .../java/android/graphics/drawable/Drawable.java | 18 +++- .../graphics/drawable/DrawableContainer.java | 12 +++ .../graphics/drawable/NinePatchDrawable.java | 79 ++++++++++---- 4 files changed, 198 insertions(+), 25 deletions(-) create mode 100644 graphics/java/android/graphics/Insets.java (limited to 'graphics') diff --git a/graphics/java/android/graphics/Insets.java b/graphics/java/android/graphics/Insets.java new file mode 100644 index 0000000..c570cd4 --- /dev/null +++ b/graphics/java/android/graphics/Insets.java @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.graphics; + +/** + * An Insets instance holds four integer offsets which describe changes to the four + * edges of a Rectangle. By convention, positive values move edges towards the + * centre of the rectangle. + *

+ * Insets are immutable so may be treated as values. + * + * @hide + */ +public class Insets { + public static final Insets NONE = new Insets(0, 0, 0, 0); + + public final int left; + public final int top; + public final int right; + public final int bottom; + + private Insets(int left, int top, int right, int bottom) { + this.left = left; + this.top = top; + this.right = right; + this.bottom = bottom; + } + + // Factory methods + + /** + * Return an Insets instance with the appropriate values. + * + * @param left the left inset + * @param top the top inset + * @param right the right inset + * @param bottom the bottom inset + * + * @return Insets instance with the appropriate values + */ + public static Insets of(int left, int top, int right, int bottom) { + if (left == 0 && top == 0 && right == 0 && bottom == 0) { + return NONE; + } + return new Insets(left, top, right, bottom); + } + + /** + * Return an Insets instance with the appropriate values. + * + * @param r the rectangle from which to take the values + * + * @return an Insets instance with the appropriate values + */ + public static Insets of(Rect r) { + return of(r.left, r.top, r.right, r.bottom); + } + + /** + * Two Insets instances are equal iff they belong to the same class and their fields are + * pairwise equal. + * + * @param o the object to compare this instance with. + * + * @return true iff this object is equal {@code o} + */ + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + Insets insets = (Insets) o; + + if (bottom != insets.bottom) return false; + if (left != insets.left) return false; + if (right != insets.right) return false; + if (top != insets.top) return false; + + return true; + } + + @Override + public int hashCode() { + int result = left; + result = 31 * result + top; + result = 31 * result + right; + result = 31 * result + bottom; + return result; + } + + @Override + public String toString() { + return "Insets{" + + "left=" + left + + ", top=" + top + + ", right=" + right + + ", bottom=" + bottom + + '}'; + } +} diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java index 86e824b..7d1942a 100644 --- a/graphics/java/android/graphics/drawable/Drawable.java +++ b/graphics/java/android/graphics/drawable/Drawable.java @@ -705,6 +705,20 @@ public abstract class Drawable { } /** + * Return in insets the layout insets suggested by this Drawable for use with alignment + * operations during layout. Positive values move toward the + * center of the Drawable. Returns true if this drawable + * actually has a layout insets, else false. When false is returned, the padding + * is always set to 0. + * + * @hide + */ + public boolean getLayoutInsets(Rect insets) { + insets.set(0, 0, 0, 0); + return false; + } + + /** * Make this drawable mutable. This operation cannot be reversed. A mutable * drawable is guaranteed to not share its state with any other drawable. * This is especially useful when you need to modify properties of drawables @@ -965,9 +979,7 @@ public abstract class Drawable { Rect pad, Rect layoutBounds, String srcName) { if (np != null) { - NinePatchDrawable npd = new NinePatchDrawable(res, bm, np, pad, srcName); - npd.setLayoutBounds(layoutBounds); - return npd; + return new NinePatchDrawable(res, bm, np, pad, layoutBounds, srcName); } return new BitmapDrawable(res, bm); diff --git a/graphics/java/android/graphics/drawable/DrawableContainer.java b/graphics/java/android/graphics/drawable/DrawableContainer.java index b0f7fd3..e10f9e8 100644 --- a/graphics/java/android/graphics/drawable/DrawableContainer.java +++ b/graphics/java/android/graphics/drawable/DrawableContainer.java @@ -90,6 +90,18 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { } } + /** + * @hide + */ + @Override + public boolean getLayoutInsets(Rect insets) { + if (mCurrDrawable != null) { + return mCurrDrawable.getLayoutInsets(insets); + } else { + return super.getLayoutInsets(insets); + } + } + @Override public void setAlpha(int alpha) { if (mAlpha != alpha) { diff --git a/graphics/java/android/graphics/drawable/NinePatchDrawable.java b/graphics/java/android/graphics/drawable/NinePatchDrawable.java index 1272071..e502b7a 100644 --- a/graphics/java/android/graphics/drawable/NinePatchDrawable.java +++ b/graphics/java/android/graphics/drawable/NinePatchDrawable.java @@ -16,9 +16,17 @@ package android.graphics.drawable; -import android.graphics.*; import android.content.res.Resources; import android.content.res.TypedArray; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.Canvas; +import android.graphics.ColorFilter; +import android.graphics.NinePatch; +import android.graphics.Paint; +import android.graphics.PixelFormat; +import android.graphics.Rect; +import android.graphics.Region; import android.util.AttributeSet; import android.util.DisplayMetrics; import android.util.TypedValue; @@ -29,7 +37,7 @@ import java.io.IOException; import java.io.InputStream; /** - * + * * A resizeable bitmap, with stretchable areas that you define. This type of image * is defined in a .png file with a special format. * @@ -47,7 +55,6 @@ public class NinePatchDrawable extends Drawable { private NinePatchState mNinePatchState; private NinePatch mNinePatch; private Rect mPadding; - private Rect mLayoutBounds; private Paint mPaint; private boolean mMutated; @@ -56,7 +63,7 @@ public class NinePatchDrawable extends Drawable { // These are scaled to match the target density. private int mBitmapWidth; private int mBitmapHeight; - + NinePatchDrawable() { } @@ -69,7 +76,7 @@ public class NinePatchDrawable extends Drawable { public NinePatchDrawable(Bitmap bitmap, byte[] chunk, Rect padding, String srcName) { this(new NinePatchState(new NinePatch(bitmap, chunk, srcName), padding), null); } - + /** * Create drawable from raw nine-patch data, setting initial target density * based on the display metrics of the resources. @@ -79,7 +86,19 @@ public class NinePatchDrawable extends Drawable { this(new NinePatchState(new NinePatch(bitmap, chunk, srcName), padding), res); mNinePatchState.mTargetDensity = mTargetDensity; } - + + /** + * Create drawable from raw nine-patch data, setting initial target density + * based on the display metrics of the resources. + * + * @hide + */ + public NinePatchDrawable(Resources res, Bitmap bitmap, byte[] chunk, + Rect padding, Rect layoutInsets, String srcName) { + this(new NinePatchState(new NinePatch(bitmap, chunk, srcName), padding, layoutInsets), res); + mNinePatchState.mTargetDensity = mTargetDensity; + } + /** * Create drawable from existing nine-patch, not dealing with density. * @deprecated Use {@link #NinePatchDrawable(Resources, NinePatch)} @@ -99,13 +118,6 @@ public class NinePatchDrawable extends Drawable { mNinePatchState.mTargetDensity = mTargetDensity; } - /** - * @hide - */ - void setLayoutBounds(Rect layoutBounds) { - mLayoutBounds = layoutBounds; - } - private void setNinePatchState(NinePatchState state, Resources res) { mNinePatchState = state; mNinePatch = state.mNinePatch; @@ -201,13 +213,26 @@ public class NinePatchDrawable extends Drawable { public int getChangingConfigurations() { return super.getChangingConfigurations() | mNinePatchState.mChangingConfigurations; } - + @Override public boolean getPadding(Rect padding) { padding.set(mPadding); return true; } + /** + * @hide + */ + @Override + public boolean getLayoutInsets(Rect insets) { + Rect layoutInsets = mNinePatchState.mLayoutInsets; + if (layoutInsets == null) { + return super.getLayoutInsets(insets); + } + insets.set(layoutInsets); + return true; + } + @Override public void setAlpha(int alpha) { if (mPaint == null && alpha == 0xFF) { @@ -217,7 +242,7 @@ public class NinePatchDrawable extends Drawable { getPaint().setAlpha(alpha); invalidateSelf(); } - + @Override public void setColorFilter(ColorFilter cf) { if (mPaint == null && cf == null) { @@ -267,6 +292,7 @@ public class NinePatchDrawable extends Drawable { options.inScreenDensity = DisplayMetrics.DENSITY_DEVICE; final Rect padding = new Rect(); + final Rect layoutInsets = new Rect(); Bitmap bitmap = null; try { @@ -290,7 +316,7 @@ public class NinePatchDrawable extends Drawable { setNinePatchState(new NinePatchState( new NinePatch(bitmap, bitmap.getNinePatchChunk(), "XML 9-patch"), - padding, dither), r); + padding, layoutInsets, dither), r); mNinePatchState.mTargetDensity = mTargetDensity; a.recycle(); @@ -344,7 +370,7 @@ public class NinePatchDrawable extends Drawable { public Region getTransparentRegion() { return mNinePatch.getTransparentRegion(getBounds()); } - + @Override public ConstantState getConstantState() { mNinePatchState.mChangingConfigurations = getChangingConfigurations(); @@ -361,27 +387,36 @@ public class NinePatchDrawable extends Drawable { return this; } - final static class NinePatchState extends ConstantState { + private final static class NinePatchState extends ConstantState { final NinePatch mNinePatch; final Rect mPadding; + final Rect mLayoutInsets; final boolean mDither; int mChangingConfigurations; int mTargetDensity = DisplayMetrics.DENSITY_DEFAULT; NinePatchState(NinePatch ninePatch, Rect padding) { - this(ninePatch, padding, DEFAULT_DITHER); + this(ninePatch, padding, new Rect(), DEFAULT_DITHER); + } + + NinePatchState(NinePatch ninePatch, Rect padding, Rect layoutInsets) { + this(ninePatch, padding, layoutInsets, DEFAULT_DITHER); } - NinePatchState(NinePatch ninePatch, Rect rect, boolean dither) { + NinePatchState(NinePatch ninePatch, Rect rect, Rect layoutInsets, boolean dither) { mNinePatch = ninePatch; mPadding = rect; + mLayoutInsets = layoutInsets; mDither = dither; } + // Copy constructor + NinePatchState(NinePatchState state) { mNinePatch = new NinePatch(state.mNinePatch); // Note we don't copy the padding because it is immutable. mPadding = state.mPadding; + mLayoutInsets = state.mLayoutInsets; mDither = state.mDither; mChangingConfigurations = state.mChangingConfigurations; mTargetDensity = state.mTargetDensity; @@ -391,12 +426,12 @@ public class NinePatchDrawable extends Drawable { public Drawable newDrawable() { return new NinePatchDrawable(this, null); } - + @Override public Drawable newDrawable(Resources res) { return new NinePatchDrawable(this, res); } - + @Override public int getChangingConfigurations() { return mChangingConfigurations; -- cgit v1.1