Display dim layer when task is dragged to screen edge
Display a dim layer preview when a task/window is dragged to the
edge of the screen. The task is launched/moved into the docked
stack if the user lets go while the preview dim layer is up.
Change-Id: Iedc9e21b0bd23427512c319b4cc7514e64310813
diff --git a/services/core/java/com/android/server/wm/TaskPositioner.java b/services/core/java/com/android/server/wm/TaskPositioner.java
index 71b83a5..7901bee 100644
--- a/services/core/java/com/android/server/wm/TaskPositioner.java
+++ b/services/core/java/com/android/server/wm/TaskPositioner.java
@@ -16,13 +16,11 @@
package com.android.server.wm;
-import com.android.server.input.InputApplicationHandle;
-import com.android.server.input.InputWindowHandle;
-import com.android.server.wm.WindowManagerService.H;
+import static android.app.ActivityManager.FREEFORM_WORKSPACE_STACK_ID;
+import static android.app.ActivityManager.DOCKED_STACK_ID;
+import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
import static com.android.server.wm.WindowManagerService.DEBUG_TASK_POSITIONING;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
+import static com.android.server.wm.WindowManagerService.SHOW_TRANSACTIONS;
import android.annotation.IntDef;
import android.graphics.Point;
@@ -34,16 +32,29 @@
import android.util.Slog;
import android.util.TypedValue;
import android.view.Display;
+import android.view.DisplayInfo;
import android.view.InputChannel;
import android.view.InputDevice;
import android.view.InputEvent;
import android.view.InputEventReceiver;
import android.view.MotionEvent;
+import android.view.SurfaceControl;
import android.view.WindowManager;
-class TaskPositioner {
+import com.android.server.input.InputApplicationHandle;
+import com.android.server.input.InputWindowHandle;
+import com.android.server.wm.WindowManagerService.H;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+class TaskPositioner implements DimLayer.DimLayerUser {
private static final String TAG = "TaskPositioner";
+ // The margin the pointer position has to be within the side of the screen to be
+ // considered at the side of the screen.
+ private static final int SIDE_MARGIN_DIP = 5;
+
@IntDef(flag = true,
value = {
CTRL_NONE,
@@ -65,8 +76,14 @@
private WindowPositionerEventReceiver mInputEventReceiver;
private Display mDisplay;
private final DisplayMetrics mDisplayMetrics = new DisplayMetrics();
+ private DimLayer mDimLayer;
+ @CtrlType
+ private int mCurrentDimSide;
+ private Rect mTmpRect = new Rect();
+ private int mSideMargin;
private int mTaskId;
+ private TaskStack mStack;
private final Rect mWindowOriginalBounds = new Rect();
private final Rect mWindowDragBounds = new Rect();
private float mStartDragX;
@@ -136,6 +153,10 @@
// Post back to WM to handle clean-ups. We still need the input
// event handler for the last finishInputEvent()!
mService.mH.sendEmptyMessage(H.FINISH_TASK_POSITIONING);
+ if (mCurrentDimSide != CTRL_NONE) {
+ mService.mActivityManager.moveTaskToStack(
+ mTaskId, DOCKED_STACK_ID, true /*toTop*/);
+ }
}
handled = true;
} catch (Exception e) {
@@ -213,6 +234,9 @@
Slog.d(TAG, "Pausing rotation during re-position");
}
mService.pauseRotationLocked();
+
+ mDimLayer = new DimLayer(mService, this, mDisplay.getDisplayId());
+ mSideMargin = (int)dipToPx(SIDE_MARGIN_DIP);
}
void unregister() {
@@ -238,6 +262,12 @@
mDragApplicationHandle = null;
mDisplay = null;
+ if (mDimLayer != null) {
+ mDimLayer.destroySurface();
+ mDimLayer = null;
+ }
+ mCurrentDimSide = CTRL_NONE;
+
// Resume rotations after a drag.
if (WindowManagerService.DEBUG_ORIENTATION) {
Slog.d(TAG, "Resuming rotation after re-position");
@@ -246,8 +276,8 @@
}
void startDragLocked(WindowState win, boolean resize, float startX, float startY) {
- if (DEBUG_TASK_POSITIONING) {Slog.d(TAG,
- "startDragLocked: win=" + win + ", resize=" + resize
+ if (DEBUG_TASK_POSITIONING) {
+ Slog.d(TAG, "startDragLocked: win=" + win + ", resize=" + resize
+ ", {" + startX + ", " + startY + "}");
}
mCtrlType = CTRL_NONE;
@@ -269,6 +299,7 @@
final Task task = win.getTask();
mTaskId = task.mTaskId;
+ mStack = task.mStack;
mStartDragX = startX;
mStartDragY = startY;
@@ -308,11 +339,77 @@
} else {
// This is a moving operation.
mWindowDragBounds.set(mWindowOriginalBounds);
- mWindowDragBounds.offset(Math.round(x - mStartDragX),
- Math.round(y - mStartDragY));
+ mWindowDragBounds.offset(Math.round(x - mStartDragX), Math.round(y - mStartDragY));
+ updateDimLayerVisibility((int) x);
}
}
+ private void updateDimLayerVisibility(int x) {
+ @CtrlType
+ int dimSide = getDimSide(x);
+ if (dimSide == mCurrentDimSide) {
+ return;
+ }
+
+ mCurrentDimSide = dimSide;
+
+ if (SHOW_TRANSACTIONS) Slog.i(TAG, ">>> OPEN TRANSACTION updateDimLayerVisibility");
+ SurfaceControl.openTransaction();
+ if (mCurrentDimSide == CTRL_NONE) {
+ mDimLayer.hide();
+ } else {
+ showDimLayer();
+ }
+ SurfaceControl.closeTransaction();
+ }
+
+ /**
+ * Returns the side of the screen the dim layer should be shown.
+ * @param x horizontal coordinate used to determine if the dim layer should be shown
+ * @return Returns {@link #CTRL_LEFT} if the dim layer should be shown on the left half of the
+ * screen, {@link #CTRL_RIGHT} if on the right side, or {@link #CTRL_NONE} if the dim layer
+ * shouldn't be shown.
+ */
+ private int getDimSide(int x) {
+ if (mStack.mStackId != FREEFORM_WORKSPACE_STACK_ID
+ || !mStack.isFullscreen()
+ || mService.mCurConfiguration.orientation != ORIENTATION_LANDSCAPE) {
+ return CTRL_NONE;
+ }
+
+ mStack.getBounds(mTmpRect);
+ if (x - mSideMargin <= mTmpRect.left) {
+ return CTRL_LEFT;
+ }
+ if (x + mSideMargin >= mTmpRect.right) {
+ return CTRL_RIGHT;
+ }
+
+ return CTRL_NONE;
+ }
+
+ private void showDimLayer() {
+ mStack.getBounds(mTmpRect);
+ if (mCurrentDimSide == CTRL_LEFT) {
+ mTmpRect.right = mTmpRect.centerX();
+ } else if (mCurrentDimSide == CTRL_RIGHT) {
+ mTmpRect.left = mTmpRect.centerX();
+ }
+
+ mDimLayer.setBounds(mTmpRect);
+ mDimLayer.show(getDragLayerLocked(), 0.5f, 0);
+ }
+
+ @Override /** {@link DimLayer.DimLayerUser} */
+ public boolean isFullscreen() {
+ return false;
+ }
+
+ @Override /** {@link DimLayer.DimLayerUser} */
+ public DisplayInfo getDisplayInfo() {
+ return mStack.getDisplayInfo();
+ }
+
private int getDragLayerLocked() {
return mService.mPolicy.windowTypeToLayerLw(WindowManager.LayoutParams.TYPE_DRAG)
* WindowManagerService.TYPE_LAYER_MULTIPLIER
@@ -322,4 +419,4 @@
private float dipToPx(float dip) {
return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dip, mDisplayMetrics);
}
-}
\ No newline at end of file
+}