diff options
7 files changed, 227 insertions, 44 deletions
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java index eeae20fa1ccf..9ef51c8554d3 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -452,6 +452,22 @@ public class ActivityManager { */ public static final int FIRST_DYNAMIC_STACK_ID = LAST_STATIC_STACK_ID + 1; + /** + * Input parameter to {@link android.app.IActivityManager#moveTaskToDockedStack} which + * specifies the position of the created docked stack at the top half of the screen if + * in portrait mode or at the left half of the screen if in landscape mode. + * @hide + */ + public static final int DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT = 0; + + /** + * Input parameter to {@link android.app.IActivityManager#moveTaskToDockedStack} which + * specifies the position of the created docked stack at the bottom half of the screen if + * in portrait mode or at the right half of the screen if in landscape mode. + * @hide + */ + public static final int DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT = 1; + /** @hide */ public int getFrontActivityScreenCompatMode() { try { diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java index d1c73bc945ff..d79716cb03e8 100644 --- a/core/java/android/app/ActivityManagerNative.java +++ b/core/java/android/app/ActivityManagerNative.java @@ -743,6 +743,16 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM return true; } + case MOVE_TASK_TO_DOCKED_STACK_TRANSACTION: { + data.enforceInterface(IActivityManager.descriptor); + int taskId = data.readInt(); + int createMode = data.readInt(); + boolean toTop = data.readInt() != 0; + moveTaskToDockedStack(taskId, createMode, toTop); + reply.writeNoException(); + return true; + } + case RESIZE_STACK_TRANSACTION: { data.enforceInterface(IActivityManager.descriptor); int stackId = data.readInt(); @@ -3510,6 +3520,21 @@ class ActivityManagerProxy implements IActivityManager reply.recycle(); } @Override + public void moveTaskToDockedStack(int taskId, int createMode, boolean toTop) + throws RemoteException + { + Parcel data = Parcel.obtain(); + Parcel reply = Parcel.obtain(); + data.writeInterfaceToken(IActivityManager.descriptor); + data.writeInt(taskId); + data.writeInt(createMode); + data.writeInt(toTop ? 1 : 0); + mRemote.transact(MOVE_TASK_TO_DOCKED_STACK_TRANSACTION, data, reply, 0); + reply.readException(); + data.recycle(); + reply.recycle(); + } + @Override public void resizeStack(int stackId, Rect r) throws RemoteException { Parcel data = Parcel.obtain(); diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java index 66fa79639256..3b30d71cde70 100644 --- a/core/java/android/app/IActivityManager.java +++ b/core/java/android/app/IActivityManager.java @@ -140,6 +140,8 @@ public interface IActivityManager extends IInterface { public boolean moveActivityTaskToBack(IBinder token, boolean nonRoot) throws RemoteException; public void moveTaskBackwards(int task) throws RemoteException; public void moveTaskToStack(int taskId, int stackId, boolean toTop) throws RemoteException; + public void moveTaskToDockedStack(int taskId, int createMode, boolean toTop) + throws RemoteException; public void resizeStack(int stackId, Rect bounds) throws RemoteException; public void positionTaskInStack(int taskId, int stackId, int position) throws RemoteException; public List<StackInfo> getAllStackInfos() throws RemoteException; @@ -888,4 +890,5 @@ public interface IActivityManager extends IInterface { int GET_ACTIVITY_STACK_ID_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 343; int MOVE_ACTIVITY_TO_STACK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 344; int REPORT_SIZE_CONFIGURATIONS = IBinder.FIRST_CALL_TRANSACTION + 345; + int MOVE_TASK_TO_DOCKED_STACK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 346; } diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 14376d1bdb80..dc6f3d69d366 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -19,7 +19,6 @@ package com.android.server.am; import static android.Manifest.permission.INTERACT_ACROSS_USERS; import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL; import static android.Manifest.permission.START_TASKS_FROM_RECENTS; -import static android.app.ActivityManager.FREEFORM_WORKSPACE_STACK_ID; import static android.app.ActivityManager.DOCKED_STACK_ID; import static android.app.ActivityManager.HOME_STACK_ID; import static android.app.ActivityManager.INVALID_STACK_ID; @@ -215,7 +214,6 @@ import android.os.ServiceManager; import android.os.StrictMode; import android.os.SystemClock; import android.os.SystemProperties; -import android.os.Trace; import android.os.UpdateLock; import android.os.UserHandle; import android.os.UserManager; @@ -9053,6 +9051,35 @@ public final class ActivityManagerService extends ActivityManagerNative } } + /** + * Moves the input task to the docked stack. + * + * @param taskId Id of task to move. + * @param createMode The mode the docked stack should be created in if it doesn't exist + * already. See + * {@link android.app.ActivityManager#DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT} + * and + * {@link android.app.ActivityManager#DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT} + * @param toTop If the task and stack should be moved to the top. + */ + @Override + public void moveTaskToDockedStack(int taskId, int createMode, boolean toTop) { + enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS, + "moveTaskToDockedStack()"); + synchronized (this) { + long ident = Binder.clearCallingIdentity(); + try { + if (DEBUG_STACK) Slog.d(TAG_STACK, "moveTaskToDockedStack: moving task=" + taskId + + " to createMode=" + createMode + " toTop=" + toTop); + mWindowManager.setDockedStackCreateMode(createMode); + mStackSupervisor.moveTaskToStackLocked( + taskId, DOCKED_STACK_ID, toTop, !FORCE_FOCUS); + } finally { + Binder.restoreCallingIdentity(ident); + } + } + } + @Override public void resizeStack(int stackId, Rect bounds) { enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS, diff --git a/services/core/java/com/android/server/wm/TaskPositioner.java b/services/core/java/com/android/server/wm/TaskPositioner.java index 71b83a5e32ea..876e9aaa7db6 100644 --- a/services/core/java/com/android/server/wm/TaskPositioner.java +++ b/services/core/java/com/android/server/wm/TaskPositioner.java @@ -16,13 +16,12 @@ 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.DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT; +import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT; +import static android.app.ActivityManager.FREEFORM_WORKSPACE_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 +33,29 @@ import android.util.DisplayMetrics; 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 +77,14 @@ class TaskPositioner { 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 +154,13 @@ class TaskPositioner { // 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) { + final int createMode = mCurrentDimSide == CTRL_LEFT + ? DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT + : DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT; + mService.mActivityManager.moveTaskToDockedStack( + mTaskId, createMode, true /*toTop*/); + } } handled = true; } catch (Exception e) { @@ -213,6 +238,9 @@ class TaskPositioner { 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 +266,12 @@ class TaskPositioner { 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 +280,8 @@ class TaskPositioner { } 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 +303,7 @@ class TaskPositioner { final Task task = win.getTask(); mTaskId = task.mTaskId; + mStack = task.mStack; mStartDragX = startX; mStartDragY = startY; @@ -308,9 +343,75 @@ class TaskPositioner { } 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() { @@ -322,4 +423,4 @@ class TaskPositioner { private float dipToPx(float dip) { return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dip, mDisplayMetrics); } -}
\ No newline at end of file +} diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java index ae3bb9b20b04..1e6fab600594 100644 --- a/services/core/java/com/android/server/wm/TaskStack.java +++ b/services/core/java/com/android/server/wm/TaskStack.java @@ -353,11 +353,13 @@ public class TaskStack implements DimLayer.DimLayerUser { private static void getInitialDockedStackBounds( Rect displayRect, Rect outBounds, int stackId) { // Docked stack start off occupying half the screen space. - // TODO(multi-window): Need to support the selecting which half of the screen the - // docked stack uses for snapping windows to the edge of the screen. final boolean splitHorizontally = displayRect.width() > displayRect.height(); + final boolean topOrLeftCreateMode = + WindowManagerService.sDockedStackCreateMode == DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT; + final boolean placeTopOrLeft = (stackId == DOCKED_STACK_ID && topOrLeftCreateMode) + || (stackId != DOCKED_STACK_ID && !topOrLeftCreateMode); outBounds.set(displayRect); - if (stackId == DOCKED_STACK_ID) { + if (placeTopOrLeft) { if (splitHorizontally) { outBounds.right = displayRect.centerX(); } else { diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 69440b883d00..8719ddb8186c 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -16,6 +16,34 @@ package com.android.server.wm; +import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT; +import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW; +import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW; +import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM; +import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; +import static android.view.WindowManager.LayoutParams.FLAG_SECURE; +import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER; +import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW; +import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW; +import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW; +import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE; +import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST; +import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY; +import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION; +import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING; +import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION; +import static android.view.WindowManager.LayoutParams.TYPE_BOOT_PROGRESS; +import static android.view.WindowManager.LayoutParams.TYPE_DREAM; +import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD; +import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG; +import static android.view.WindowManager.LayoutParams.TYPE_PRIVATE_PRESENTATION; +import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR; +import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION; +import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER; +import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER; + +import static com.android.server.wm.WindowState.BOUNDS_FOR_TOUCH; + import android.Manifest; import android.animation.ValueAnimator; import android.app.ActivityManagerNative; @@ -110,9 +138,7 @@ import android.view.WindowManagerPolicy; import android.view.WindowManagerPolicy.PointerEventListener; import android.view.animation.Animation; -import static com.android.server.wm.WindowState.BOUNDS_FOR_TOUCH; import com.android.internal.app.IAssistScreenshotReceiver; -import com.android.internal.app.IBatteryStats; import com.android.internal.util.FastPrintWriter; import com.android.internal.view.IInputContext; import com.android.internal.view.IInputMethodClient; @@ -149,31 +175,6 @@ import java.util.HashMap; import java.util.Iterator; import java.util.List; -import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW; -import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW; -import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM; -import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; -import static android.view.WindowManager.LayoutParams.FLAG_SECURE; -import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER; -import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW; -import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW; -import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW; -import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE; -import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST; -import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY; -import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION; -import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING; -import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION; -import static android.view.WindowManager.LayoutParams.TYPE_BOOT_PROGRESS; -import static android.view.WindowManager.LayoutParams.TYPE_DREAM; -import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD; -import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG; -import static android.view.WindowManager.LayoutParams.TYPE_PRIVATE_PRESENTATION; -import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR; -import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION; -import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER; -import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER; - /** {@hide} */ public class WindowManagerService extends IWindowManager.Stub implements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs { @@ -458,6 +459,8 @@ public class WindowManagerService extends IWindowManager.Stub private boolean mKeyguardWaitingForActivityDrawn; + static int sDockedStackCreateMode = DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT; + class RotationWatcher { IRotationWatcher watcher; IBinder.DeathRecipient deathRecipient; @@ -4448,6 +4451,12 @@ public class WindowManagerService extends IWindowManager.Stub } } + public void setDockedStackCreateMode(int mode) { + synchronized (mWindowMap) { + sDockedStackCreateMode = mode; + } + } + /** * Create a new TaskStack and place it on a DisplayContent. * @param stackId The unique identifier of the new stack. |