Skip to content

Commit 1557fd7

Browse files
author
Philip Milne
committed
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
1 parent c58a6d2 commit 1557fd7

File tree

17 files changed

+435
-41
lines changed

17 files changed

+435
-41
lines changed

api/current.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24079,6 +24079,7 @@ package android.view {
2407924079
method public android.view.View getFocusedChild();
2408024080
method public android.view.animation.LayoutAnimationController getLayoutAnimation();
2408124081
method public android.view.animation.Animation.AnimationListener getLayoutAnimationListener();
24082+
method public int getLayoutMode();
2408224083
method public android.animation.LayoutTransition getLayoutTransition();
2408324084
method public int getPersistentDrawingCache();
2408424085
method public int indexOfChild(android.view.View);
@@ -24126,6 +24127,7 @@ package android.view {
2412624127
method public void setDescendantFocusability(int);
2412724128
method public void setLayoutAnimation(android.view.animation.LayoutAnimationController);
2412824129
method public void setLayoutAnimationListener(android.view.animation.Animation.AnimationListener);
24130+
method public void setLayoutMode(int);
2412924131
method public void setLayoutTransition(android.animation.LayoutTransition);
2413024132
method public void setMotionEventSplittingEnabled(boolean);
2413124133
method public void setOnHierarchyChangeListener(android.view.ViewGroup.OnHierarchyChangeListener);
@@ -24138,9 +24140,11 @@ package android.view {
2413824140
method public void startViewTransition(android.view.View);
2413924141
method public void updateViewLayout(android.view.View, android.view.ViewGroup.LayoutParams);
2414024142
field protected static final int CLIP_TO_PADDING_MASK = 34; // 0x22
24143+
field public static final int COMPONENT_BOUNDS = 0; // 0x0
2414124144
field public static final int FOCUS_AFTER_DESCENDANTS = 262144; // 0x40000
2414224145
field public static final int FOCUS_BEFORE_DESCENDANTS = 131072; // 0x20000
2414324146
field public static final int FOCUS_BLOCK_DESCENDANTS = 393216; // 0x60000
24147+
field public static final int LAYOUT_BOUNDS = 1; // 0x1
2414424148
field public static final int PERSISTENT_ALL_CACHES = 3; // 0x3
2414524149
field public static final int PERSISTENT_ANIMATION_CACHE = 1; // 0x1
2414624150
field public static final int PERSISTENT_NO_CACHE = 0; // 0x0

core/java/android/view/View.java

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import android.graphics.Bitmap;
2525
import android.graphics.Camera;
2626
import android.graphics.Canvas;
27+
import android.graphics.Insets;
2728
import android.graphics.Interpolator;
2829
import android.graphics.LinearGradient;
2930
import android.graphics.Matrix;
@@ -2597,6 +2598,12 @@ static class TransformationInfo {
25972598
@ViewDebug.ExportedProperty(category = "padding")
25982599
protected int mPaddingBottom;
25992600

2601+
/**
2602+
* The layout insets in pixels, that is the distance in pixels between the
2603+
* visible edges of this view its bounds.
2604+
*/
2605+
private Insets mLayoutInsets;
2606+
26002607
/**
26012608
* Briefly describes the view and is primarily used for accessibility support.
26022609
*/
@@ -13272,6 +13279,29 @@ public boolean isPaddingRelative() {
1327213279
return mUserPaddingRelative;
1327313280
}
1327413281

13282+
/**
13283+
* @hide
13284+
*/
13285+
public Insets getLayoutInsets() {
13286+
if (mLayoutInsets == null) {
13287+
if (mBackground == null) {
13288+
mLayoutInsets = Insets.NONE;
13289+
} else {
13290+
Rect insetRect = new Rect();
13291+
boolean hasInsets = mBackground.getLayoutInsets(insetRect);
13292+
mLayoutInsets = hasInsets ? Insets.of(insetRect) : Insets.NONE;
13293+
}
13294+
}
13295+
return mLayoutInsets;
13296+
}
13297+
13298+
/**
13299+
* @hide
13300+
*/
13301+
public void setLayoutInsets(Insets layoutInsets) {
13302+
mLayoutInsets = layoutInsets;
13303+
}
13304+
1327513305
/**
1327613306
* Changes the selection state of this view. A view can be selected or not.
1327713307
* Note that selection is not the same as focus. Views are typically

core/java/android/view/ViewGroup.java

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,12 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
169169
*/
170170
protected int mGroupFlags;
171171

172+
/*
173+
* THe layout mode: either {@link #UNDEFINED_LAYOUT_MODE}, {@link #COMPONENT_BOUNDS} or
174+
* {@link #LAYOUT_BOUNDS}
175+
*/
176+
private int mLayoutMode = UNDEFINED_LAYOUT_MODE;
177+
172178
/**
173179
* NOTE: If you change the flags below make sure to reflect the changes
174180
* the DisplayList class
@@ -334,6 +340,24 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
334340
*/
335341
public static final int PERSISTENT_ALL_CACHES = 0x3;
336342

343+
// Layout Modes
344+
345+
private static final int UNDEFINED_LAYOUT_MODE = -1;
346+
347+
/**
348+
* This constant is a {@link #setLayoutMode(int) layoutMode}.
349+
* Component bounds are the raw values of {@link #getLeft() left}, {@link #getTop() top},
350+
* {@link #getRight() right} and {@link #getBottom() bottom}.
351+
*/
352+
public static final int COMPONENT_BOUNDS = 0;
353+
354+
/**
355+
* This constant is a {@link #setLayoutMode(int) layoutMode}.
356+
* Layout bounds are derived by offsetting the component bounds using
357+
* {@link View#getLayoutInsets()}.
358+
*/
359+
public static final int LAYOUT_BOUNDS = 1;
360+
337361
/**
338362
* We clip to padding when FLAG_CLIP_TO_PADDING and FLAG_PADDING_NOT_NULL
339363
* are set at the same time.
@@ -4367,6 +4391,52 @@ public void setPersistentDrawingCache(int drawingCacheToKeep) {
43674391
mPersistentDrawingCache = drawingCacheToKeep & PERSISTENT_ALL_CACHES;
43684392
}
43694393

4394+
/**
4395+
* Returns the basis of alignment during the layout of this view group:
4396+
* either {@link #COMPONENT_BOUNDS} or {@link #LAYOUT_BOUNDS}.
4397+
*
4398+
* @return whether or not this view group should use the component or layout bounds during
4399+
* layout operations
4400+
*
4401+
* @see #setLayoutMode(int)
4402+
*/
4403+
public int getLayoutMode() {
4404+
if (mLayoutMode == UNDEFINED_LAYOUT_MODE) {
4405+
ViewParent parent = getParent();
4406+
if (parent instanceof ViewGroup) {
4407+
ViewGroup viewGroup = (ViewGroup) parent;
4408+
return viewGroup.getLayoutMode();
4409+
} else {
4410+
int targetSdkVersion = mContext.getApplicationInfo().targetSdkVersion;
4411+
boolean preJellyBean = targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN;
4412+
return preJellyBean ? COMPONENT_BOUNDS : LAYOUT_BOUNDS;
4413+
}
4414+
4415+
}
4416+
return mLayoutMode;
4417+
}
4418+
4419+
/**
4420+
* Sets the basis of alignment during alignment of this view group.
4421+
* Valid values are either {@link #COMPONENT_BOUNDS} or {@link #LAYOUT_BOUNDS}.
4422+
* <p>
4423+
* The default is to query the property of the parent if this view group has a parent.
4424+
* If this ViewGroup is the root of the view hierarchy the default
4425+
* value is {@link #LAYOUT_BOUNDS} for target SDK's greater than JellyBean,
4426+
* {@link #LAYOUT_BOUNDS} otherwise.
4427+
*
4428+
* @return whether or not this view group should use the component or layout bounds during
4429+
* layout operations
4430+
*
4431+
* @see #getLayoutMode()
4432+
*/
4433+
public void setLayoutMode(int layoutMode) {
4434+
if (mLayoutMode != layoutMode) {
4435+
mLayoutMode = layoutMode;
4436+
requestLayout();
4437+
}
4438+
}
4439+
43704440
/**
43714441
* Returns a new set of layout parameters based on the supplied attributes set.
43724442
*

core/java/android/widget/GridLayout.java

Lines changed: 33 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import android.content.res.TypedArray;
2121
import android.graphics.Canvas;
2222
import android.graphics.Color;
23+
import android.graphics.Insets;
2324
import android.graphics.Paint;
2425
import android.util.AttributeSet;
2526
import android.util.Log;
@@ -559,9 +560,9 @@ static Alignment getAlignment(int gravity, boolean horizontal) {
559560
int flags = (gravity & mask) >> shift;
560561
switch (flags) {
561562
case (AXIS_SPECIFIED | AXIS_PULL_BEFORE):
562-
return LEADING;
563+
return horizontal ? LEFT : TOP;
563564
case (AXIS_SPECIFIED | AXIS_PULL_AFTER):
564-
return TRAILING;
565+
return horizontal ? RIGHT : BOTTOM;
565566
case (AXIS_SPECIFIED | AXIS_PULL_BEFORE | AXIS_PULL_AFTER):
566567
return FILL;
567568
case AXIS_SPECIFIED:
@@ -1042,12 +1043,15 @@ protected void onLayout(boolean changed, int left, int top, int right, int botto
10421043
int rightMargin = getMargin(c, true, false);
10431044
int bottomMargin = getMargin(c, false, false);
10441045

1046+
int sumMarginsX = leftMargin + rightMargin;
1047+
int sumMarginsY = topMargin + bottomMargin;
1048+
10451049
// Alignment offsets: the location of the view relative to its alignment group.
1046-
int alignmentOffsetX = boundsX.getOffset(c, hAlign, leftMargin + pWidth + rightMargin);
1047-
int alignmentOffsetY = boundsY.getOffset(c, vAlign, topMargin + pHeight + bottomMargin);
1050+
int alignmentOffsetX = boundsX.getOffset(this, c, hAlign, pWidth + sumMarginsX, true);
1051+
int alignmentOffsetY = boundsY.getOffset(this, c, vAlign, pHeight + sumMarginsY, false);
10481052

1049-
int width = hAlign.getSizeInCell(c, pWidth, cellWidth - leftMargin - rightMargin);
1050-
int height = vAlign.getSizeInCell(c, pHeight, cellHeight - topMargin - bottomMargin);
1053+
int width = hAlign.getSizeInCell(c, pWidth, cellWidth - sumMarginsX);
1054+
int height = vAlign.getSizeInCell(c, pHeight, cellHeight - sumMarginsY);
10511055

10521056
int dx = x1 + gravityOffsetX + alignmentOffsetX;
10531057

@@ -1181,7 +1185,7 @@ private void computeGroupBounds() {
11811185
View c = getChildAt(i);
11821186
LayoutParams lp = getLayoutParams(c);
11831187
Spec spec = horizontal ? lp.columnSpec : lp.rowSpec;
1184-
groupBounds.getValue(i).include(c, spec, GridLayout.this, this);
1188+
groupBounds.getValue(i).include(GridLayout.this, c, spec, this);
11851189
}
11861190
}
11871191

@@ -2138,16 +2142,30 @@ protected int size(boolean min) {
21382142
return before + after;
21392143
}
21402144

2141-
protected int getOffset(View c, Alignment alignment, int size) {
2142-
return before - alignment.getAlignmentValue(c, size);
2145+
private int getAlignmentValue(GridLayout gl, View c, int size, Alignment a, boolean horiz) {
2146+
boolean useLayoutBounds = gl.getLayoutMode() == LAYOUT_BOUNDS;
2147+
if (!useLayoutBounds) {
2148+
return a.getAlignmentValue(c, size);
2149+
} else {
2150+
Insets insets = c.getLayoutInsets();
2151+
int leadingInset = horiz ? insets.left : insets.top; // RTL?
2152+
int trailingInset = horiz ? insets.right : insets.bottom; // RTL?
2153+
int totalInset = leadingInset + trailingInset;
2154+
return leadingInset + a.getAlignmentValue(c, size - totalInset);
2155+
}
2156+
}
2157+
2158+
protected int getOffset(GridLayout gl, View c, Alignment a, int size, boolean horizontal) {
2159+
return before - getAlignmentValue(gl, c, size, a, horizontal);
21432160
}
21442161

2145-
protected final void include(View c, Spec spec, GridLayout gridLayout, Axis axis) {
2162+
protected final void include(GridLayout gl, View c, Spec spec, Axis axis) {
21462163
this.flexibility &= spec.getFlexibility();
2147-
int size = gridLayout.getMeasurementIncludingMargin(c, axis.horizontal);
2148-
Alignment alignment = gridLayout.getAlignment(spec.alignment, axis.horizontal);
2164+
boolean horizontal = axis.horizontal;
2165+
int size = gl.getMeasurementIncludingMargin(c, horizontal);
2166+
Alignment alignment = gl.getAlignment(spec.alignment, horizontal);
21492167
// todo test this works correctly when the returned value is UNDEFINED
2150-
int before = alignment.getAlignmentValue(c, size);
2168+
int before = getAlignmentValue(gl, c, size, alignment, horizontal);
21512169
include(before, size - before);
21522170
}
21532171

@@ -2614,8 +2632,8 @@ protected int size(boolean min) {
26142632
}
26152633

26162634
@Override
2617-
protected int getOffset(View c, Alignment alignment, int size) {
2618-
return max(0, super.getOffset(c, alignment, size));
2635+
protected int getOffset(GridLayout gl, View c, Alignment a, int size, boolean hrz) {
2636+
return max(0, super.getOffset(gl, c, a, size, hrz));
26192637
}
26202638
};
26212639
}
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
/*
2+
* Copyright (C) 2006 The Android Open Source Project
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package android.graphics;
18+
19+
/**
20+
* An Insets instance holds four integer offsets which describe changes to the four
21+
* edges of a Rectangle. By convention, positive values move edges towards the
22+
* centre of the rectangle.
23+
* <p>
24+
* Insets are immutable so may be treated as values.
25+
*
26+
* @hide
27+
*/
28+
public class Insets {
29+
public static final Insets NONE = new Insets(0, 0, 0, 0);
30+
31+
public final int left;
32+
public final int top;
33+
public final int right;
34+
public final int bottom;
35+
36+
private Insets(int left, int top, int right, int bottom) {
37+
this.left = left;
38+
this.top = top;
39+
this.right = right;
40+
this.bottom = bottom;
41+
}
42+
43+
// Factory methods
44+
45+
/**
46+
* Return an Insets instance with the appropriate values.
47+
*
48+
* @param left the left inset
49+
* @param top the top inset
50+
* @param right the right inset
51+
* @param bottom the bottom inset
52+
*
53+
* @return Insets instance with the appropriate values
54+
*/
55+
public static Insets of(int left, int top, int right, int bottom) {
56+
if (left == 0 && top == 0 && right == 0 && bottom == 0) {
57+
return NONE;
58+
}
59+
return new Insets(left, top, right, bottom);
60+
}
61+
62+
/**
63+
* Return an Insets instance with the appropriate values.
64+
*
65+
* @param r the rectangle from which to take the values
66+
*
67+
* @return an Insets instance with the appropriate values
68+
*/
69+
public static Insets of(Rect r) {
70+
return of(r.left, r.top, r.right, r.bottom);
71+
}
72+
73+
/**
74+
* Two Insets instances are equal iff they belong to the same class and their fields are
75+
* pairwise equal.
76+
*
77+
* @param o the object to compare this instance with.
78+
*
79+
* @return true iff this object is equal {@code o}
80+
*/
81+
@Override
82+
public boolean equals(Object o) {
83+
if (this == o) return true;
84+
if (o == null || getClass() != o.getClass()) return false;
85+
86+
Insets insets = (Insets) o;
87+
88+
if (bottom != insets.bottom) return false;
89+
if (left != insets.left) return false;
90+
if (right != insets.right) return false;
91+
if (top != insets.top) return false;
92+
93+
return true;
94+
}
95+
96+
@Override
97+
public int hashCode() {
98+
int result = left;
99+
result = 31 * result + top;
100+
result = 31 * result + right;
101+
result = 31 * result + bottom;
102+
return result;
103+
}
104+
105+
@Override
106+
public String toString() {
107+
return "Insets{" +
108+
"left=" + left +
109+
", top=" + top +
110+
", right=" + right +
111+
", bottom=" + bottom +
112+
'}';
113+
}
114+
}

0 commit comments

Comments
 (0)