diff options
| author | 2020-12-04 16:11:15 +0800 | |
|---|---|---|
| committer | 2020-12-17 07:39:24 +0800 | |
| commit | 2c8ea7b0217ecd50a70c52b3fbd3fa7697d297d7 (patch) | |
| tree | bf1f8c810f80db1b0e1517c2a3e6f8bf20dfdb38 | |
| parent | 519fb38710e029818bfeea37f46025636386591a (diff) | |
Fix showing black background when resizing the divider bar.
Reports resizing state to WM core so that app client could apply bigger
visible bounds while resizing splits. Also moves DividerHandleView to
more generic package.
Fix: 172704238
Test: manul check divider behavior
Test: atest WMShellUnitTests
Change-Id: I1656c86de9a0b5dfe5e6da57ccc9d5f6e467843a
| -rw-r--r-- | libs/WindowManager/Shell/res/layout/docked_stack_divider.xml | 4 | ||||
| -rw-r--r-- | libs/WindowManager/Shell/res/layout/split_divider.xml | 6 | ||||
| -rw-r--r-- | libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPair.java | 28 | ||||
| -rw-r--r-- | libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerHandleView.java (renamed from libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/DividerHandleView.java) | 12 | ||||
| -rw-r--r-- | libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java | 76 | ||||
| -rw-r--r-- | libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java | 4 | ||||
| -rw-r--r-- | libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitWindowManager.java | 19 | ||||
| -rw-r--r-- | libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/DividerView.java | 7 | ||||
| -rw-r--r-- | libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java | 15 | ||||
| -rw-r--r-- | services/core/java/com/android/server/wm/WindowState.java | 3 |
10 files changed, 116 insertions, 58 deletions
diff --git a/libs/WindowManager/Shell/res/layout/docked_stack_divider.xml b/libs/WindowManager/Shell/res/layout/docked_stack_divider.xml index ea21eb97df57..ed5d2e1b49f5 100644 --- a/libs/WindowManager/Shell/res/layout/docked_stack_divider.xml +++ b/libs/WindowManager/Shell/res/layout/docked_stack_divider.xml @@ -27,9 +27,9 @@ <com.android.wm.shell.legacysplitscreen.MinimizedDockShadow style="@style/DockedDividerMinimizedShadow" android:id="@+id/minimized_dock_shadow" - android:alpha="0"/>"> + android:alpha="0"/> - <com.android.wm.shell.legacysplitscreen.DividerHandleView + <com.android.wm.shell.common.split.DividerHandleView style="@style/DockedDividerHandle" android:id="@+id/docked_divider_handle" android:contentDescription="@string/accessibility_divider" diff --git a/libs/WindowManager/Shell/res/layout/split_divider.xml b/libs/WindowManager/Shell/res/layout/split_divider.xml index 341fe617b2d0..7f583f3e6bac 100644 --- a/libs/WindowManager/Shell/res/layout/split_divider.xml +++ b/libs/WindowManager/Shell/res/layout/split_divider.xml @@ -24,4 +24,10 @@ android:id="@+id/docked_divider_background" android:background="@color/docked_divider_background"/> + <com.android.wm.shell.common.split.DividerHandleView + style="@style/DockedDividerHandle" + android:id="@+id/docked_divider_handle" + android:contentDescription="@string/accessibility_divider" + android:background="@null"/> + </com.android.wm.shell.common.split.DividerView> diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPair.java b/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPair.java index 9754f5165a1c..563de06fe40c 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPair.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPair.java @@ -96,7 +96,8 @@ class AppPair implements ShellTaskOrganizer.TaskListener, SplitLayout.LayoutChan mTaskInfo2 = task2; mSplitLayout = new SplitLayout( mDisplayController.getDisplayContext(mRootTaskInfo.displayId), - mRootTaskInfo.configuration, this, b -> b.setParent(mRootTaskLeash)); + mRootTaskInfo.configuration, this /* layoutChangeListener */, + b -> b.setParent(mRootTaskLeash)); final WindowContainerToken token1 = task1.token; final WindowContainerToken token2 = task2.token; @@ -191,22 +192,7 @@ class AppPair implements ShellTaskOrganizer.TaskListener, SplitLayout.LayoutChan if (mSplitLayout != null && mSplitLayout.updateConfiguration(mRootTaskInfo.configuration)) { - // Update bounds when root bounds or its orientation changed. - final WindowContainerTransaction wct = new WindowContainerTransaction(); - final SurfaceControl dividerLeash = mSplitLayout.getDividerLeash(); - final Rect dividerBounds = mSplitLayout.getDividerBounds(); - final Rect bounds1 = mSplitLayout.getBounds1(); - final Rect bounds2 = mSplitLayout.getBounds2(); - - wct.setBounds(mTaskInfo1.token, bounds1) - .setBounds(mTaskInfo2.token, bounds2); - mController.getTaskOrganizer().applyTransaction(wct); - mSyncQueue.runInSync(t -> t - .setPosition(mTaskLeash1, bounds1.left, bounds1.top) - .setPosition(mTaskLeash2, bounds2.left, bounds2.top) - .setPosition(dividerLeash, dividerBounds.left, dividerBounds.top) - // Resets layer to divider bar to make sure it is always on top. - .setLayer(dividerLeash, Integer.MAX_VALUE)); + onBoundsChanged(mSplitLayout); } } else if (taskInfo.taskId == getTaskId1()) { mTaskInfo1 = taskInfo; @@ -262,6 +248,10 @@ class AppPair implements ShellTaskOrganizer.TaskListener, SplitLayout.LayoutChan final Rect bounds1 = layout.getBounds1(); final Rect bounds2 = layout.getBounds2(); mSyncQueue.runInSync(t -> t + // Ignores the original surface bounds so that the app could fill up the gap + // between each surface with corresponding background while resizing. + .setWindowCrop(mTaskLeash1, bounds1.width(), bounds1.height()) + .setWindowCrop(mTaskLeash2, bounds2.width(), bounds2.height()) .setPosition(dividerLeash, dividerBounds.left, dividerBounds.top) .setPosition(mTaskLeash1, bounds1.left, bounds1.top) .setPosition(mTaskLeash2, bounds2.left, bounds2.top)); @@ -279,6 +269,10 @@ class AppPair implements ShellTaskOrganizer.TaskListener, SplitLayout.LayoutChan .setBounds(mTaskInfo2.token, bounds2); mController.getTaskOrganizer().applyTransaction(wct); mSyncQueue.runInSync(t -> t + // Resets layer of divider bar to make sure it is always on top. + .setLayer(dividerLeash, Integer.MAX_VALUE) + .setWindowCrop(mTaskLeash1, bounds1.width(), bounds1.height()) + .setWindowCrop(mTaskLeash2, bounds2.width(), bounds2.height()) .setPosition(dividerLeash, dividerBounds.left, dividerBounds.top) .setPosition(mTaskLeash1, bounds1.left, bounds1.top) .setPosition(mTaskLeash2, bounds2.left, bounds2.top)); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/DividerHandleView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerHandleView.java index 17ca110285bf..218bf47e24aa 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/DividerHandleView.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerHandleView.java @@ -14,7 +14,10 @@ * limitations under the License. */ -package com.android.wm.shell.legacysplitscreen; +package com.android.wm.shell.common.split; + +import static com.android.wm.shell.common.split.DividerView.TOUCH_ANIMATION_DURATION; +import static com.android.wm.shell.common.split.DividerView.TOUCH_RELEASE_ANIMATION_DURATION; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; @@ -84,7 +87,8 @@ public class DividerHandleView extends View { mCircleDiameter = (mWidth + mHeight) / 3; } - void setTouching(boolean touching, boolean animate) { + /** Sets touching state for this handle view. */ + public void setTouching(boolean touching, boolean animate) { if (touching == mTouching) { return; } @@ -116,8 +120,8 @@ public class DividerHandleView extends View { mAnimator = new AnimatorSet(); mAnimator.playTogether(widthAnimator, heightAnimator); mAnimator.setDuration(touching - ? DividerView.TOUCH_ANIMATION_DURATION - : DividerView.TOUCH_RELEASE_ANIMATION_DURATION); + ? TOUCH_ANIMATION_DURATION + : TOUCH_RELEASE_ANIMATION_DURATION); mAnimator.setInterpolator(touching ? Interpolators.TOUCH_RESPONSE : Interpolators.FAST_OUT_SLOW_IN); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java index e97fe0a9111c..707747b3889b 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java @@ -33,17 +33,23 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.android.internal.policy.DividerSnapAlgorithm; +import com.android.wm.shell.R; +import com.android.wm.shell.animation.Interpolators; /** * Stack divider for app pair. */ -// TODO(b/172704238): add handle view to indicate touching status. public class DividerView extends FrameLayout implements View.OnTouchListener { + public static final long TOUCH_ANIMATION_DURATION = 150; + public static final long TOUCH_RELEASE_ANIMATION_DURATION = 200; + private final int mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop(); private SplitLayout mSplitLayout; private SurfaceControlViewHost mViewHost; - private DragListener mDragListener; + private DividerHandleView mHandle; + private View mBackground; + private int mTouchElevation; private VelocityTracker mVelocityTracker; private boolean mMoving; @@ -70,16 +76,18 @@ public class DividerView extends FrameLayout implements View.OnTouchListener { /** Sets up essential dependencies of the divider bar. */ public void setup( SplitLayout layout, - SurfaceControlViewHost viewHost, - @Nullable DragListener dragListener) { + SurfaceControlViewHost viewHost) { mSplitLayout = layout; mViewHost = viewHost; - mDragListener = dragListener; } @Override protected void onFinishInflate() { super.onFinishInflate(); + mHandle = findViewById(R.id.docked_divider_handle); + mBackground = findViewById(R.id.docked_divider_background); + mTouchElevation = getResources().getDimensionPixelSize( + R.dimen.docked_stack_divider_lift_elevation); setOnTouchListener(this); } @@ -97,7 +105,7 @@ public class DividerView extends FrameLayout implements View.OnTouchListener { case MotionEvent.ACTION_DOWN: mVelocityTracker = VelocityTracker.obtain(); mVelocityTracker.addMovement(event); - setSlippery(false); + setTouching(); mStartPos = touchPos; mMoving = false; break; @@ -106,9 +114,6 @@ public class DividerView extends FrameLayout implements View.OnTouchListener { if (!mMoving && Math.abs(touchPos - mStartPos) > mTouchSlop) { mStartPos = touchPos; mMoving = true; - if (mDragListener != null) { - mDragListener.onDragStart(); - } } if (mMoving) { final int position = mSplitLayout.getDividePosition() + touchPos - mStartPos; @@ -122,11 +127,8 @@ public class DividerView extends FrameLayout implements View.OnTouchListener { final float velocity = isLandscape ? mVelocityTracker.getXVelocity() : mVelocityTracker.getYVelocity(); - setSlippery(true); + releaseTouching(); mMoving = false; - if (mDragListener != null) { - mDragListener.onDragEnd(); - } final int position = mSplitLayout.getDividePosition() + touchPos - mStartPos; final DividerSnapAlgorithm.SnapTarget snapTarget = @@ -137,6 +139,45 @@ public class DividerView extends FrameLayout implements View.OnTouchListener { return true; } + private void setTouching() { + setSlippery(false); + mHandle.setTouching(true, true); + if (isLandscape()) { + mBackground.animate().scaleX(1.4f); + } else { + mBackground.animate().scaleY(1.4f); + } + mBackground.animate() + .setInterpolator(Interpolators.TOUCH_RESPONSE) + .setDuration(TOUCH_ANIMATION_DURATION) + .translationZ(mTouchElevation) + .start(); + // Lift handle as well so it doesn't get behind the background, even though it doesn't + // cast shadow. + mHandle.animate() + .setInterpolator(Interpolators.TOUCH_RESPONSE) + .setDuration(TOUCH_ANIMATION_DURATION) + .translationZ(mTouchElevation) + .start(); + } + + private void releaseTouching() { + setSlippery(true); + mHandle.setTouching(false, true); + mBackground.animate() + .setInterpolator(Interpolators.FAST_OUT_SLOW_IN) + .setDuration(TOUCH_RELEASE_ANIMATION_DURATION) + .translationZ(0) + .scaleX(1f) + .scaleY(1f) + .start(); + mHandle.animate() + .setInterpolator(Interpolators.FAST_OUT_SLOW_IN) + .setDuration(TOUCH_RELEASE_ANIMATION_DURATION) + .translationZ(0) + .start(); + } + private void setSlippery(boolean slippery) { if (mViewHost == null) { return; @@ -159,13 +200,4 @@ public class DividerView extends FrameLayout implements View.OnTouchListener { private boolean isLandscape() { return getResources().getConfiguration().orientation == ORIENTATION_LANDSCAPE; } - - /** Monitors dragging action of the divider bar. */ - // TODO(b/172704238): add listeners to deal with resizing state of the app windows. - public interface DragListener { - /** Called when start dragging. */ - void onDragStart(); - /** Called when stop dragging. */ - void onDragEnd(); - } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java index 6b9bf2d44261..291e9bdad69b 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java @@ -156,12 +156,14 @@ public class SplitLayout { void updateDivideBounds(int position) { updateBounds(position); mLayoutChangeListener.onBoundsChanging(this); + mSplitWindowManager.setResizingSplits(true); } void setDividePosition(int position) { mDividePosition = position; updateBounds(mDividePosition); mLayoutChangeListener.onBoundsChanged(this); + mSplitWindowManager.setResizingSplits(false); } /** @@ -172,9 +174,11 @@ public class SplitLayout { switch (snapTarget.flag) { case FLAG_DISMISS_START: mLayoutChangeListener.onSnappedToDismiss(false /* snappedToEnd */); + mSplitWindowManager.setResizingSplits(false); break; case FLAG_DISMISS_END: mLayoutChangeListener.onSnappedToDismiss(true /* snappedToEnd */); + mSplitWindowManager.setResizingSplits(false); break; default: flingDividePosition(currentPosition, snapTarget.position); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitWindowManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitWindowManager.java index 238caef27547..29116bd6f956 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitWindowManager.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitWindowManager.java @@ -25,6 +25,7 @@ import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMA import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY; import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER; +import android.app.ActivityTaskManager; import android.content.Context; import android.content.res.Configuration; import android.graphics.PixelFormat; @@ -32,6 +33,8 @@ import android.graphics.Rect; import android.graphics.Region; import android.os.Binder; import android.os.IBinder; +import android.os.RemoteException; +import android.util.Slog; import android.view.IWindow; import android.view.LayoutInflater; import android.view.SurfaceControl; @@ -47,11 +50,13 @@ import com.android.wm.shell.R; * Holds view hierarchy of a root surface and helps to inflate {@link DividerView} for a split. */ public final class SplitWindowManager extends WindowlessWindowManager { + private static final String TAG = SplitWindowManager.class.getSimpleName(); private static final String DIVIDER_WINDOW_TITLE = "SplitDivider"; + private final ParentContainerCallbacks mParentContainerCallbacks; private Context mContext; private SurfaceControlViewHost mViewHost; - final private ParentContainerCallbacks mParentContainerCallbacks; + private boolean mResizingSplits; public interface ParentContainerCallbacks { void attachToParentSurface(SurfaceControl.Builder b); @@ -104,7 +109,7 @@ public final class SplitWindowManager extends WindowlessWindowManager { lp.setTitle(DIVIDER_WINDOW_TITLE); lp.privateFlags |= PRIVATE_FLAG_NO_MOVE_ANIMATION | PRIVATE_FLAG_TRUSTED_OVERLAY; mViewHost.setView(dividerView, lp); - dividerView.setup(splitLayout, mViewHost, null /* dragListener */); + dividerView.setup(splitLayout, mViewHost); } /** @@ -117,6 +122,16 @@ public final class SplitWindowManager extends WindowlessWindowManager { mViewHost = null; } + void setResizingSplits(boolean resizing) { + if (resizing == mResizingSplits) return; + try { + ActivityTaskManager.getService().setSplitScreenResizing(resizing); + mResizingSplits = resizing; + } catch (RemoteException e) { + Slog.w(TAG, "Error calling setSplitScreenResizing", e); + } + } + /** * Gets {@link SurfaceControl} of the surface holding divider view. @return {@code null} if not * feasible. diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/DividerView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/DividerView.java index 16c966fccbf4..c1b6c4fec792 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/DividerView.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/DividerView.java @@ -20,6 +20,9 @@ import static android.view.PointerIcon.TYPE_HORIZONTAL_DOUBLE_ARROW; import static android.view.PointerIcon.TYPE_VERTICAL_DOUBLE_ARROW; import static android.view.WindowManager.DOCKED_RIGHT; +import static com.android.wm.shell.common.split.DividerView.TOUCH_ANIMATION_DURATION; +import static com.android.wm.shell.common.split.DividerView.TOUCH_RELEASE_ANIMATION_DURATION; + import android.animation.AnimationHandler; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; @@ -66,6 +69,7 @@ import com.android.internal.policy.DockedDividerUtils; import com.android.wm.shell.R; import com.android.wm.shell.animation.FlingAnimationUtils; import com.android.wm.shell.animation.Interpolators; +import com.android.wm.shell.common.split.DividerHandleView; import java.util.function.Consumer; @@ -82,9 +86,6 @@ public class DividerView extends FrameLayout implements OnTouchListener, void onDraggingEnd(); } - static final long TOUCH_ANIMATION_DURATION = 150; - static final long TOUCH_RELEASE_ANIMATION_DURATION = 200; - public static final int INVALID_RECENTS_GROW_TARGET = -1; private static final int LOG_VALUE_RESIZE_50_50 = 0; diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java index 708a6c56a3f5..cd468167e372 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java @@ -75,15 +75,16 @@ public class SplitLayoutTests extends ShellTestCase { } @Test - @UiThreadTest - public void testSnapToTarget() { - DividerSnapAlgorithm.SnapTarget snapTarget = getSnapTarget(0 /* position */, - DividerSnapAlgorithm.SnapTarget.FLAG_NONE); - mSplitLayout.snapToTarget(0 /* currentPosition */, snapTarget); - verify(mLayoutChangeListener).onBoundsChanging(any(SplitLayout.class)); + public void testSetDividePosition() { + mSplitLayout.setDividePosition(anyInt()); + verify(mLayoutChangeListener).onBoundsChanged(any(SplitLayout.class)); + } + @Test + @UiThreadTest + public void testSnapToDismissTarget() { // verify it callbacks properly when the snap target indicates dismissing split. - snapTarget = getSnapTarget(0 /* position */, + DividerSnapAlgorithm.SnapTarget snapTarget = getSnapTarget(0 /* position */, DividerSnapAlgorithm.SnapTarget.FLAG_DISMISS_START); mSplitLayout.snapToTarget(0 /* currentPosition */, snapTarget); verify(mLayoutChangeListener).onSnappedToDismiss(eq(false)); diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index 32b84a8d0a2c..d3102600092f 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -3843,7 +3843,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP if (task == null) { return false; } - if (!inSplitScreenWindowingMode() && !inFreeformWindowingMode()) { + if (!inSplitScreenWindowingMode() && !inFreeformWindowingMode() + && !task.getRootTask().mCreatedByOrganizer) { return false; } // TODO(157912944): formalize drag-resizing so that exceptions aren't hardcoded like this |