diff --git a/api/current.txt b/api/current.txt index e17bf2865cb6a..17d349ac2f1c2 100644 --- a/api/current.txt +++ b/api/current.txt @@ -3499,6 +3499,7 @@ package android.app { method public android.view.ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback, int); method public void openContextMenu(android.view.View); method public void openOptionsMenu(); + method public void overlayWithDecorCaption(boolean); method public void overridePendingTransition(int, int); method public void postponeEnterTransition(); method public void recreate(); diff --git a/api/system-current.txt b/api/system-current.txt index d8b9b6f77313b..4d410625f328c 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -3602,6 +3602,7 @@ package android.app { method public android.view.ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback, int); method public void openContextMenu(android.view.View); method public void openOptionsMenu(); + method public void overlayWithDecorCaption(boolean); method public void overridePendingTransition(int, int); method public void postponeEnterTransition(); method public void recreate(); diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index 472d97fdb9eda..8bb0ff5a2781e 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -6617,6 +6617,17 @@ public class Activity extends ContextThemeWrapper } } + /** + * Set whether the caption should displayed directly on the content rather than push it down. + * + * This affects only freeform windows since they display the caption and only the main + * window of the activity. The caption is used to drag the window around and also shows + * maximize and close action buttons. + */ + public void overlayWithDecorCaption(boolean overlay) { + mWindow.setOverlayDecorCaption(overlay); + } + /** * Interface for informing a translucent {@link Activity} once all visible activities below it * have completed drawing. This is necessary only after an {@link Activity} has been made diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java index 8259372892333..3c4d45a244b93 100644 --- a/core/java/android/view/Window.java +++ b/core/java/android/view/Window.java @@ -276,6 +276,8 @@ public abstract class Window { private boolean mDestroyed; + private boolean mOverlayWithDecorCaption = false; + // The current window attributes. private final WindowManager.LayoutParams mWindowAttributes = new WindowManager.LayoutParams(); @@ -2044,4 +2046,18 @@ public abstract class Window { /** @hide */ public void setTheme(int resId) { } + + /** + * Whether the caption should be displayed directly on the content rather than push the content + * down. This affects only freeform windows since they display the caption. + * @hide + */ + public void setOverlayDecorCaption(boolean overlayCaption) { + mOverlayWithDecorCaption = overlayCaption; + } + + /** @hide */ + public boolean getOverlayDecorCaption() { + return mOverlayWithDecorCaption; + } } diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java index 4c221fc51cda3..27fe03cec97bc 100644 --- a/core/java/com/android/internal/policy/DecorView.java +++ b/core/java/com/android/internal/policy/DecorView.java @@ -1570,7 +1570,7 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT)); } mDecorCaptionView.addView(root, - new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT)); + new ViewGroup.MarginLayoutParams(MATCH_PARENT, MATCH_PARENT)); } else { addView(root, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT)); } @@ -1672,9 +1672,7 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind void clearContentView() { if (mDecorCaptionView != null) { - if (mDecorCaptionView.getChildCount() > 1) { - mDecorCaptionView.removeViewAt(1); - } + mDecorCaptionView.removeContentView(); } else { // This window doesn't have caption, so we need to just remove the // children of the decor view. diff --git a/core/java/com/android/internal/widget/DecorCaptionView.java b/core/java/com/android/internal/widget/DecorCaptionView.java index e22bd10b63603..16e8296167040 100644 --- a/core/java/com/android/internal/widget/DecorCaptionView.java +++ b/core/java/com/android/internal/widget/DecorCaptionView.java @@ -23,7 +23,6 @@ import android.os.RemoteException; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; -import android.widget.LinearLayout; import android.view.ViewGroup; import android.view.ViewOutlineProvider; import android.view.Window; @@ -50,7 +49,7 @@ import com.android.internal.policy.PhoneWindow; *
  • ..
  • * */ -public class DecorCaptionView extends LinearLayout +public class DecorCaptionView extends ViewGroup implements View.OnClickListener, View.OnTouchListener { private final static String TAG = "DecorCaptionView"; private PhoneWindow mOwner = null; @@ -62,6 +61,11 @@ public class DecorCaptionView extends LinearLayout // True when the left mouse button got released while dragging. private boolean mLeftMouseButtonReleased; + private boolean mOverlayWithAppContent = false; + + private View mCaption; + private View mContent; + public DecorCaptionView(Context context) { super(context); } @@ -74,9 +78,16 @@ public class DecorCaptionView extends LinearLayout super(context, attrs, defStyle); } + @Override + protected void onFinishInflate() { + super.onFinishInflate(); + mCaption = getChildAt(0); + } + public void setPhoneWindow(PhoneWindow owner, boolean show) { mOwner = owner; mShow = show; + mOverlayWithAppContent = owner.getOverlayDecorCaption(); updateCaptionVisibility(); // By changing the outline provider to BOUNDS, the window can remove its // background without removing the shadow. @@ -152,13 +163,61 @@ public class DecorCaptionView extends LinearLayout @Override public void addView(View child, int index, ViewGroup.LayoutParams params) { + if (!(params instanceof MarginLayoutParams)) { + throw new IllegalArgumentException( + "params " + params + " must subclass MarginLayoutParams"); + } // Make sure that we never get more then one client area in our view. if (index >= 2 || getChildCount() >= 2) { throw new IllegalStateException("DecorCaptionView can only handle 1 client view"); } - super.addView(child, index, params); + // To support the overlaying content in the caption, we need to put the content view as the + // first child to get the right Z-Ordering. + super.addView(child, 0, params); + mContent = child; } + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + final int captionHeight; + if (mCaption.getVisibility() != View.GONE) { + measureChildWithMargins(mCaption, widthMeasureSpec, 0, heightMeasureSpec, 0); + captionHeight = mCaption.getMeasuredHeight(); + } else { + captionHeight = 0; + } + if (mContent != null) { + if (mOverlayWithAppContent) { + measureChildWithMargins(mContent, widthMeasureSpec, 0, heightMeasureSpec, 0); + } else { + measureChildWithMargins(mContent, widthMeasureSpec, 0, heightMeasureSpec, + captionHeight); + } + } + + setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), + MeasureSpec.getSize(heightMeasureSpec)); + } + + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + final int captionHeight; + if (mCaption.getVisibility() != View.GONE) { + mCaption.layout(0, 0, mCaption.getMeasuredWidth(), mCaption.getMeasuredHeight()); + captionHeight = mCaption.getBottom() - mCaption.getTop(); + } else { + captionHeight = 0; + } + + if (mContent != null) { + if (mOverlayWithAppContent) { + mContent.layout(0, 0, mContent.getMeasuredWidth(), mContent.getMeasuredHeight()); + } else { + mContent.layout(0, captionHeight, mContent.getMeasuredWidth(), + captionHeight + mContent.getMeasuredHeight()); + } + } + } /** * Determine if the workspace is entirely covered by the window. * @return Returns true when the window is filling the entire screen/workspace. @@ -175,9 +234,8 @@ public class DecorCaptionView extends LinearLayout private void updateCaptionVisibility() { // Don't show the caption if the window has e.g. entered full screen. boolean invisible = isFillingScreen() || !mShow; - View caption = getChildAt(0); - caption.setVisibility(invisible ? GONE : VISIBLE); - caption.setOnTouchListener(this); + mCaption.setVisibility(invisible ? GONE : VISIBLE); + mCaption.setOnTouchListener(this); } /** @@ -199,7 +257,38 @@ public class DecorCaptionView extends LinearLayout } public int getCaptionHeight() { - final View caption = getChildAt(0); - return (caption != null) ? caption.getHeight() : 0; + return (mCaption != null) ? mCaption.getHeight() : 0; + } + + public void removeContentView() { + if (mContent != null) { + removeView(mContent); + mContent = null; + } + } + + public View getCaption() { + return mCaption; + } + + @Override + public LayoutParams generateLayoutParams(AttributeSet attrs) { + return new MarginLayoutParams(getContext(), attrs); + } + + @Override + protected LayoutParams generateDefaultLayoutParams() { + return new MarginLayoutParams(MarginLayoutParams.MATCH_PARENT, + MarginLayoutParams.MATCH_PARENT); + } + + @Override + protected LayoutParams generateLayoutParams(LayoutParams p) { + return new MarginLayoutParams(p); + } + + @Override + protected boolean checkLayoutParams(ViewGroup.LayoutParams p) { + return p instanceof MarginLayoutParams; } } diff --git a/core/res/res/layout/decor_caption_dark.xml b/core/res/res/layout/decor_caption_dark.xml index 86d68af291e43..273264d3d85f8 100644 --- a/core/res/res/layout/decor_caption_dark.xml +++ b/core/res/res/layout/decor_caption_dark.xml @@ -23,6 +23,7 @@ android:layout_height="match_parent" android:descendantFocusability="beforeDescendants" >