Loading libs/WindowManager/Shell/res/layout/docked_stack_divider.xml +2 −2 Original line number Diff line number Diff line Loading @@ -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" Loading libs/WindowManager/Shell/res/layout/split_divider.xml +6 −0 Original line number Diff line number Diff line Loading @@ -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> libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPair.java +11 −17 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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)); Loading @@ -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)); Loading libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/DividerHandleView.java→libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerHandleView.java +8 −4 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; } Loading Loading @@ -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); Loading libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java +54 −22 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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); } Loading @@ -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; Loading @@ -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; Loading @@ -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 = Loading @@ -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; Loading @@ -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(); } } Loading
libs/WindowManager/Shell/res/layout/docked_stack_divider.xml +2 −2 Original line number Diff line number Diff line Loading @@ -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" Loading
libs/WindowManager/Shell/res/layout/split_divider.xml +6 −0 Original line number Diff line number Diff line Loading @@ -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>
libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPair.java +11 −17 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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)); Loading @@ -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)); Loading
libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/DividerHandleView.java→libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerHandleView.java +8 −4 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; } Loading Loading @@ -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); Loading
libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java +54 −22 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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); } Loading @@ -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; Loading @@ -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; Loading @@ -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 = Loading @@ -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; Loading @@ -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(); } }