Merge "Fix issue #8311263: Corrupted UI across all tabs in People app" into jb-mr2-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
9c9aec721a
@@ -16,33 +16,42 @@
|
||||
|
||||
package com.android.internal.widget;
|
||||
|
||||
import android.view.ViewGroup;
|
||||
import com.android.internal.app.ActionBarImpl;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Rect;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
/**
|
||||
* Special layout for the containing of an overlay action bar (and its
|
||||
* content) to correctly handle fitting system windows when the content
|
||||
* has request that its layout ignore them.
|
||||
*/
|
||||
public class ActionBarOverlayLayout extends FrameLayout {
|
||||
public class ActionBarOverlayLayout extends ViewGroup {
|
||||
private int mActionBarHeight;
|
||||
private ActionBarImpl mActionBar;
|
||||
private int mWindowVisibility = View.VISIBLE;
|
||||
|
||||
// The main UI elements that we handle the layout of.
|
||||
private View mContent;
|
||||
private View mActionBarTop;
|
||||
private View mActionBarBottom;
|
||||
|
||||
// Some interior UI elements.
|
||||
private ActionBarContainer mContainerView;
|
||||
private ActionBarView mActionView;
|
||||
private View mActionBarBottom;
|
||||
|
||||
private boolean mOverlayMode;
|
||||
private int mLastSystemUiVisibility;
|
||||
private final Rect mLocalInsets = new Rect();
|
||||
private final Rect mBaseContentInsets = new Rect();
|
||||
private final Rect mLastBaseContentInsets = new Rect();
|
||||
private final Rect mContentInsets = new Rect();
|
||||
private final Rect mBaseInnerInsets = new Rect();
|
||||
private final Rect mInnerInsets = new Rect();
|
||||
private final Rect mLastInnerInsets = new Rect();
|
||||
|
||||
static final int[] mActionBarSizeAttr = new int [] {
|
||||
com.android.internal.R.attr.actionBarSize
|
||||
@@ -139,7 +148,7 @@ public class ActionBarOverlayLayout extends FrameLayout {
|
||||
private boolean applyInsets(View view, Rect insets, boolean left, boolean top,
|
||||
boolean bottom, boolean right) {
|
||||
boolean changed = false;
|
||||
FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams)view.getLayoutParams();
|
||||
LayoutParams lp = (LayoutParams)view.getLayoutParams();
|
||||
if (left && lp.leftMargin != insets.left) {
|
||||
changed = true;
|
||||
lp.leftMargin = insets.left;
|
||||
@@ -168,54 +177,165 @@ public class ActionBarOverlayLayout extends FrameLayout {
|
||||
|
||||
// The top and bottom action bars are always within the content area.
|
||||
boolean changed = applyInsets(mActionBarTop, insets, true, true, false, true);
|
||||
if (mActionBarBottom != null) {
|
||||
changed |= applyInsets(mActionBarBottom, insets, true, false, true, true);
|
||||
}
|
||||
changed |= applyInsets(mActionBarBottom, insets, true, false, true, true);
|
||||
|
||||
int topSpace = 0;
|
||||
if (stable || mActionBarTop.getVisibility() == VISIBLE) {
|
||||
// This is the space needed on top of the window for the action bar.
|
||||
topSpace = mActionBarHeight;
|
||||
mBaseInnerInsets.set(insets);
|
||||
computeFitSystemWindows(mBaseInnerInsets, mBaseContentInsets);
|
||||
if (!mLastBaseContentInsets.equals(mBaseContentInsets)) {
|
||||
changed = true;
|
||||
mLastBaseContentInsets.set(mBaseContentInsets);
|
||||
}
|
||||
if (mActionBar != null && mActionBar.hasNonEmbeddedTabs()) {
|
||||
View tabs = mContainerView.getTabContainer();
|
||||
if (tabs != null && (stable || tabs.getVisibility() == VISIBLE)) {
|
||||
// If tabs are not embedded, increase space on top to account for them.
|
||||
topSpace += mActionBarHeight;
|
||||
}
|
||||
}
|
||||
|
||||
int bottomSpace = 0;
|
||||
if (mActionView.isSplitActionBar()) {
|
||||
if ((mActionBarBottom != null
|
||||
&& (stable || mActionBarBottom.getVisibility() == VISIBLE))) {
|
||||
// If action bar is split, adjust bottom insets for it.
|
||||
bottomSpace = mActionBarHeight;
|
||||
}
|
||||
}
|
||||
|
||||
// If the window has not requested system UI layout flags, we need to
|
||||
// make sure its content is not being covered by system UI... though it
|
||||
// will still be covered by the action bar since they have requested it to
|
||||
// overlay.
|
||||
boolean res = computeFitSystemWindows(insets, mLocalInsets);
|
||||
if (!mOverlayMode && !stable) {
|
||||
mLocalInsets.top += topSpace;
|
||||
mLocalInsets.bottom += bottomSpace;
|
||||
} else {
|
||||
insets.top += topSpace;
|
||||
insets.bottom += bottomSpace;
|
||||
}
|
||||
changed |= applyInsets(mContent, mLocalInsets, true, true, true, true);
|
||||
|
||||
if (changed) {
|
||||
requestLayout();
|
||||
}
|
||||
|
||||
super.fitSystemWindows(insets);
|
||||
// We don't do any more at this point. To correctly compute the content/inner
|
||||
// insets in all cases, we need to know the measured size of the various action
|
||||
// bar elements. fitSystemWindows() happens before the measure pass, so we can't
|
||||
// do that here. Instead we will take this up in onMeasure().
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected LayoutParams generateDefaultLayoutParams() {
|
||||
return new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LayoutParams generateLayoutParams(AttributeSet attrs) {
|
||||
return new LayoutParams(getContext(), attrs);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
int maxHeight = 0;
|
||||
int maxWidth = 0;
|
||||
int childState = 0;
|
||||
|
||||
int topInset = 0;
|
||||
int bottomInset = 0;
|
||||
|
||||
measureChildWithMargins(mActionBarTop, widthMeasureSpec, 0, heightMeasureSpec, 0);
|
||||
LayoutParams lp = (LayoutParams) mActionBarTop.getLayoutParams();
|
||||
maxWidth = Math.max(maxWidth,
|
||||
mActionBarTop.getMeasuredWidth() + lp.leftMargin + lp.rightMargin);
|
||||
maxHeight = Math.max(maxHeight,
|
||||
mActionBarTop.getMeasuredHeight() + lp.topMargin + lp.bottomMargin);
|
||||
childState = combineMeasuredStates(childState, mActionBarTop.getMeasuredState());
|
||||
|
||||
measureChildWithMargins(mActionBarBottom, widthMeasureSpec, 0, heightMeasureSpec, 0);
|
||||
lp = (LayoutParams) mActionBarBottom.getLayoutParams();
|
||||
maxWidth = Math.max(maxWidth,
|
||||
mActionBarBottom.getMeasuredWidth() + lp.leftMargin + lp.rightMargin);
|
||||
maxHeight = Math.max(maxHeight,
|
||||
mActionBarBottom.getMeasuredHeight() + lp.topMargin + lp.bottomMargin);
|
||||
childState = combineMeasuredStates(childState, mActionBarBottom.getMeasuredState());
|
||||
|
||||
final int vis = getWindowSystemUiVisibility();
|
||||
final boolean stable = (vis & SYSTEM_UI_FLAG_LAYOUT_STABLE) != 0;
|
||||
|
||||
if (stable) {
|
||||
// This is the standard space needed for the action bar. For stable measurement,
|
||||
// we can't depend on the size currently reported by it -- this must remain constant.
|
||||
topInset = mActionBarHeight;
|
||||
if (mActionBar != null && mActionBar.hasNonEmbeddedTabs()) {
|
||||
View tabs = mContainerView.getTabContainer();
|
||||
if (tabs != null) {
|
||||
// If tabs are not embedded, increase space on top to account for them.
|
||||
topInset += mActionBarHeight;
|
||||
}
|
||||
}
|
||||
} else if (mActionBarTop.getVisibility() == VISIBLE) {
|
||||
// This is the space needed on top of the window for all of the action bar
|
||||
// and tabs.
|
||||
topInset = mActionBarTop.getMeasuredHeight();
|
||||
}
|
||||
|
||||
if (mActionView.isSplitActionBar()) {
|
||||
// If action bar is split, adjust bottom insets for it.
|
||||
if (stable) {
|
||||
bottomInset = mActionBarHeight;
|
||||
} else {
|
||||
bottomInset = mActionBarBottom.getMeasuredHeight();
|
||||
}
|
||||
}
|
||||
|
||||
// If the window has not requested system UI layout flags, we need to
|
||||
// make sure its content is not being covered by system UI... though it
|
||||
// will still be covered by the action bar if they have requested it to
|
||||
// overlay.
|
||||
mContentInsets.set(mBaseContentInsets);
|
||||
mInnerInsets.set(mBaseInnerInsets);
|
||||
if (!mOverlayMode && !stable) {
|
||||
mContentInsets.top += topInset;
|
||||
mContentInsets.bottom += bottomInset;
|
||||
} else {
|
||||
mInnerInsets.top += topInset;
|
||||
mInnerInsets.bottom += bottomInset;
|
||||
}
|
||||
applyInsets(mContent, mContentInsets, true, true, true, true);
|
||||
|
||||
if (!mLastInnerInsets.equals(mInnerInsets)) {
|
||||
// If the inner insets have changed, we need to dispatch this down to
|
||||
// the app's fitSystemWindows(). We do this before measuring the content
|
||||
// view to keep the same semantics as the normal fitSystemWindows() call.
|
||||
mLastInnerInsets.set(mInnerInsets);
|
||||
super.fitSystemWindows(mInnerInsets);
|
||||
}
|
||||
|
||||
measureChildWithMargins(mContent, widthMeasureSpec, 0, heightMeasureSpec, 0);
|
||||
lp = (LayoutParams) mContent.getLayoutParams();
|
||||
maxWidth = Math.max(maxWidth,
|
||||
mContent.getMeasuredWidth() + lp.leftMargin + lp.rightMargin);
|
||||
maxHeight = Math.max(maxHeight,
|
||||
mContent.getMeasuredHeight() + lp.topMargin + lp.bottomMargin);
|
||||
childState = combineMeasuredStates(childState, mContent.getMeasuredState());
|
||||
|
||||
// Account for padding too
|
||||
maxWidth += getPaddingLeft() + getPaddingRight();
|
||||
maxHeight += getPaddingTop() + getPaddingBottom();
|
||||
|
||||
// Check against our minimum height and width
|
||||
maxHeight = Math.max(maxHeight, getSuggestedMinimumHeight());
|
||||
maxWidth = Math.max(maxWidth, getSuggestedMinimumWidth());
|
||||
|
||||
setMeasuredDimension(resolveSizeAndState(maxWidth, widthMeasureSpec, childState),
|
||||
resolveSizeAndState(maxHeight, heightMeasureSpec,
|
||||
childState << MEASURED_HEIGHT_STATE_SHIFT));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
|
||||
final int count = getChildCount();
|
||||
|
||||
final int parentLeft = getPaddingLeft();
|
||||
final int parentRight = right - left - getPaddingRight();
|
||||
|
||||
final int parentTop = getPaddingTop();
|
||||
final int parentBottom = bottom - top - getPaddingBottom();
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
final View child = getChildAt(i);
|
||||
if (child.getVisibility() != GONE) {
|
||||
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
|
||||
|
||||
final int width = child.getMeasuredWidth();
|
||||
final int height = child.getMeasuredHeight();
|
||||
|
||||
int childLeft = parentLeft + lp.leftMargin;
|
||||
int childTop;
|
||||
if (child == mActionBarBottom) {
|
||||
childTop = parentBottom - height - lp.bottomMargin;
|
||||
} else {
|
||||
childTop = parentTop + lp.topMargin;
|
||||
}
|
||||
|
||||
child.layout(childLeft, childTop, childLeft + width, childTop + height);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void pullChildren() {
|
||||
if (mContent == null) {
|
||||
mContent = findViewById(com.android.internal.R.id.content);
|
||||
@@ -226,4 +346,23 @@ public class ActionBarOverlayLayout extends FrameLayout {
|
||||
mActionBarBottom = findViewById(com.android.internal.R.id.split_action_bar);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class LayoutParams extends MarginLayoutParams {
|
||||
public LayoutParams(Context c, AttributeSet attrs) {
|
||||
super(c, attrs);
|
||||
}
|
||||
|
||||
public LayoutParams(int width, int height) {
|
||||
super(width, height);
|
||||
}
|
||||
|
||||
public LayoutParams(ViewGroup.LayoutParams source) {
|
||||
super(source);
|
||||
}
|
||||
|
||||
public LayoutParams(ViewGroup.MarginLayoutParams source) {
|
||||
super(source);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,8 +29,7 @@ This is an optimized layout for a screen with the Action Bar enabled.
|
||||
android:layout_height="match_parent" />
|
||||
<LinearLayout android:id="@+id/top_action_bar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="top">
|
||||
android:layout_height="wrap_content">
|
||||
<com.android.internal.widget.ActionBarContainer android:id="@+id/action_bar_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
@@ -57,7 +56,6 @@ This is an optimized layout for a screen with the Action Bar enabled.
|
||||
<com.android.internal.widget.ActionBarContainer android:id="@+id/split_action_bar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom"
|
||||
style="?android:attr/actionBarSplitStyle"
|
||||
android:visibility="gone"
|
||||
android:gravity="center"/>
|
||||
|
||||
Reference in New Issue
Block a user