am 9c9aec72: Merge "Fix issue #8311263: Corrupted UI across all tabs in People app" into jb-mr2-dev

* commit '9c9aec721a78f23b4315ac920c26b109999a07f1':
  Fix issue #8311263: Corrupted UI across all tabs in People app
This commit is contained in:
Dianne Hackborn
2013-03-05 17:36:39 +00:00
committed by Android Git Automerger
2 changed files with 184 additions and 47 deletions

View File

@@ -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);
}
}
}

View File

@@ -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"/>