From b6c2624c8d9ee71d1c8d0aaf8082f92bb84b1418 Mon Sep 17 00:00:00 2001 From: Robert Carr Date: Thu, 22 Oct 2015 12:03:28 -0700 Subject: [PATCH] Add window setDecorView API. Add a Window API for setting a view which will be placed in the decoration area (next to the window control buttons). Change-Id: Ie106cbea653ff95fdba987a2a43506d394600612 --- api/current.txt | 2 + api/system-current.txt | 2 + core/java/android/view/Window.java | 21 +++++++++ .../android/internal/policy/PhoneWindow.java | 25 ++++++++++ .../internal/widget/NonClientDecorView.java | 46 +++++++------------ core/res/res/layout/non_client_decor_dark.xml | 5 +- .../res/res/layout/non_client_decor_light.xml | 5 +- core/res/res/values/symbols.xml | 1 + libs/hwui/renderthread/CanvasContext.cpp | 17 ++++--- 9 files changed, 83 insertions(+), 41 deletions(-) diff --git a/api/current.txt b/api/current.txt index e91244074522e..bee446b157eaf 100644 --- a/api/current.txt +++ b/api/current.txt @@ -37441,6 +37441,8 @@ package android.view { method public abstract void setContentView(int); method public abstract void setContentView(android.view.View); method public abstract void setContentView(android.view.View, android.view.ViewGroup.LayoutParams); + method public abstract void setDecorView(android.view.View); + method public abstract void setDecorView(int); method protected void setDefaultWindowFormat(int); method public void setDimAmount(float); method public void setElevation(float); diff --git a/api/system-current.txt b/api/system-current.txt index b996af313a07c..4648672dc5a4c 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -39738,6 +39738,8 @@ package android.view { method public abstract void setContentView(int); method public abstract void setContentView(android.view.View); method public abstract void setContentView(android.view.View, android.view.ViewGroup.LayoutParams); + method public abstract void setDecorView(android.view.View); + method public abstract void setDecorView(int); method protected void setDefaultWindowFormat(int); method public void setDimAmount(float); method public void setDisableWallpaperTouchEvents(boolean); diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java index d9ec866ffbabe..5d11c8b7d888e 100644 --- a/core/java/android/view/Window.java +++ b/core/java/android/view/Window.java @@ -1155,6 +1155,27 @@ public abstract class Window { */ public abstract void setContentView(View view); + /** + * Install a view in the decoration (title) area, to be shown when + * the window is in multi-window mode. This view will be placed + * next to the window controls. + * + * The view may be restored to defaults by passing null. + * + * @param view The desired view to display in window decorations. + */ + public abstract void setDecorView(View view); + + /** + * Convenience for + * {@link #setDecorView(View)} + * to set the custom window decoration from a layout resource. The layout will be inflated + * adding all top level views to the decoration + * + * @param layoutResID Resource ID to be inflated. + */ + public abstract void setDecorView(@LayoutRes int layoutResID); + /** * Set the screen content to an explicit view. This view is placed * directly into the screen's view hierarchy. It can itself be a complex diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java index afef7633bc69d..8a2621176f9ab 100644 --- a/core/java/com/android/internal/policy/PhoneWindow.java +++ b/core/java/com/android/internal/policy/PhoneWindow.java @@ -123,6 +123,7 @@ import android.view.animation.Animation; import android.view.animation.AnimationUtils; import android.view.animation.Interpolator; import android.widget.FrameLayout; +import android.widget.LinearLayout; import android.widget.ImageView; import android.widget.PopupWindow; import android.widget.ProgressBar; @@ -468,6 +469,30 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { } } + @Override + public void setDecorView(int layoutResID) { + View v = mLayoutInflater.inflate(layoutResID, null); + setDecorView(v); + } + + @Override + public void setDecorView(View view) { + if (mContentParent == null) { + installDecor(); + } + + LinearLayout clientDecorPlaceholder = + (LinearLayout) findViewById(R.id.client_decor_placeholder); + + if (clientDecorPlaceholder != null) { + clientDecorPlaceholder.removeAllViews(); + + if (view != null) { + clientDecorPlaceholder.addView(view); + } + } + } + @Override public void addContentView(View view, ViewGroup.LayoutParams params) { if (mContentParent == null) { diff --git a/core/java/com/android/internal/widget/NonClientDecorView.java b/core/java/com/android/internal/widget/NonClientDecorView.java index 5d502c9dcca02..be9be11f9da6f 100644 --- a/core/java/com/android/internal/widget/NonClientDecorView.java +++ b/core/java/com/android/internal/widget/NonClientDecorView.java @@ -428,8 +428,7 @@ public class NonClientDecorView extends LinearLayout // The render nodes for the multi threaded renderer. private ThreadedRenderer mRenderer; - private RenderNode mFrameNode; - private RenderNode mBackdropNode; + private RenderNode mFrameAndBackdropNode; private final Rect mOldTargetRect = new Rect(); private final Rect mNewTargetRect = new Rect(); @@ -450,13 +449,11 @@ public class NonClientDecorView extends LinearLayout setName("ResizeFrame"); mRenderer = renderer; - // Create the render nodes for our frame and backdrop which can be resized independently - // from the content. - mFrameNode = RenderNode.create("FrameNode", null); - mBackdropNode = RenderNode.create("BackdropNode", null); + // Create a render node for the content and frame backdrop + // which can be resized independently from the content. + mFrameAndBackdropNode = RenderNode.create("FrameAndBackdropNode", null); - mRenderer.addRenderNode(mFrameNode, false); - mRenderer.addRenderNode(mBackdropNode, true); + mRenderer.addRenderNode(mFrameAndBackdropNode, true); // Set the initial bounds and draw once so that we do not get a broken frame. mTargetRect.set(initialBounds); @@ -504,10 +501,9 @@ public class NonClientDecorView extends LinearLayout // Invalidate the current content bounds. mRenderer.setContentDrawBounds(0, 0, 0, 0); - // Remove the render nodes again + // Remove the render node again // (see comment above - better to do that only once). - mRenderer.removeRenderNode(mFrameNode); - mRenderer.removeRenderNode(mBackdropNode); + mRenderer.removeRenderNode(mFrameAndBackdropNode); mRenderer = null; @@ -575,7 +571,7 @@ public class NonClientDecorView extends LinearLayout mRenderer.setContentDrawBounds( mLastXOffset, - mLastYOffset + mLastCaptionHeight, + mLastYOffset, mLastXOffset + mLastContentWidth, mLastYOffset + mLastCaptionHeight + mLastContentHeight); // If this was the first call and changeWindowSizeLocked got already called prior @@ -623,30 +619,20 @@ public class NonClientDecorView extends LinearLayout final int width = newBounds.width(); final int height = newBounds.height(); - // Produce the draw calls. - // TODO(skuhne): Create a separate caption view which draws this. If the shadow should - // be resized while the window resizes, this hierarchy needs to have the elevation. - // That said - it is probably no good idea to draw the shadow every time since it costs - // a considerable time which we should rather spend for resizing the content and it does - // barely show while the entire screen is moving. - mFrameNode.setLeftTopRightBottom(left, top, left + width, top + mLastCaptionHeight); - DisplayListCanvas canvas = mFrameNode.start(width, height); + mFrameAndBackdropNode.setLeftTopRightBottom(left, top, left + width, top + height); + + // Draw the caption and content backdrops in to our render node. + DisplayListCanvas canvas = mFrameAndBackdropNode.start(width, height); mCaptionBackgroundDrawable.setBounds(0, 0, left + width, top + mLastCaptionHeight); mCaptionBackgroundDrawable.draw(canvas); - mFrameNode.end(canvas); - - mBackdropNode.setLeftTopRightBottom(left, top + mLastCaptionHeight, left + width, - top + height); // The backdrop: clear everything with the background. Clipping is done elsewhere. - canvas = mBackdropNode.start(width, height - mLastCaptionHeight); - mResizingBackgroundDrawable.setBounds(0, 0, left + width, top + height); + mResizingBackgroundDrawable.setBounds(0, mLastCaptionHeight, left + width, top + height); mResizingBackgroundDrawable.draw(canvas); - mBackdropNode.end(canvas); + mFrameAndBackdropNode.end(canvas); - // We need to render both rendered nodes explicitly. - mRenderer.drawRenderNode(mFrameNode); - mRenderer.drawRenderNode(mBackdropNode); + // We need to render the node explicitly + mRenderer.drawRenderNode(mFrameAndBackdropNode); reportDrawIfNeeded(); } diff --git a/core/res/res/layout/non_client_decor_dark.xml b/core/res/res/layout/non_client_decor_dark.xml index 112f4b7f74a90..40b8960a7ff96 100644 --- a/core/res/res/layout/non_client_decor_dark.xml +++ b/core/res/res/layout/non_client_decor_dark.xml @@ -29,10 +29,11 @@ android:background="@drawable/non_client_decor_title" android:focusable="false" android:descendantFocusability="blocksDescendants" > - + android:layout_weight="1"/>