Loading libs/WindowManager/Shell/res/values/dimen.xml +17 −0 Original line number Diff line number Diff line Loading @@ -321,4 +321,21 @@ <!-- The smaller size of the dismiss target (shrinks when something is in the target). --> <dimen name="floating_dismiss_circle_small">120dp</dimen> <!-- The thickness of shadows of a window that has focus in DIP. --> <dimen name="freeform_decor_shadow_focused_thickness">20dp</dimen> <!-- The thickness of shadows of a window that doesn't have focus in DIP. --> <dimen name="freeform_decor_shadow_unfocused_thickness">5dp</dimen> <!-- Height of button (32dp) + 2 * margin (5dp each). --> <dimen name="freeform_decor_caption_height">42dp</dimen> <!-- Width of buttons (64dp) + handle (128dp) + padding (24dp total). --> <dimen name="freeform_decor_caption_width">216dp</dimen> <dimen name="freeform_resize_handle">30dp</dimen> <dimen name="freeform_resize_corner">44dp</dimen> </resources> libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java +24 −26 Original line number Diff line number Diff line Loading @@ -21,7 +21,6 @@ import android.app.WindowConfiguration; import android.content.Context; import android.content.res.ColorStateList; import android.graphics.Color; import android.graphics.Rect; import android.graphics.drawable.VectorDrawable; import android.os.Handler; import android.view.Choreographer; Loading @@ -43,22 +42,6 @@ import com.android.wm.shell.desktopmode.DesktopModeStatus; * The shadow's thickness is 20dp when the window is in focus and 5dp when the window isn't. */ public class CaptionWindowDecoration extends WindowDecoration<WindowDecorLinearLayout> { // The thickness of shadows of a window that has focus in DIP. private static final int DECOR_SHADOW_FOCUSED_THICKNESS_IN_DIP = 20; // The thickness of shadows of a window that doesn't have focus in DIP. private static final int DECOR_SHADOW_UNFOCUSED_THICKNESS_IN_DIP = 5; // Height of button (32dp) + 2 * margin (5dp each) private static final int DECOR_CAPTION_HEIGHT_IN_DIP = 42; // Width of buttons (64dp) + handle (128dp) + padding (24dp total) private static final int DECOR_CAPTION_WIDTH_IN_DIP = 216; private static final int RESIZE_HANDLE_IN_DIP = 30; private static final int RESIZE_CORNER_IN_DIP = 44; private static final Rect EMPTY_OUTSET = new Rect(); private static final Rect RESIZE_HANDLE_OUTSET = new Rect( RESIZE_HANDLE_IN_DIP, RESIZE_HANDLE_IN_DIP, RESIZE_HANDLE_IN_DIP, RESIZE_HANDLE_IN_DIP); private final Handler mHandler; private final Choreographer mChoreographer; private final SyncTransactionQueue mSyncQueue; Loading @@ -69,6 +52,7 @@ public class CaptionWindowDecoration extends WindowDecoration<WindowDecorLinearL private DragResizeInputListener mDragResizeListener; private RelayoutParams mRelayoutParams = new RelayoutParams(); private final WindowDecoration.RelayoutResult<WindowDecorLinearLayout> mResult = new WindowDecoration.RelayoutResult<>(); Loading Loading @@ -114,19 +98,31 @@ public class CaptionWindowDecoration extends WindowDecoration<WindowDecorLinearL void relayout(ActivityManager.RunningTaskInfo taskInfo, SurfaceControl.Transaction startT, SurfaceControl.Transaction finishT) { final int shadowRadiusDp = taskInfo.isFocused ? DECOR_SHADOW_FOCUSED_THICKNESS_IN_DIP : DECOR_SHADOW_UNFOCUSED_THICKNESS_IN_DIP; final int shadowRadiusID = taskInfo.isFocused ? R.dimen.freeform_decor_shadow_focused_thickness : R.dimen.freeform_decor_shadow_unfocused_thickness; final boolean isFreeform = mTaskInfo.configuration.windowConfiguration.getWindowingMode() == WindowConfiguration.WINDOWING_MODE_FREEFORM; final boolean isDragResizeable = isFreeform && mTaskInfo.isResizeable; final Rect outset = isDragResizeable ? RESIZE_HANDLE_OUTSET : EMPTY_OUTSET; WindowDecorLinearLayout oldRootView = mResult.mRootView; final SurfaceControl oldDecorationSurface = mDecorationContainerSurface; final WindowContainerTransaction wct = new WindowContainerTransaction(); relayout(taskInfo, R.layout.caption_window_decoration, oldRootView, DECOR_CAPTION_HEIGHT_IN_DIP, DECOR_CAPTION_WIDTH_IN_DIP, outset, shadowRadiusDp, startT, finishT, wct, mResult); int outsetLeftId = R.dimen.freeform_resize_handle; int outsetTopId = R.dimen.freeform_resize_handle; int outsetRightId = R.dimen.freeform_resize_handle; int outsetBottomId = R.dimen.freeform_resize_handle; mRelayoutParams.mRunningTaskInfo = taskInfo; mRelayoutParams.mLayoutResId = R.layout.caption_window_decoration; mRelayoutParams.mCaptionHeightId = R.dimen.freeform_decor_caption_height; mRelayoutParams.mCaptionWidthId = R.dimen.freeform_decor_caption_width; mRelayoutParams.mShadowRadiusId = shadowRadiusID; if (isDragResizeable) { mRelayoutParams.setOutsets(outsetLeftId, outsetTopId, outsetRightId, outsetBottomId); } relayout(mRelayoutParams, startT, finishT, wct, oldRootView, mResult); mTaskOrganizer.applyTransaction(wct); Loading Loading @@ -167,10 +163,12 @@ public class CaptionWindowDecoration extends WindowDecoration<WindowDecorLinearL } int touchSlop = ViewConfiguration.get(mResult.mRootView.getContext()).getScaledTouchSlop(); int resize_handle = mResult.mRootView.getResources() .getDimensionPixelSize(R.dimen.freeform_resize_handle); int resize_corner = mResult.mRootView.getResources() .getDimensionPixelSize(R.dimen.freeform_resize_corner); mDragResizeListener.setGeometry( mResult.mWidth, mResult.mHeight, (int) (mResult.mDensity * RESIZE_HANDLE_IN_DIP), (int) (mResult.mDensity * RESIZE_CORNER_IN_DIP), touchSlop); mResult.mWidth, mResult.mHeight, resize_handle, resize_corner, touchSlop); } /** Loading libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java +67 −27 Original line number Diff line number Diff line Loading @@ -19,11 +19,11 @@ package com.android.wm.shell.windowdecor; import android.app.ActivityManager.RunningTaskInfo; import android.content.Context; import android.content.res.Configuration; import android.content.res.Resources; import android.graphics.Color; import android.graphics.PixelFormat; import android.graphics.Point; import android.graphics.Rect; import android.util.DisplayMetrics; import android.view.Display; import android.view.InsetsState; import android.view.LayoutInflater; Loading Loading @@ -142,15 +142,14 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> */ abstract void relayout(RunningTaskInfo taskInfo); void relayout(RunningTaskInfo taskInfo, int layoutResId, T rootView, float captionHeightDp, float captionWidthDp, Rect outsetsDp, float shadowRadiusDp, SurfaceControl.Transaction startT, SurfaceControl.Transaction finishT, WindowContainerTransaction wct, RelayoutResult<T> outResult) { void relayout(RelayoutParams params, SurfaceControl.Transaction startT, SurfaceControl.Transaction finishT, WindowContainerTransaction wct, T rootView, RelayoutResult<T> outResult) { outResult.reset(); final Configuration oldTaskConfig = mTaskInfo.getConfiguration(); if (taskInfo != null) { mTaskInfo = taskInfo; if (params.mRunningTaskInfo != null) { mTaskInfo = params.mRunningTaskInfo; } if (!mTaskInfo.isVisible) { Loading @@ -159,7 +158,7 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> return; } if (rootView == null && layoutResId == 0) { if (rootView == null && params.mLayoutResId == 0) { throw new IllegalArgumentException("layoutResId and rootView can't both be invalid."); } Loading @@ -176,15 +175,15 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> return; } mDecorWindowContext = mContext.createConfigurationContext(taskConfig); if (layoutResId != 0) { outResult.mRootView = (T) LayoutInflater.from(mDecorWindowContext).inflate(layoutResId, null); if (params.mLayoutResId != 0) { outResult.mRootView = (T) LayoutInflater.from(mDecorWindowContext) .inflate(params.mLayoutResId, null); } } if (outResult.mRootView == null) { outResult.mRootView = (T) LayoutInflater.from(mDecorWindowContext).inflate(layoutResId, null); outResult.mRootView = (T) LayoutInflater.from(mDecorWindowContext) .inflate(params.mLayoutResId , null); } // DecorationContainerSurface Loading @@ -200,18 +199,18 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> } final Rect taskBounds = taskConfig.windowConfiguration.getBounds(); outResult.mDensity = taskConfig.densityDpi * DisplayMetrics.DENSITY_DEFAULT_SCALE; final int decorContainerOffsetX = -(int) (outsetsDp.left * outResult.mDensity); final int decorContainerOffsetY = -(int) (outsetsDp.top * outResult.mDensity); final int decorContainerOffsetX = -loadResource(params.mOutsetLeftId); final int decorContainerOffsetY = -loadResource(params.mOutsetTopId); outResult.mWidth = taskBounds.width() + (int) (outsetsDp.right * outResult.mDensity) + loadResource(params.mOutsetRightId) - decorContainerOffsetX; outResult.mHeight = taskBounds.height() + (int) (outsetsDp.bottom * outResult.mDensity) + loadResource(params.mOutsetBottomId) - decorContainerOffsetY; startT.setPosition( mDecorationContainerSurface, decorContainerOffsetX, decorContainerOffsetY) .setWindowCrop(mDecorationContainerSurface, outResult.mWidth, outResult.mHeight) .setWindowCrop(mDecorationContainerSurface, outResult.mWidth, outResult.mHeight) // TODO(b/244455401): Change the z-order when it's better organized .setLayer(mDecorationContainerSurface, mTaskInfo.numActivities + 1) .show(mDecorationContainerSurface); Loading @@ -226,12 +225,13 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> .build(); } float shadowRadius = outResult.mDensity * shadowRadiusDp; float shadowRadius = loadResource(params.mShadowRadiusId); int backgroundColorInt = mTaskInfo.taskDescription.getBackgroundColor(); mTmpColor[0] = (float) Color.red(backgroundColorInt) / 255.f; mTmpColor[1] = (float) Color.green(backgroundColorInt) / 255.f; mTmpColor[2] = (float) Color.blue(backgroundColorInt) / 255.f; startT.setWindowCrop(mTaskBackgroundSurface, taskBounds.width(), taskBounds.height()) startT.setWindowCrop(mTaskBackgroundSurface, taskBounds.width(), taskBounds.height()) .setShadowRadius(mTaskBackgroundSurface, shadowRadius) .setColor(mTaskBackgroundSurface, mTmpColor) // TODO(b/244455401): Change the z-order when it's better organized Loading @@ -248,8 +248,8 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> .build(); } final int captionHeight = (int) Math.ceil(captionHeightDp * outResult.mDensity); final int captionWidth = (int) Math.ceil(captionWidthDp * outResult.mDensity); final int captionHeight = loadResource(params.mCaptionHeightId); final int captionWidth = loadResource(params.mCaptionWidthId); //Prevent caption from going offscreen if task is too high up final int captionYPos = taskBounds.top <= captionHeight / 2 ? 0 : captionHeight / 2; Loading Loading @@ -289,8 +289,10 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> // Caption insets mCaptionInsetsRect.set(taskBounds); mCaptionInsetsRect.bottom = mCaptionInsetsRect.top + captionHeight - captionYPos; wct.addRectInsetsProvider(mTaskInfo.token, mCaptionInsetsRect, CAPTION_INSETS_TYPES); mCaptionInsetsRect.bottom = mCaptionInsetsRect.top + captionHeight - captionYPos; wct.addRectInsetsProvider(mTaskInfo.token, mCaptionInsetsRect, CAPTION_INSETS_TYPES); } else { startT.hide(mCaptionContainerSurface); } Loading @@ -307,6 +309,13 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> .setCrop(mTaskSurface, mTaskSurfaceCrop); } private int loadResource(int resourceId) { if (resourceId == Resources.ID_NULL) { return 0; } return mDecorWindowContext.getResources().getDimensionPixelSize(resourceId); } /** * Obtains the {@link Display} instance for the display ID in {@link #mTaskInfo} if it exists or * registers {@link #mOnDisplaysChangedListener} if it doesn't. Loading Loading @@ -368,13 +377,11 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> static class RelayoutResult<T extends View & TaskFocusStateConsumer> { int mWidth; int mHeight; float mDensity; T mRootView; void reset() { mWidth = 0; mHeight = 0; mDensity = 0; mRootView = null; } } Loading @@ -395,4 +402,37 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> return new SurfaceControlViewHost(c, d, wmm); } } static class RelayoutParams{ RunningTaskInfo mRunningTaskInfo; int mLayoutResId; int mCaptionHeightId; int mCaptionWidthId; int mShadowRadiusId; int mOutsetTopId; int mOutsetBottomId; int mOutsetLeftId; int mOutsetRightId; void setOutsets(int leftId, int topId, int rightId, int bottomId) { mOutsetLeftId = leftId; mOutsetTopId = topId; mOutsetRightId = rightId; mOutsetBottomId = bottomId; } void reset() { mLayoutResId = Resources.ID_NULL; mCaptionHeightId = Resources.ID_NULL; mCaptionWidthId = Resources.ID_NULL; mShadowRadiusId = Resources.ID_NULL; mOutsetTopId = Resources.ID_NULL; mOutsetBottomId = Resources.ID_NULL; mOutsetLeftId = Resources.ID_NULL; mOutsetRightId = Resources.ID_NULL; } } } No newline at end of file libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java +34 −21 Original line number Diff line number Diff line Loading @@ -51,6 +51,7 @@ import android.window.WindowContainerTransaction; import androidx.test.filters.SmallTest; import com.android.wm.shell.R; import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.ShellTestCase; import com.android.wm.shell.TestRunningTaskInfoBuilder; Loading @@ -76,13 +77,9 @@ import java.util.function.Supplier; @SmallTest @RunWith(AndroidTestingRunner.class) public class WindowDecorationTests extends ShellTestCase { private static final int CAPTION_HEIGHT_DP = 32; private static final int CAPTION_WIDTH_DP = 216; private static final int SHADOW_RADIUS_DP = 5; private static final Rect TASK_BOUNDS = new Rect(100, 300, 400, 400); private static final Point TASK_POSITION_IN_PARENT = new Point(40, 60); private final Rect mOutsetsDp = new Rect(); private final WindowDecoration.RelayoutResult<TestView> mRelayoutResult = new WindowDecoration.RelayoutResult<>(); Loading @@ -104,6 +101,7 @@ public class WindowDecorationTests extends ShellTestCase { private final List<SurfaceControl.Builder> mMockSurfaceControlBuilders = new ArrayList<>(); private SurfaceControl.Transaction mMockSurfaceControlStartT; private SurfaceControl.Transaction mMockSurfaceControlFinishT; private WindowDecoration.RelayoutParams mRelayoutParams = new WindowDecoration.RelayoutParams(); @Before public void setUp() { Loading Loading @@ -147,7 +145,8 @@ public class WindowDecorationTests extends ShellTestCase { // Density is 2. Outsets are (20, 40, 60, 80) px. Shadow radius is 10px. Caption height is // 64px. taskInfo.configuration.densityDpi = DisplayMetrics.DENSITY_DEFAULT * 2; mOutsetsDp.set(10, 20, 30, 40); mRelayoutParams.setOutsets(R.dimen.freeform_resize_handle, R.dimen.freeform_resize_handle, R.dimen.freeform_resize_handle, R.dimen.freeform_resize_handle); final SurfaceControl taskSurface = mock(SurfaceControl.class); final TestWindowDecoration windowDecor = createWindowDecoration(taskInfo, taskSurface); Loading Loading @@ -197,8 +196,13 @@ public class WindowDecorationTests extends ShellTestCase { // Density is 2. Outsets are (20, 40, 60, 80) px. Shadow radius is 10px. Caption height is // 64px. taskInfo.configuration.densityDpi = DisplayMetrics.DENSITY_DEFAULT * 2; mOutsetsDp.set(10, 20, 30, 40); // int outsetLeftId = R.dimen.split_divider_bar_width; // int outsetTopId = R.dimen.gestures_onehanded_drag_threshold; // int outsetRightId = R.dimen.freeform_resize_handle; // int outsetBottomId = R.dimen.bubble_dismiss_target_padding_x; // mRelayoutParams.setOutsets(outsetLeftId, outsetTopId, outsetRightId, outsetBottomId); mRelayoutParams.setOutsets(R.dimen.freeform_resize_handle, R.dimen.freeform_resize_handle, R.dimen.freeform_resize_handle, R.dimen.freeform_resize_handle); final SurfaceControl taskSurface = mock(SurfaceControl.class); final TestWindowDecoration windowDecor = createWindowDecoration(taskInfo, taskSurface); Loading @@ -207,8 +211,8 @@ public class WindowDecorationTests extends ShellTestCase { verify(decorContainerSurfaceBuilder).setParent(taskSurface); verify(decorContainerSurfaceBuilder).setContainerLayer(); verify(mMockSurfaceControlStartT).setTrustedOverlay(decorContainerSurface, true); verify(mMockSurfaceControlStartT).setPosition(decorContainerSurface, -20, -40); verify(mMockSurfaceControlStartT).setWindowCrop(decorContainerSurface, 380, 220); verify(mMockSurfaceControlStartT).setPosition(decorContainerSurface, -60, -60); verify(mMockSurfaceControlStartT).setWindowCrop(decorContainerSurface, 420, 220); verify(taskBackgroundSurfaceBuilder).setParent(taskSurface); verify(taskBackgroundSurfaceBuilder).setEffectLayer(); Loading @@ -221,34 +225,36 @@ public class WindowDecorationTests extends ShellTestCase { verify(captionContainerSurfaceBuilder).setParent(decorContainerSurface); verify(captionContainerSurfaceBuilder).setContainerLayer(); verify(mMockSurfaceControlStartT).setPosition(captionContainerSurface, -46, 8); verify(mMockSurfaceControlStartT).setWindowCrop(captionContainerSurface, 300, 64); verify(mMockSurfaceControlStartT).setPosition(captionContainerSurface, -6, -156); verify(mMockSurfaceControlStartT).setWindowCrop(captionContainerSurface, 300, 432); verify(mMockSurfaceControlStartT).show(captionContainerSurface); verify(mMockSurfaceControlViewHostFactory).create(any(), eq(defaultDisplay), any()); verify(mMockSurfaceControlViewHost) .setView(same(mMockView), argThat(lp -> lp.height == 64 && lp.width == 300 argThat(lp -> lp.height == 432 && lp.width == 432 && (lp.flags & LayoutParams.FLAG_NOT_FOCUSABLE) != 0)); if (ViewRootImpl.CAPTION_ON_SHELL) { verify(mMockView).setTaskFocusState(true); verify(mMockWindowContainerTransaction) .addRectInsetsProvider(taskInfo.token, new Rect(100, 300, 400, 364), new Rect(100, 300, 400, 516), new int[] { InsetsState.ITYPE_CAPTION_BAR }); } verify(mMockSurfaceControlFinishT) .setPosition(taskSurface, TASK_POSITION_IN_PARENT.x, TASK_POSITION_IN_PARENT.y); verify(mMockSurfaceControlFinishT) .setCrop(taskSurface, new Rect(-20, -40, 360, 180)); .setCrop(taskSurface, new Rect(-60, -60, 360, 160)); verify(mMockSurfaceControlStartT) .show(taskSurface); assertEquals(380, mRelayoutResult.mWidth); assertEquals(420, mRelayoutResult.mWidth); assertEquals(220, mRelayoutResult.mHeight); assertEquals(2, mRelayoutResult.mDensity, 0.f); } @Test Loading Loading @@ -287,7 +293,8 @@ public class WindowDecorationTests extends ShellTestCase { // Density is 2. Outsets are (20, 40, 60, 80) px. Shadow radius is 10px. Caption height is // 64px. taskInfo.configuration.densityDpi = DisplayMetrics.DENSITY_DEFAULT * 2; mOutsetsDp.set(10, 20, 30, 40); mRelayoutParams.setOutsets(R.dimen.freeform_resize_handle, R.dimen.freeform_resize_handle, R.dimen.freeform_resize_handle, R.dimen.freeform_resize_handle); final SurfaceControl taskSurface = mock(SurfaceControl.class); final TestWindowDecoration windowDecor = createWindowDecoration(taskInfo, taskSurface); Loading Loading @@ -410,9 +417,15 @@ public class WindowDecorationTests extends ShellTestCase { @Override void relayout(ActivityManager.RunningTaskInfo taskInfo) { relayout(null /* taskInfo */, 0 /* layoutResId */, mMockView, CAPTION_HEIGHT_DP, CAPTION_WIDTH_DP, mOutsetsDp, SHADOW_RADIUS_DP, mMockSurfaceControlStartT, mMockSurfaceControlFinishT, mMockWindowContainerTransaction, mRelayoutResult); mRelayoutParams.mLayoutResId = 0; mRelayoutParams.mCaptionHeightId = R.dimen.freeform_decor_caption_width; mRelayoutParams.mCaptionWidthId = R.dimen.freeform_decor_caption_width; mRelayoutParams.mShadowRadiusId = R.dimen.freeform_decor_shadow_unfocused_thickness; relayout(mRelayoutParams, mMockSurfaceControlStartT, mMockSurfaceControlFinishT, mMockWindowContainerTransaction, mMockView, mRelayoutResult); } } } Loading
libs/WindowManager/Shell/res/values/dimen.xml +17 −0 Original line number Diff line number Diff line Loading @@ -321,4 +321,21 @@ <!-- The smaller size of the dismiss target (shrinks when something is in the target). --> <dimen name="floating_dismiss_circle_small">120dp</dimen> <!-- The thickness of shadows of a window that has focus in DIP. --> <dimen name="freeform_decor_shadow_focused_thickness">20dp</dimen> <!-- The thickness of shadows of a window that doesn't have focus in DIP. --> <dimen name="freeform_decor_shadow_unfocused_thickness">5dp</dimen> <!-- Height of button (32dp) + 2 * margin (5dp each). --> <dimen name="freeform_decor_caption_height">42dp</dimen> <!-- Width of buttons (64dp) + handle (128dp) + padding (24dp total). --> <dimen name="freeform_decor_caption_width">216dp</dimen> <dimen name="freeform_resize_handle">30dp</dimen> <dimen name="freeform_resize_corner">44dp</dimen> </resources>
libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java +24 −26 Original line number Diff line number Diff line Loading @@ -21,7 +21,6 @@ import android.app.WindowConfiguration; import android.content.Context; import android.content.res.ColorStateList; import android.graphics.Color; import android.graphics.Rect; import android.graphics.drawable.VectorDrawable; import android.os.Handler; import android.view.Choreographer; Loading @@ -43,22 +42,6 @@ import com.android.wm.shell.desktopmode.DesktopModeStatus; * The shadow's thickness is 20dp when the window is in focus and 5dp when the window isn't. */ public class CaptionWindowDecoration extends WindowDecoration<WindowDecorLinearLayout> { // The thickness of shadows of a window that has focus in DIP. private static final int DECOR_SHADOW_FOCUSED_THICKNESS_IN_DIP = 20; // The thickness of shadows of a window that doesn't have focus in DIP. private static final int DECOR_SHADOW_UNFOCUSED_THICKNESS_IN_DIP = 5; // Height of button (32dp) + 2 * margin (5dp each) private static final int DECOR_CAPTION_HEIGHT_IN_DIP = 42; // Width of buttons (64dp) + handle (128dp) + padding (24dp total) private static final int DECOR_CAPTION_WIDTH_IN_DIP = 216; private static final int RESIZE_HANDLE_IN_DIP = 30; private static final int RESIZE_CORNER_IN_DIP = 44; private static final Rect EMPTY_OUTSET = new Rect(); private static final Rect RESIZE_HANDLE_OUTSET = new Rect( RESIZE_HANDLE_IN_DIP, RESIZE_HANDLE_IN_DIP, RESIZE_HANDLE_IN_DIP, RESIZE_HANDLE_IN_DIP); private final Handler mHandler; private final Choreographer mChoreographer; private final SyncTransactionQueue mSyncQueue; Loading @@ -69,6 +52,7 @@ public class CaptionWindowDecoration extends WindowDecoration<WindowDecorLinearL private DragResizeInputListener mDragResizeListener; private RelayoutParams mRelayoutParams = new RelayoutParams(); private final WindowDecoration.RelayoutResult<WindowDecorLinearLayout> mResult = new WindowDecoration.RelayoutResult<>(); Loading Loading @@ -114,19 +98,31 @@ public class CaptionWindowDecoration extends WindowDecoration<WindowDecorLinearL void relayout(ActivityManager.RunningTaskInfo taskInfo, SurfaceControl.Transaction startT, SurfaceControl.Transaction finishT) { final int shadowRadiusDp = taskInfo.isFocused ? DECOR_SHADOW_FOCUSED_THICKNESS_IN_DIP : DECOR_SHADOW_UNFOCUSED_THICKNESS_IN_DIP; final int shadowRadiusID = taskInfo.isFocused ? R.dimen.freeform_decor_shadow_focused_thickness : R.dimen.freeform_decor_shadow_unfocused_thickness; final boolean isFreeform = mTaskInfo.configuration.windowConfiguration.getWindowingMode() == WindowConfiguration.WINDOWING_MODE_FREEFORM; final boolean isDragResizeable = isFreeform && mTaskInfo.isResizeable; final Rect outset = isDragResizeable ? RESIZE_HANDLE_OUTSET : EMPTY_OUTSET; WindowDecorLinearLayout oldRootView = mResult.mRootView; final SurfaceControl oldDecorationSurface = mDecorationContainerSurface; final WindowContainerTransaction wct = new WindowContainerTransaction(); relayout(taskInfo, R.layout.caption_window_decoration, oldRootView, DECOR_CAPTION_HEIGHT_IN_DIP, DECOR_CAPTION_WIDTH_IN_DIP, outset, shadowRadiusDp, startT, finishT, wct, mResult); int outsetLeftId = R.dimen.freeform_resize_handle; int outsetTopId = R.dimen.freeform_resize_handle; int outsetRightId = R.dimen.freeform_resize_handle; int outsetBottomId = R.dimen.freeform_resize_handle; mRelayoutParams.mRunningTaskInfo = taskInfo; mRelayoutParams.mLayoutResId = R.layout.caption_window_decoration; mRelayoutParams.mCaptionHeightId = R.dimen.freeform_decor_caption_height; mRelayoutParams.mCaptionWidthId = R.dimen.freeform_decor_caption_width; mRelayoutParams.mShadowRadiusId = shadowRadiusID; if (isDragResizeable) { mRelayoutParams.setOutsets(outsetLeftId, outsetTopId, outsetRightId, outsetBottomId); } relayout(mRelayoutParams, startT, finishT, wct, oldRootView, mResult); mTaskOrganizer.applyTransaction(wct); Loading Loading @@ -167,10 +163,12 @@ public class CaptionWindowDecoration extends WindowDecoration<WindowDecorLinearL } int touchSlop = ViewConfiguration.get(mResult.mRootView.getContext()).getScaledTouchSlop(); int resize_handle = mResult.mRootView.getResources() .getDimensionPixelSize(R.dimen.freeform_resize_handle); int resize_corner = mResult.mRootView.getResources() .getDimensionPixelSize(R.dimen.freeform_resize_corner); mDragResizeListener.setGeometry( mResult.mWidth, mResult.mHeight, (int) (mResult.mDensity * RESIZE_HANDLE_IN_DIP), (int) (mResult.mDensity * RESIZE_CORNER_IN_DIP), touchSlop); mResult.mWidth, mResult.mHeight, resize_handle, resize_corner, touchSlop); } /** Loading
libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java +67 −27 Original line number Diff line number Diff line Loading @@ -19,11 +19,11 @@ package com.android.wm.shell.windowdecor; import android.app.ActivityManager.RunningTaskInfo; import android.content.Context; import android.content.res.Configuration; import android.content.res.Resources; import android.graphics.Color; import android.graphics.PixelFormat; import android.graphics.Point; import android.graphics.Rect; import android.util.DisplayMetrics; import android.view.Display; import android.view.InsetsState; import android.view.LayoutInflater; Loading Loading @@ -142,15 +142,14 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> */ abstract void relayout(RunningTaskInfo taskInfo); void relayout(RunningTaskInfo taskInfo, int layoutResId, T rootView, float captionHeightDp, float captionWidthDp, Rect outsetsDp, float shadowRadiusDp, SurfaceControl.Transaction startT, SurfaceControl.Transaction finishT, WindowContainerTransaction wct, RelayoutResult<T> outResult) { void relayout(RelayoutParams params, SurfaceControl.Transaction startT, SurfaceControl.Transaction finishT, WindowContainerTransaction wct, T rootView, RelayoutResult<T> outResult) { outResult.reset(); final Configuration oldTaskConfig = mTaskInfo.getConfiguration(); if (taskInfo != null) { mTaskInfo = taskInfo; if (params.mRunningTaskInfo != null) { mTaskInfo = params.mRunningTaskInfo; } if (!mTaskInfo.isVisible) { Loading @@ -159,7 +158,7 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> return; } if (rootView == null && layoutResId == 0) { if (rootView == null && params.mLayoutResId == 0) { throw new IllegalArgumentException("layoutResId and rootView can't both be invalid."); } Loading @@ -176,15 +175,15 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> return; } mDecorWindowContext = mContext.createConfigurationContext(taskConfig); if (layoutResId != 0) { outResult.mRootView = (T) LayoutInflater.from(mDecorWindowContext).inflate(layoutResId, null); if (params.mLayoutResId != 0) { outResult.mRootView = (T) LayoutInflater.from(mDecorWindowContext) .inflate(params.mLayoutResId, null); } } if (outResult.mRootView == null) { outResult.mRootView = (T) LayoutInflater.from(mDecorWindowContext).inflate(layoutResId, null); outResult.mRootView = (T) LayoutInflater.from(mDecorWindowContext) .inflate(params.mLayoutResId , null); } // DecorationContainerSurface Loading @@ -200,18 +199,18 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> } final Rect taskBounds = taskConfig.windowConfiguration.getBounds(); outResult.mDensity = taskConfig.densityDpi * DisplayMetrics.DENSITY_DEFAULT_SCALE; final int decorContainerOffsetX = -(int) (outsetsDp.left * outResult.mDensity); final int decorContainerOffsetY = -(int) (outsetsDp.top * outResult.mDensity); final int decorContainerOffsetX = -loadResource(params.mOutsetLeftId); final int decorContainerOffsetY = -loadResource(params.mOutsetTopId); outResult.mWidth = taskBounds.width() + (int) (outsetsDp.right * outResult.mDensity) + loadResource(params.mOutsetRightId) - decorContainerOffsetX; outResult.mHeight = taskBounds.height() + (int) (outsetsDp.bottom * outResult.mDensity) + loadResource(params.mOutsetBottomId) - decorContainerOffsetY; startT.setPosition( mDecorationContainerSurface, decorContainerOffsetX, decorContainerOffsetY) .setWindowCrop(mDecorationContainerSurface, outResult.mWidth, outResult.mHeight) .setWindowCrop(mDecorationContainerSurface, outResult.mWidth, outResult.mHeight) // TODO(b/244455401): Change the z-order when it's better organized .setLayer(mDecorationContainerSurface, mTaskInfo.numActivities + 1) .show(mDecorationContainerSurface); Loading @@ -226,12 +225,13 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> .build(); } float shadowRadius = outResult.mDensity * shadowRadiusDp; float shadowRadius = loadResource(params.mShadowRadiusId); int backgroundColorInt = mTaskInfo.taskDescription.getBackgroundColor(); mTmpColor[0] = (float) Color.red(backgroundColorInt) / 255.f; mTmpColor[1] = (float) Color.green(backgroundColorInt) / 255.f; mTmpColor[2] = (float) Color.blue(backgroundColorInt) / 255.f; startT.setWindowCrop(mTaskBackgroundSurface, taskBounds.width(), taskBounds.height()) startT.setWindowCrop(mTaskBackgroundSurface, taskBounds.width(), taskBounds.height()) .setShadowRadius(mTaskBackgroundSurface, shadowRadius) .setColor(mTaskBackgroundSurface, mTmpColor) // TODO(b/244455401): Change the z-order when it's better organized Loading @@ -248,8 +248,8 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> .build(); } final int captionHeight = (int) Math.ceil(captionHeightDp * outResult.mDensity); final int captionWidth = (int) Math.ceil(captionWidthDp * outResult.mDensity); final int captionHeight = loadResource(params.mCaptionHeightId); final int captionWidth = loadResource(params.mCaptionWidthId); //Prevent caption from going offscreen if task is too high up final int captionYPos = taskBounds.top <= captionHeight / 2 ? 0 : captionHeight / 2; Loading Loading @@ -289,8 +289,10 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> // Caption insets mCaptionInsetsRect.set(taskBounds); mCaptionInsetsRect.bottom = mCaptionInsetsRect.top + captionHeight - captionYPos; wct.addRectInsetsProvider(mTaskInfo.token, mCaptionInsetsRect, CAPTION_INSETS_TYPES); mCaptionInsetsRect.bottom = mCaptionInsetsRect.top + captionHeight - captionYPos; wct.addRectInsetsProvider(mTaskInfo.token, mCaptionInsetsRect, CAPTION_INSETS_TYPES); } else { startT.hide(mCaptionContainerSurface); } Loading @@ -307,6 +309,13 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> .setCrop(mTaskSurface, mTaskSurfaceCrop); } private int loadResource(int resourceId) { if (resourceId == Resources.ID_NULL) { return 0; } return mDecorWindowContext.getResources().getDimensionPixelSize(resourceId); } /** * Obtains the {@link Display} instance for the display ID in {@link #mTaskInfo} if it exists or * registers {@link #mOnDisplaysChangedListener} if it doesn't. Loading Loading @@ -368,13 +377,11 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> static class RelayoutResult<T extends View & TaskFocusStateConsumer> { int mWidth; int mHeight; float mDensity; T mRootView; void reset() { mWidth = 0; mHeight = 0; mDensity = 0; mRootView = null; } } Loading @@ -395,4 +402,37 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> return new SurfaceControlViewHost(c, d, wmm); } } static class RelayoutParams{ RunningTaskInfo mRunningTaskInfo; int mLayoutResId; int mCaptionHeightId; int mCaptionWidthId; int mShadowRadiusId; int mOutsetTopId; int mOutsetBottomId; int mOutsetLeftId; int mOutsetRightId; void setOutsets(int leftId, int topId, int rightId, int bottomId) { mOutsetLeftId = leftId; mOutsetTopId = topId; mOutsetRightId = rightId; mOutsetBottomId = bottomId; } void reset() { mLayoutResId = Resources.ID_NULL; mCaptionHeightId = Resources.ID_NULL; mCaptionWidthId = Resources.ID_NULL; mShadowRadiusId = Resources.ID_NULL; mOutsetTopId = Resources.ID_NULL; mOutsetBottomId = Resources.ID_NULL; mOutsetLeftId = Resources.ID_NULL; mOutsetRightId = Resources.ID_NULL; } } } No newline at end of file
libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java +34 −21 Original line number Diff line number Diff line Loading @@ -51,6 +51,7 @@ import android.window.WindowContainerTransaction; import androidx.test.filters.SmallTest; import com.android.wm.shell.R; import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.ShellTestCase; import com.android.wm.shell.TestRunningTaskInfoBuilder; Loading @@ -76,13 +77,9 @@ import java.util.function.Supplier; @SmallTest @RunWith(AndroidTestingRunner.class) public class WindowDecorationTests extends ShellTestCase { private static final int CAPTION_HEIGHT_DP = 32; private static final int CAPTION_WIDTH_DP = 216; private static final int SHADOW_RADIUS_DP = 5; private static final Rect TASK_BOUNDS = new Rect(100, 300, 400, 400); private static final Point TASK_POSITION_IN_PARENT = new Point(40, 60); private final Rect mOutsetsDp = new Rect(); private final WindowDecoration.RelayoutResult<TestView> mRelayoutResult = new WindowDecoration.RelayoutResult<>(); Loading @@ -104,6 +101,7 @@ public class WindowDecorationTests extends ShellTestCase { private final List<SurfaceControl.Builder> mMockSurfaceControlBuilders = new ArrayList<>(); private SurfaceControl.Transaction mMockSurfaceControlStartT; private SurfaceControl.Transaction mMockSurfaceControlFinishT; private WindowDecoration.RelayoutParams mRelayoutParams = new WindowDecoration.RelayoutParams(); @Before public void setUp() { Loading Loading @@ -147,7 +145,8 @@ public class WindowDecorationTests extends ShellTestCase { // Density is 2. Outsets are (20, 40, 60, 80) px. Shadow radius is 10px. Caption height is // 64px. taskInfo.configuration.densityDpi = DisplayMetrics.DENSITY_DEFAULT * 2; mOutsetsDp.set(10, 20, 30, 40); mRelayoutParams.setOutsets(R.dimen.freeform_resize_handle, R.dimen.freeform_resize_handle, R.dimen.freeform_resize_handle, R.dimen.freeform_resize_handle); final SurfaceControl taskSurface = mock(SurfaceControl.class); final TestWindowDecoration windowDecor = createWindowDecoration(taskInfo, taskSurface); Loading Loading @@ -197,8 +196,13 @@ public class WindowDecorationTests extends ShellTestCase { // Density is 2. Outsets are (20, 40, 60, 80) px. Shadow radius is 10px. Caption height is // 64px. taskInfo.configuration.densityDpi = DisplayMetrics.DENSITY_DEFAULT * 2; mOutsetsDp.set(10, 20, 30, 40); // int outsetLeftId = R.dimen.split_divider_bar_width; // int outsetTopId = R.dimen.gestures_onehanded_drag_threshold; // int outsetRightId = R.dimen.freeform_resize_handle; // int outsetBottomId = R.dimen.bubble_dismiss_target_padding_x; // mRelayoutParams.setOutsets(outsetLeftId, outsetTopId, outsetRightId, outsetBottomId); mRelayoutParams.setOutsets(R.dimen.freeform_resize_handle, R.dimen.freeform_resize_handle, R.dimen.freeform_resize_handle, R.dimen.freeform_resize_handle); final SurfaceControl taskSurface = mock(SurfaceControl.class); final TestWindowDecoration windowDecor = createWindowDecoration(taskInfo, taskSurface); Loading @@ -207,8 +211,8 @@ public class WindowDecorationTests extends ShellTestCase { verify(decorContainerSurfaceBuilder).setParent(taskSurface); verify(decorContainerSurfaceBuilder).setContainerLayer(); verify(mMockSurfaceControlStartT).setTrustedOverlay(decorContainerSurface, true); verify(mMockSurfaceControlStartT).setPosition(decorContainerSurface, -20, -40); verify(mMockSurfaceControlStartT).setWindowCrop(decorContainerSurface, 380, 220); verify(mMockSurfaceControlStartT).setPosition(decorContainerSurface, -60, -60); verify(mMockSurfaceControlStartT).setWindowCrop(decorContainerSurface, 420, 220); verify(taskBackgroundSurfaceBuilder).setParent(taskSurface); verify(taskBackgroundSurfaceBuilder).setEffectLayer(); Loading @@ -221,34 +225,36 @@ public class WindowDecorationTests extends ShellTestCase { verify(captionContainerSurfaceBuilder).setParent(decorContainerSurface); verify(captionContainerSurfaceBuilder).setContainerLayer(); verify(mMockSurfaceControlStartT).setPosition(captionContainerSurface, -46, 8); verify(mMockSurfaceControlStartT).setWindowCrop(captionContainerSurface, 300, 64); verify(mMockSurfaceControlStartT).setPosition(captionContainerSurface, -6, -156); verify(mMockSurfaceControlStartT).setWindowCrop(captionContainerSurface, 300, 432); verify(mMockSurfaceControlStartT).show(captionContainerSurface); verify(mMockSurfaceControlViewHostFactory).create(any(), eq(defaultDisplay), any()); verify(mMockSurfaceControlViewHost) .setView(same(mMockView), argThat(lp -> lp.height == 64 && lp.width == 300 argThat(lp -> lp.height == 432 && lp.width == 432 && (lp.flags & LayoutParams.FLAG_NOT_FOCUSABLE) != 0)); if (ViewRootImpl.CAPTION_ON_SHELL) { verify(mMockView).setTaskFocusState(true); verify(mMockWindowContainerTransaction) .addRectInsetsProvider(taskInfo.token, new Rect(100, 300, 400, 364), new Rect(100, 300, 400, 516), new int[] { InsetsState.ITYPE_CAPTION_BAR }); } verify(mMockSurfaceControlFinishT) .setPosition(taskSurface, TASK_POSITION_IN_PARENT.x, TASK_POSITION_IN_PARENT.y); verify(mMockSurfaceControlFinishT) .setCrop(taskSurface, new Rect(-20, -40, 360, 180)); .setCrop(taskSurface, new Rect(-60, -60, 360, 160)); verify(mMockSurfaceControlStartT) .show(taskSurface); assertEquals(380, mRelayoutResult.mWidth); assertEquals(420, mRelayoutResult.mWidth); assertEquals(220, mRelayoutResult.mHeight); assertEquals(2, mRelayoutResult.mDensity, 0.f); } @Test Loading Loading @@ -287,7 +293,8 @@ public class WindowDecorationTests extends ShellTestCase { // Density is 2. Outsets are (20, 40, 60, 80) px. Shadow radius is 10px. Caption height is // 64px. taskInfo.configuration.densityDpi = DisplayMetrics.DENSITY_DEFAULT * 2; mOutsetsDp.set(10, 20, 30, 40); mRelayoutParams.setOutsets(R.dimen.freeform_resize_handle, R.dimen.freeform_resize_handle, R.dimen.freeform_resize_handle, R.dimen.freeform_resize_handle); final SurfaceControl taskSurface = mock(SurfaceControl.class); final TestWindowDecoration windowDecor = createWindowDecoration(taskInfo, taskSurface); Loading Loading @@ -410,9 +417,15 @@ public class WindowDecorationTests extends ShellTestCase { @Override void relayout(ActivityManager.RunningTaskInfo taskInfo) { relayout(null /* taskInfo */, 0 /* layoutResId */, mMockView, CAPTION_HEIGHT_DP, CAPTION_WIDTH_DP, mOutsetsDp, SHADOW_RADIUS_DP, mMockSurfaceControlStartT, mMockSurfaceControlFinishT, mMockWindowContainerTransaction, mRelayoutResult); mRelayoutParams.mLayoutResId = 0; mRelayoutParams.mCaptionHeightId = R.dimen.freeform_decor_caption_width; mRelayoutParams.mCaptionWidthId = R.dimen.freeform_decor_caption_width; mRelayoutParams.mShadowRadiusId = R.dimen.freeform_decor_shadow_unfocused_thickness; relayout(mRelayoutParams, mMockSurfaceControlStartT, mMockSurfaceControlFinishT, mMockWindowContainerTransaction, mMockView, mRelayoutResult); } } }