Dismissing of docked stack by dragging to the side.
Bug: 24623909
Change-Id: Ic93b169442de1eb4dca9f65a87ae2b813bcef043
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 42888cf..faa3a43 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -2691,6 +2691,13 @@
reply.writeNoException();
return true;
}
+ case REMOVE_STACK: {
+ data.enforceInterface(IActivityManager.descriptor);
+ final int stackId = data.readInt();
+ removeStack(stackId);
+ reply.writeNoException();
+ return true;
+ }
}
return super.onTransact(code, data, reply, flags);
@@ -6239,5 +6246,17 @@
reply.recycle();
}
+ @Override
+ public void removeStack(int stackId) throws RemoteException {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ data.writeInt(stackId);
+ mRemote.transact(REMOVE_STACK, data, reply, 0);
+ reply.readException();
+ data.recycle();
+ reply.recycle();
+ }
+
private IBinder mRemote;
}
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index ae82bd6..e23620d 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -16,8 +16,8 @@
package android.app;
-import android.app.ActivityManager.RunningTaskInfo;
import android.app.ActivityManager.RunningServiceInfo;
+import android.app.ActivityManager.RunningTaskInfo;
import android.app.ActivityManager.StackInfo;
import android.app.assist.AssistContent;
import android.app.assist.AssistStructure;
@@ -538,6 +538,8 @@
public void suppressResizeConfigChanges(boolean suppress) throws RemoteException;
+ public void removeStack(int stackId) throws RemoteException;
+
/*
* Private non-Binder interfaces
*/
@@ -895,4 +897,5 @@
int REPORT_SIZE_CONFIGURATIONS = IBinder.FIRST_CALL_TRANSACTION + 345;
int MOVE_TASK_TO_DOCKED_STACK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 346;
int SUPPRESS_RESIZE_CONFIG_CHANGES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 347;
+ int REMOVE_STACK = IBinder.FIRST_CALL_TRANSACTION + 348;
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index dac317a..91eaf93 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -17572,6 +17572,24 @@
}
@Override
+ public void removeStack(int stackId) {
+ enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
+ "detahStack()");
+ if (stackId == HOME_STACK_ID) {
+ throw new IllegalArgumentException("Removing home stack is not allowed.");
+ }
+ synchronized (this) {
+ ActivityStack stack = mStackSupervisor.getStack(stackId);
+ if (stack != null) {
+ ArrayList<TaskRecord> tasks = stack.getAllTasks();
+ for (int i = tasks.size() - 1; i >= 0; i--) {
+ removeTaskByIdLocked(tasks.get(i).taskId, true /* killProcess */);
+ }
+ }
+ }
+ }
+
+ @Override
public void updatePersistentConfiguration(Configuration values) {
enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,
"updateConfiguration()");
diff --git a/services/core/java/com/android/server/wm/DimLayer.java b/services/core/java/com/android/server/wm/DimLayer.java
index 8c479d8..bc31274 100644
--- a/services/core/java/com/android/server/wm/DimLayer.java
+++ b/services/core/java/com/android/server/wm/DimLayer.java
@@ -29,6 +29,10 @@
private static final String TAG = "DimLayer";
private static final boolean DEBUG = false;
+ public static final float RESIZING_HINT_ALPHA = 0.5f;
+
+ public static final int RESIZING_HINT_DURATION_MS = 0;
+
/** Actual surface that dims */
SurfaceControl mDimSurface;
diff --git a/services/core/java/com/android/server/wm/DockedStackDividerController.java b/services/core/java/com/android/server/wm/DockedStackDividerController.java
index b9028e3..120b077 100644
--- a/services/core/java/com/android/server/wm/DockedStackDividerController.java
+++ b/services/core/java/com/android/server/wm/DockedStackDividerController.java
@@ -25,16 +25,22 @@
import static android.view.WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING;
import static android.view.WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
+import static com.android.server.wm.DimLayer.RESIZING_HINT_ALPHA;
+import static com.android.server.wm.DimLayer.RESIZING_HINT_DURATION_MS;
+import static com.android.server.wm.TaskPositioner.SIDE_MARGIN_DIP;
import static com.android.server.wm.TaskStack.DOCKED_BOTTOM;
import static com.android.server.wm.TaskStack.DOCKED_LEFT;
import static com.android.server.wm.TaskStack.DOCKED_RIGHT;
import static com.android.server.wm.TaskStack.DOCKED_TOP;
+import static com.android.server.wm.WindowManagerService.dipToPixel;
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.os.RemoteException;
+import android.util.Slog;
+import android.view.DisplayInfo;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
@@ -44,11 +50,13 @@
/**
* Controls showing and hiding of a docked stack divider on the display.
*/
-public class DockedStackDividerController implements View.OnTouchListener {
+public class DockedStackDividerController implements View.OnTouchListener, DimLayer.DimLayerUser {
private static final String TAG = "DockedStackDivider";
private final Context mContext;
private final int mDividerWidth;
private final DisplayContent mDisplayContent;
+ private final int mSideMargin;
+ private final DimLayer mDimLayer;
private View mView;
private Rect mTmpRect = new Rect();
private Rect mLastResizeRect = new Rect();
@@ -57,12 +65,15 @@
private TaskStack mTaskStack;
private Rect mOriginalRect = new Rect();
private int mDockSide;
+ private boolean mDimLayerVisible;
DockedStackDividerController(Context context, DisplayContent displayContent) {
mContext = context;
mDisplayContent = displayContent;
mDividerWidth = context.getResources().getDimensionPixelSize(
com.android.internal.R.dimen.docked_stack_divider_thickness);
+ mSideMargin = dipToPixel(SIDE_MARGIN_DIP, mDisplayContent.getDisplayMetrics());
+ mDimLayer = new DimLayer(displayContent.mService, this, displayContent.getDisplayId());
}
private void addDivider(Configuration configuration) {
@@ -154,11 +165,17 @@
break;
case MotionEvent.ACTION_MOVE:
if (mTaskStack != null) {
- resizeStack(event);
+ final int x = (int) event.getRawX();
+ final int y = (int) event.getRawY();
+ resizeStack(x, y);
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
+ if (mTaskStack != null) {
+ maybeDismissTaskStack((int) event.getRawX(), (int) event.getRawY());
+ }
+ setDimLayerVisible(false, -1, -1);
mTaskStack = null;
mDockSide = TaskStack.DOCKED_INVALID;
break;
@@ -166,10 +183,88 @@
return true;
}
- private void resizeStack(MotionEvent event) {
+ private void maybeDismissTaskStack(int x, int y) {
+ final int distance = distanceFromDockSide(mDockSide, mOriginalRect, x, y);
+ if (distance == -1) {
+ Slog.wtf(TAG, "maybeDismissTaskStack: Unknown dock side=" + mDockSide);
+ return;
+ }
+ if (distance <= mSideMargin) {
+ try {
+ mDisplayContent.mService.mActivityManager.removeStack(mTaskStack.mStackId);
+ } catch (RemoteException e) {
+ // This can't happen because we are in the same process.
+ }
+ }
+ }
+
+ private void updateDimLayer(int x, int y) {
+ final int distance = distanceFromDockSide(mDockSide, mOriginalRect, x, y);
+ if (distance == -1) {
+ Slog.wtf(TAG, "updateDimLayer: Unknown dock side=" + mDockSide);
+ return;
+ }
+ setDimLayerVisible(distance <= mSideMargin, x, y);
+ }
+
+ /**
+ * Provides the distance from the point to the docked side of a rectangle.
+ *
+ * @return non negative distance or -1 on error
+ */
+ private static int distanceFromDockSide(int dockSide, Rect bounds, int x, int y) {
+ switch (dockSide) {
+ case DOCKED_LEFT:
+ return x - bounds.left;
+ case DOCKED_TOP:
+ return y - bounds.top;
+ case DOCKED_RIGHT:
+ return bounds.right - x;
+ case DOCKED_BOTTOM:
+ return bounds.bottom - y;
+ }
+ return -1;
+ }
+
+ private void setDimLayerVisible(boolean visible, int x, int y) {
+ if (visible) {
+ mTmpRect.set(mOriginalRect);
+ switch (mDockSide) {
+ case DOCKED_LEFT:
+ mTmpRect.right = x;
+ break;
+ case DOCKED_TOP:
+ mTmpRect.bottom = y;
+ break;
+ case DOCKED_RIGHT:
+ mTmpRect.left = x;
+ break;
+ case DOCKED_BOTTOM:
+ mTmpRect.top = y;
+ break;
+ default:
+ Slog.wtf(TAG, "setDimLayerVisible: Unknown dock side when setting dim layer="
+ + mDockSide);
+ return;
+ }
+ mDimLayer.setBounds(mTmpRect);
+ }
+ if (mDimLayerVisible == visible) {
+ return;
+ }
+ mDimLayerVisible = visible;
+ if (mDimLayerVisible) {
+ mDimLayer.show(mDisplayContent.mService.getDragLayerLocked(), RESIZING_HINT_ALPHA,
+ RESIZING_HINT_DURATION_MS);
+ } else {
+ mDimLayer.hide();
+ }
+ }
+
+ private void resizeStack(int x, int y) {
mTmpRect.set(mOriginalRect);
- final int deltaX = (int) event.getRawX() - mStartX;
- final int deltaY = (int) event.getRawY() - mStartY;
+ final int deltaX = x - mStartX;
+ final int deltaY = y - mStartY;
switch (mDockSide) {
case DOCKED_LEFT:
mTmpRect.right += deltaX;
@@ -191,7 +286,9 @@
try {
mDisplayContent.mService.mActivityManager.resizeStack(DOCKED_STACK_ID, mTmpRect);
} catch (RemoteException e) {
+ // This can't happen because we are in the same process.
}
+ updateDimLayer(x, y);
}
boolean isResizing() {
@@ -201,4 +298,24 @@
int getWidthAdjustment() {
return getWidth() / 2;
}
+
+ @Override
+ public boolean isFullscreen() {
+ return false;
+ }
+
+ @Override
+ public DisplayInfo getDisplayInfo() {
+ return mDisplayContent.getDisplayInfo();
+ }
+
+ @Override
+ public void getBounds(Rect outBounds) {
+ // This dim layer user doesn't need this.
+ }
+
+ @Override
+ public String toShortString() {
+ return TAG;
+ }
}
diff --git a/services/core/java/com/android/server/wm/TaskPositioner.java b/services/core/java/com/android/server/wm/TaskPositioner.java
index 207da47..227b3f0 100644
--- a/services/core/java/com/android/server/wm/TaskPositioner.java
+++ b/services/core/java/com/android/server/wm/TaskPositioner.java
@@ -23,8 +23,11 @@
import static android.app.ActivityManager.RESIZE_MODE_USER_FORCED;
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
+import static com.android.server.wm.DimLayer.RESIZING_HINT_ALPHA;
+import static com.android.server.wm.DimLayer.RESIZING_HINT_DURATION_MS;
import static com.android.server.wm.WindowManagerService.DEBUG_TASK_POSITIONING;
import static com.android.server.wm.WindowManagerService.SHOW_TRANSACTIONS;
+import static com.android.server.wm.WindowManagerService.dipToPixel;
import static com.android.server.wm.WindowState.MINIMUM_VISIBLE_HEIGHT_IN_DP;
import static com.android.server.wm.WindowState.MINIMUM_VISIBLE_WIDTH_IN_DP;
@@ -60,7 +63,7 @@
// 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 = 100;
+ static final int SIDE_MARGIN_DIP = 100;
@IntDef(flag = true,
value = {
@@ -246,7 +249,7 @@
mDisplay.getDisplayId());
mDragWindowHandle.name = TAG;
mDragWindowHandle.inputChannel = mServerChannel;
- mDragWindowHandle.layer = getDragLayerLocked();
+ mDragWindowHandle.layer = mService.getDragLayerLocked();
mDragWindowHandle.layoutParamsFlags = 0;
mDragWindowHandle.layoutParamsType = WindowManager.LayoutParams.TYPE_DRAG;
mDragWindowHandle.dispatchingTimeoutNanos =
@@ -279,9 +282,9 @@
mService.pauseRotationLocked();
mDimLayer = new DimLayer(mService, this, mDisplay.getDisplayId());
- mSideMargin = mService.dipToPixel(SIDE_MARGIN_DIP, mDisplayMetrics);
- mMinVisibleWidth = mService.dipToPixel(MINIMUM_VISIBLE_WIDTH_IN_DP, mDisplayMetrics);
- mMinVisibleHeight = mService.dipToPixel(MINIMUM_VISIBLE_HEIGHT_IN_DP, mDisplayMetrics);
+ mSideMargin = dipToPixel(SIDE_MARGIN_DIP, mDisplayMetrics);
+ mMinVisibleWidth = dipToPixel(MINIMUM_VISIBLE_WIDTH_IN_DP, mDisplayMetrics);
+ mMinVisibleHeight = dipToPixel(MINIMUM_VISIBLE_HEIGHT_IN_DP, mDisplayMetrics);
mDragEnded = false;
}
@@ -455,7 +458,8 @@
}
mDimLayer.setBounds(mTmpRect);
- mDimLayer.show(getDragLayerLocked(), 0.5f, 0);
+ mDimLayer.show(mService.getDragLayerLocked(), RESIZING_HINT_ALPHA,
+ RESIZING_HINT_DURATION_MS);
}
@Override /** {@link DimLayer.DimLayerUser} */
@@ -477,10 +481,4 @@
public String toShortString() {
return TAG;
}
-
- private int getDragLayerLocked() {
- return mService.mPolicy.windowTypeToLayerLw(WindowManager.LayoutParams.TYPE_DRAG)
- * WindowManagerService.TYPE_LAYER_MULTIPLIER
- + WindowManagerService.TYPE_LAYER_OFFSET;
- }
}
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index a630993..ca358b1 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -19,6 +19,7 @@
import static android.app.ActivityManager.*;
import static com.android.server.wm.WindowManagerService.DEBUG_TASK_MOVEMENT;
import static com.android.server.wm.WindowManagerService.H.RESIZE_STACK;
+import static com.android.server.wm.WindowManagerService.H.UNUSED;
import static com.android.server.wm.WindowManagerService.TAG;
import android.annotation.IntDef;
@@ -177,9 +178,9 @@
if (mDisplayContent != null) {
mDisplayContent.mDimBehindController.updateDimLayer(this);
+ mAnimationBackgroundSurface.setBounds(bounds);
}
- mAnimationBackgroundSurface.setBounds(bounds);
mBounds.set(bounds);
mRotation = rotation;
return true;
@@ -238,7 +239,7 @@
// a one-way call. We do this to prevent a deadlock between window manager
// lock and activity manager lock been held.
mService.mH.sendMessage(
- mService.mH.obtainMessage(RESIZE_STACK, mStackId, -1, mBounds));
+ mService.mH.obtainMessage(RESIZE_STACK, mStackId, UNUSED, mBounds));
}
}
}
@@ -488,7 +489,7 @@
&& otherStackId >= FIRST_STATIC_STACK_ID
&& otherStackId <= LAST_STATIC_STACK_ID) {
mService.mH.sendMessage(
- mService.mH.obtainMessage(RESIZE_STACK, otherStackId, -1, bounds));
+ mService.mH.obtainMessage(RESIZE_STACK, otherStackId, UNUSED, bounds));
}
}
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 3cf8500..6defcf5 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -465,6 +465,11 @@
static int sDockedStackCreateMode = DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
+ int getDragLayerLocked() {
+ return mPolicy.windowTypeToLayerLw(LayoutParams.TYPE_DRAG) * TYPE_LAYER_MULTIPLIER
+ + TYPE_LAYER_OFFSET;
+ }
+
class RotationWatcher {
IRotationWatcher watcher;
IBinder.DeathRecipient deathRecipient;