Skip to content

Commit 4e1cb3b

Browse files
Philip MilneAndroid (Google) Code Review
authored andcommitted
Merge "Fix for bug 6110465."
2 parents 7c886ac + 1557fd7 commit 4e1cb3b

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
@@ -24127,6 +24127,7 @@ package android.view {
2412724127
method public android.view.View getFocusedChild();
2412824128
method public android.view.animation.LayoutAnimationController getLayoutAnimation();
2412924129
method public android.view.animation.Animation.AnimationListener getLayoutAnimationListener();
24130+
method public int getLayoutMode();
2413024131
method public android.animation.LayoutTransition getLayoutTransition();
2413124132
method public int getPersistentDrawingCache();
2413224133
method public int indexOfChild(android.view.View);
@@ -24174,6 +24175,7 @@ package android.view {
2417424175
method public void setDescendantFocusability(int);
2417524176
method public void setLayoutAnimation(android.view.animation.LayoutAnimationController);
2417624177
method public void setLayoutAnimationListener(android.view.animation.Animation.AnimationListener);
24178+
method public void setLayoutMode(int);
2417724179
method public void setLayoutTransition(android.animation.LayoutTransition);
2417824180
method public void setMotionEventSplittingEnabled(boolean);
2417924181
method public void setOnHierarchyChangeListener(android.view.ViewGroup.OnHierarchyChangeListener);
@@ -24186,9 +24188,11 @@ package android.view {
2418624188
method public void startViewTransition(android.view.View);
2418724189
method public void updateViewLayout(android.view.View, android.view.ViewGroup.LayoutParams);
2418824190
field protected static final int CLIP_TO_PADDING_MASK = 34; // 0x22
24191+
field public static final int COMPONENT_BOUNDS = 0; // 0x0
2418924192
field public static final int FOCUS_AFTER_DESCENDANTS = 262144; // 0x40000
2419024193
field public static final int FOCUS_BEFORE_DESCENDANTS = 131072; // 0x20000
2419124194
field public static final int FOCUS_BLOCK_DESCENDANTS = 393216; // 0x60000
24195+
field public static final int LAYOUT_BOUNDS = 1; // 0x1
2419224196
field public static final int PERSISTENT_ALL_CACHES = 3; // 0x3
2419324197
field public static final int PERSISTENT_ANIMATION_CACHE = 1; // 0x1
2419424198
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;
@@ -2697,6 +2698,12 @@ static class TransformationInfo {
26972698
@ViewDebug.ExportedProperty(category = "padding")
26982699
protected int mPaddingBottom;
26992700

2701+
/**
2702+
* The layout insets in pixels, that is the distance in pixels between the
2703+
* visible edges of this view its bounds.
2704+
*/
2705+
private Insets mLayoutInsets;
2706+
27002707
/**
27012708
* Briefly describes the view and is primarily used for accessibility support.
27022709
*/
@@ -13841,6 +13848,29 @@ public boolean isPaddingRelative() {
1384113848
return mUserPaddingRelative;
1384213849
}
1384313850

13851+
/**
13852+
* @hide
13853+
*/
13854+
public Insets getLayoutInsets() {
13855+
if (mLayoutInsets == null) {
13856+
if (mBackground == null) {
13857+
mLayoutInsets = Insets.NONE;
13858+
} else {
13859+
Rect insetRect = new Rect();
13860+
boolean hasInsets = mBackground.getLayoutInsets(insetRect);
13861+
mLayoutInsets = hasInsets ? Insets.of(insetRect) : Insets.NONE;
13862+
}
13863+
}
13864+
return mLayoutInsets;
13865+
}
13866+
13867+
/**
13868+
* @hide
13869+
*/
13870+
public void setLayoutInsets(Insets layoutInsets) {
13871+
mLayoutInsets = layoutInsets;
13872+
}
13873+
1384413874
/**
1384513875
* Changes the selection state of this view. A view can be selected or not.
1384613876
* 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
@@ -170,6 +170,12 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
170170
*/
171171
protected int mGroupFlags;
172172

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

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

4450+
/**
4451+
* Returns the basis of alignment during the layout of this view group:
4452+
* either {@link #COMPONENT_BOUNDS} or {@link #LAYOUT_BOUNDS}.
4453+
*
4454+
* @return whether or not this view group should use the component or layout bounds during
4455+
* layout operations
4456+
*
4457+
* @see #setLayoutMode(int)
4458+
*/
4459+
public int getLayoutMode() {
4460+
if (mLayoutMode == UNDEFINED_LAYOUT_MODE) {
4461+
ViewParent parent = getParent();
4462+
if (parent instanceof ViewGroup) {
4463+
ViewGroup viewGroup = (ViewGroup) parent;
4464+
return viewGroup.getLayoutMode();
4465+
} else {
4466+
int targetSdkVersion = mContext.getApplicationInfo().targetSdkVersion;
4467+
boolean preJellyBean = targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN;
4468+
return preJellyBean ? COMPONENT_BOUNDS : LAYOUT_BOUNDS;
4469+
}
4470+
4471+
}
4472+
return mLayoutMode;
4473+
}
4474+
4475+
/**
4476+
* Sets the basis of alignment during alignment of this view group.
4477+
* Valid values are either {@link #COMPONENT_BOUNDS} or {@link #LAYOUT_BOUNDS}.
4478+
* <p>
4479+
* The default is to query the property of the parent if this view group has a parent.
4480+
* If this ViewGroup is the root of the view hierarchy the default
4481+
* value is {@link #LAYOUT_BOUNDS} for target SDK's greater than JellyBean,
4482+
* {@link #LAYOUT_BOUNDS} otherwise.
4483+
*
4484+
* @return whether or not this view group should use the component or layout bounds during
4485+
* layout operations
4486+
*
4487+
* @see #getLayoutMode()
4488+
*/
4489+
public void setLayoutMode(int layoutMode) {
4490+
if (mLayoutMode != layoutMode) {
4491+
mLayoutMode = layoutMode;
4492+
requestLayout();
4493+
}
4494+
}
4495+
44264496
/**
44274497
* Returns a new set of layout parameters based on the supplied attributes set.
44284498
*

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)