diff --git a/api/current.txt b/api/current.txt index 5304e001f6e7a..bcda821efd743 100644 --- a/api/current.txt +++ b/api/current.txt @@ -24079,6 +24079,7 @@ package android.view { method public android.view.View getFocusedChild(); method public android.view.animation.LayoutAnimationController getLayoutAnimation(); method public android.view.animation.Animation.AnimationListener getLayoutAnimationListener(); + method public int getLayoutMode(); method public android.animation.LayoutTransition getLayoutTransition(); method public int getPersistentDrawingCache(); method public int indexOfChild(android.view.View); @@ -24126,6 +24127,7 @@ package android.view { method public void setDescendantFocusability(int); method public void setLayoutAnimation(android.view.animation.LayoutAnimationController); method public void setLayoutAnimationListener(android.view.animation.Animation.AnimationListener); + method public void setLayoutMode(int); method public void setLayoutTransition(android.animation.LayoutTransition); method public void setMotionEventSplittingEnabled(boolean); method public void setOnHierarchyChangeListener(android.view.ViewGroup.OnHierarchyChangeListener); @@ -24138,9 +24140,11 @@ package android.view { method public void startViewTransition(android.view.View); method public void updateViewLayout(android.view.View, android.view.ViewGroup.LayoutParams); field protected static final int CLIP_TO_PADDING_MASK = 34; // 0x22 + field public static final int COMPONENT_BOUNDS = 0; // 0x0 field public static final int FOCUS_AFTER_DESCENDANTS = 262144; // 0x40000 field public static final int FOCUS_BEFORE_DESCENDANTS = 131072; // 0x20000 field public static final int FOCUS_BLOCK_DESCENDANTS = 393216; // 0x60000 + field public static final int LAYOUT_BOUNDS = 1; // 0x1 field public static final int PERSISTENT_ALL_CACHES = 3; // 0x3 field public static final int PERSISTENT_ANIMATION_CACHE = 1; // 0x1 field public static final int PERSISTENT_NO_CACHE = 0; // 0x0 diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 1fa19d134a1a2..d1e90b465d624 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -24,6 +24,7 @@ import android.content.res.TypedArray; import android.graphics.Bitmap; import android.graphics.Camera; import android.graphics.Canvas; +import android.graphics.Insets; import android.graphics.Interpolator; import android.graphics.LinearGradient; import android.graphics.Matrix; @@ -2597,6 +2598,12 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal @ViewDebug.ExportedProperty(category = "padding") protected int mPaddingBottom; + /** + * The layout insets in pixels, that is the distance in pixels between the + * visible edges of this view its bounds. + */ + private Insets mLayoutInsets; + /** * Briefly describes the view and is primarily used for accessibility support. */ @@ -13272,6 +13279,29 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal return mUserPaddingRelative; } + /** + * @hide + */ + public Insets getLayoutInsets() { + if (mLayoutInsets == null) { + if (mBackground == null) { + mLayoutInsets = Insets.NONE; + } else { + Rect insetRect = new Rect(); + boolean hasInsets = mBackground.getLayoutInsets(insetRect); + mLayoutInsets = hasInsets ? Insets.of(insetRect) : Insets.NONE; + } + } + return mLayoutInsets; + } + + /** + * @hide + */ + public void setLayoutInsets(Insets layoutInsets) { + mLayoutInsets = layoutInsets; + } + /** * Changes the selection state of this view. A view can be selected or not. * Note that selection is not the same as focus. Views are typically diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java index 121b544bf62c3..e5c5e459dad6a 100644 --- a/core/java/android/view/ViewGroup.java +++ b/core/java/android/view/ViewGroup.java @@ -169,6 +169,12 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager */ protected int mGroupFlags; + /* + * THe layout mode: either {@link #UNDEFINED_LAYOUT_MODE}, {@link #COMPONENT_BOUNDS} or + * {@link #LAYOUT_BOUNDS} + */ + private int mLayoutMode = UNDEFINED_LAYOUT_MODE; + /** * NOTE: If you change the flags below make sure to reflect the changes * the DisplayList class @@ -334,6 +340,24 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager */ public static final int PERSISTENT_ALL_CACHES = 0x3; + // Layout Modes + + private static final int UNDEFINED_LAYOUT_MODE = -1; + + /** + * This constant is a {@link #setLayoutMode(int) layoutMode}. + * Component bounds are the raw values of {@link #getLeft() left}, {@link #getTop() top}, + * {@link #getRight() right} and {@link #getBottom() bottom}. + */ + public static final int COMPONENT_BOUNDS = 0; + + /** + * This constant is a {@link #setLayoutMode(int) layoutMode}. + * Layout bounds are derived by offsetting the component bounds using + * {@link View#getLayoutInsets()}. + */ + public static final int LAYOUT_BOUNDS = 1; + /** * We clip to padding when FLAG_CLIP_TO_PADDING and FLAG_PADDING_NOT_NULL * are set at the same time. @@ -4367,6 +4391,52 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager mPersistentDrawingCache = drawingCacheToKeep & PERSISTENT_ALL_CACHES; } + /** + * Returns the basis of alignment during the layout of this view group: + * either {@link #COMPONENT_BOUNDS} or {@link #LAYOUT_BOUNDS}. + * + * @return whether or not this view group should use the component or layout bounds during + * layout operations + * + * @see #setLayoutMode(int) + */ + public int getLayoutMode() { + if (mLayoutMode == UNDEFINED_LAYOUT_MODE) { + ViewParent parent = getParent(); + if (parent instanceof ViewGroup) { + ViewGroup viewGroup = (ViewGroup) parent; + return viewGroup.getLayoutMode(); + } else { + int targetSdkVersion = mContext.getApplicationInfo().targetSdkVersion; + boolean preJellyBean = targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN; + return preJellyBean ? COMPONENT_BOUNDS : LAYOUT_BOUNDS; + } + + } + return mLayoutMode; + } + + /** + * Sets the basis of alignment during alignment of this view group. + * Valid values are either {@link #COMPONENT_BOUNDS} or {@link #LAYOUT_BOUNDS}. + *
+ * The default is to query the property of the parent if this view group has a parent. + * If this ViewGroup is the root of the view hierarchy the default + * value is {@link #LAYOUT_BOUNDS} for target SDK's greater than JellyBean, + * {@link #LAYOUT_BOUNDS} otherwise. + * + * @return whether or not this view group should use the component or layout bounds during + * layout operations + * + * @see #getLayoutMode() + */ + public void setLayoutMode(int layoutMode) { + if (mLayoutMode != layoutMode) { + mLayoutMode = layoutMode; + requestLayout(); + } + } + /** * Returns a new set of layout parameters based on the supplied attributes set. * diff --git a/core/java/android/widget/GridLayout.java b/core/java/android/widget/GridLayout.java index 60dd55cec36ed..1cb676f5c405a 100644 --- a/core/java/android/widget/GridLayout.java +++ b/core/java/android/widget/GridLayout.java @@ -20,6 +20,7 @@ import android.content.Context; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Color; +import android.graphics.Insets; import android.graphics.Paint; import android.util.AttributeSet; import android.util.Log; @@ -559,9 +560,9 @@ public class GridLayout extends ViewGroup { int flags = (gravity & mask) >> shift; switch (flags) { case (AXIS_SPECIFIED | AXIS_PULL_BEFORE): - return LEADING; + return horizontal ? LEFT : TOP; case (AXIS_SPECIFIED | AXIS_PULL_AFTER): - return TRAILING; + return horizontal ? RIGHT : BOTTOM; case (AXIS_SPECIFIED | AXIS_PULL_BEFORE | AXIS_PULL_AFTER): return FILL; case AXIS_SPECIFIED: @@ -1042,12 +1043,15 @@ public class GridLayout extends ViewGroup { int rightMargin = getMargin(c, true, false); int bottomMargin = getMargin(c, false, false); - // Alignment offsets: the location of the view relative to its alignment group. - int alignmentOffsetX = boundsX.getOffset(c, hAlign, leftMargin + pWidth + rightMargin); - int alignmentOffsetY = boundsY.getOffset(c, vAlign, topMargin + pHeight + bottomMargin); + int sumMarginsX = leftMargin + rightMargin; + int sumMarginsY = topMargin + bottomMargin; - int width = hAlign.getSizeInCell(c, pWidth, cellWidth - leftMargin - rightMargin); - int height = vAlign.getSizeInCell(c, pHeight, cellHeight - topMargin - bottomMargin); + // Alignment offsets: the location of the view relative to its alignment group. + int alignmentOffsetX = boundsX.getOffset(this, c, hAlign, pWidth + sumMarginsX, true); + int alignmentOffsetY = boundsY.getOffset(this, c, vAlign, pHeight + sumMarginsY, false); + + int width = hAlign.getSizeInCell(c, pWidth, cellWidth - sumMarginsX); + int height = vAlign.getSizeInCell(c, pHeight, cellHeight - sumMarginsY); int dx = x1 + gravityOffsetX + alignmentOffsetX; @@ -1181,7 +1185,7 @@ public class GridLayout extends ViewGroup { View c = getChildAt(i); LayoutParams lp = getLayoutParams(c); Spec spec = horizontal ? lp.columnSpec : lp.rowSpec; - groupBounds.getValue(i).include(c, spec, GridLayout.this, this); + groupBounds.getValue(i).include(GridLayout.this, c, spec, this); } } @@ -2138,16 +2142,30 @@ public class GridLayout extends ViewGroup { return before + after; } - protected int getOffset(View c, Alignment alignment, int size) { - return before - alignment.getAlignmentValue(c, size); + private int getAlignmentValue(GridLayout gl, View c, int size, Alignment a, boolean horiz) { + boolean useLayoutBounds = gl.getLayoutMode() == LAYOUT_BOUNDS; + if (!useLayoutBounds) { + return a.getAlignmentValue(c, size); + } else { + Insets insets = c.getLayoutInsets(); + int leadingInset = horiz ? insets.left : insets.top; // RTL? + int trailingInset = horiz ? insets.right : insets.bottom; // RTL? + int totalInset = leadingInset + trailingInset; + return leadingInset + a.getAlignmentValue(c, size - totalInset); + } } - protected final void include(View c, Spec spec, GridLayout gridLayout, Axis axis) { + protected int getOffset(GridLayout gl, View c, Alignment a, int size, boolean horizontal) { + return before - getAlignmentValue(gl, c, size, a, horizontal); + } + + protected final void include(GridLayout gl, View c, Spec spec, Axis axis) { this.flexibility &= spec.getFlexibility(); - int size = gridLayout.getMeasurementIncludingMargin(c, axis.horizontal); - Alignment alignment = gridLayout.getAlignment(spec.alignment, axis.horizontal); + boolean horizontal = axis.horizontal; + int size = gl.getMeasurementIncludingMargin(c, horizontal); + Alignment alignment = gl.getAlignment(spec.alignment, horizontal); // todo test this works correctly when the returned value is UNDEFINED - int before = alignment.getAlignmentValue(c, size); + int before = getAlignmentValue(gl, c, size, alignment, horizontal); include(before, size - before); } @@ -2614,8 +2632,8 @@ public class GridLayout extends ViewGroup { } @Override - protected int getOffset(View c, Alignment alignment, int size) { - return max(0, super.getOffset(c, alignment, size)); + protected int getOffset(GridLayout gl, View c, Alignment a, int size, boolean hrz) { + return max(0, super.getOffset(gl, c, a, size, hrz)); } }; } diff --git a/graphics/java/android/graphics/Insets.java b/graphics/java/android/graphics/Insets.java new file mode 100644 index 0000000000000..c570cd4a4f693 --- /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 86e824b9e8ea2..7d1942acaf43f 100644
--- a/graphics/java/android/graphics/drawable/Drawable.java
+++ b/graphics/java/android/graphics/drawable/Drawable.java
@@ -704,6 +704,20 @@ public abstract class Drawable {
return false;
}
+ /**
+ * 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.
@@ -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 b0f7fd3e1e80d..e10f9e8d8de19 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 1272071b2cda2..e502b7a0c16e8 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 rect, boolean dither) {
+ NinePatchState(NinePatch ninePatch, Rect padding, Rect layoutInsets) {
+ this(ninePatch, padding, layoutInsets, DEFAULT_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;
diff --git a/tests/GridLayoutTest/AndroidManifest.xml b/tests/GridLayoutTest/AndroidManifest.xml
index 141e8fafda76a..677220db8a539 100644
--- a/tests/GridLayoutTest/AndroidManifest.xml
+++ b/tests/GridLayoutTest/AndroidManifest.xml
@@ -83,6 +83,13 @@