Loading libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicator.java +144 −36 Original line number Diff line number Diff line Loading @@ -16,10 +16,13 @@ package com.android.wm.shell.desktopmode; import static com.android.wm.shell.desktopmode.EnterDesktopTaskTransitionHandler.FINAL_FREEFORM_SCALE; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.RectEvaluator; import android.animation.ValueAnimator; import android.annotation.NonNull; import android.app.ActivityManager; import android.content.Context; import android.content.res.Resources; Loading @@ -32,12 +35,12 @@ import android.view.View; import android.view.WindowManager; import android.view.WindowlessWindowManager; import android.view.animation.DecelerateInterpolator; import android.widget.ImageView; import com.android.wm.shell.R; import com.android.wm.shell.RootTaskDisplayAreaOrganizer; import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.common.DisplayController; import com.android.wm.shell.common.DisplayLayout; import com.android.wm.shell.common.SyncTransactionQueue; /** Loading @@ -56,6 +59,9 @@ public class DesktopModeVisualIndicator { private final SyncTransactionQueue mSyncQueue; private SurfaceControlViewHost mViewHost; private View mView; private boolean mIsFullscreen; public DesktopModeVisualIndicator(SyncTransactionQueue syncQueue, ActivityManager.RunningTaskInfo taskInfo, DisplayController displayController, Context context, SurfaceControl taskSurface, ShellTaskOrganizer taskOrganizer, Loading @@ -67,21 +73,19 @@ public class DesktopModeVisualIndicator { mTaskSurface = taskSurface; mTaskOrganizer = taskOrganizer; mRootTdaOrganizer = taskDisplayAreaOrganizer; createView(); } /** * Create and animate the indicator for the exit desktop mode transition. * Create a fullscreen indicator with no animation */ public void createFullscreenIndicator() { private void createView() { final SurfaceControl.Transaction t = new SurfaceControl.Transaction(); final Resources resources = mContext.getResources(); final DisplayMetrics metrics = resources.getDisplayMetrics(); final int screenWidth = metrics.widthPixels; final int screenHeight = metrics.heightPixels; final int padding = mDisplayController .getDisplayLayout(mTaskInfo.displayId).stableInsets().top; final ImageView v = new ImageView(mContext); v.setImageResource(R.drawable.desktop_windowing_transition_background); mView = new View(mContext); final SurfaceControl.Builder builder = new SurfaceControl.Builder(); mRootTdaOrganizer.attachToDisplayArea(mTaskInfo.displayId, builder); mLeash = builder Loading @@ -101,7 +105,7 @@ public class DesktopModeVisualIndicator { mViewHost = new SurfaceControlViewHost(mContext, mDisplayController.getDisplay(mTaskInfo.displayId), windowManager, "FullscreenVisualIndicator"); mViewHost.setView(v, lp); mViewHost.setView(mView, lp); // We want this indicator to be behind the dragged task, but in front of all others. t.setRelativeLayer(mLeash, mTaskSurface, -1); Loading @@ -109,17 +113,56 @@ public class DesktopModeVisualIndicator { transaction.merge(t); t.close(); }); final Rect startBounds = new Rect(padding, padding, screenWidth - padding, screenHeight - padding); final VisualIndicatorAnimator animator = VisualIndicatorAnimator.fullscreenIndicator(v, startBounds); } /** * Create fullscreen indicator and fades it in. */ public void createFullscreenIndicator() { mIsFullscreen = true; mView.setBackgroundResource(R.drawable.desktop_windowing_transition_background); final VisualIndicatorAnimator animator = VisualIndicatorAnimator.toFullscreenAnimator( mView, mDisplayController.getDisplayLayout(mTaskInfo.displayId)); animator.start(); } /** * Create a fullscreen indicator. Animator fades it in while expanding the bounds outwards. */ public void createFullscreenIndicatorWithAnimatedBounds() { mIsFullscreen = true; mView.setBackgroundResource(R.drawable.desktop_windowing_transition_background); final VisualIndicatorAnimator animator = VisualIndicatorAnimator .toFullscreenAnimatorWithAnimatedBounds(mView, mDisplayController.getDisplayLayout(mTaskInfo.displayId)); animator.start(); } /** * Takes existing fullscreen indicator and animates it to freeform bounds */ public void transitionFullscreenIndicatorToFreeform() { mIsFullscreen = false; final VisualIndicatorAnimator animator = VisualIndicatorAnimator.toFreeformAnimator( mView, mDisplayController.getDisplayLayout(mTaskInfo.displayId)); animator.start(); } /** * Takes the existing freeform indicator and animates it to fullscreen */ public void transitionFreeformIndicatorToFullscreen() { mIsFullscreen = true; final VisualIndicatorAnimator animator = VisualIndicatorAnimator.toFullscreenAnimatorWithAnimatedBounds( mView, mDisplayController.getDisplayLayout(mTaskInfo.displayId)); animator.start(); } /** * Release the indicator and its components when it is no longer needed. */ public void releaseFullscreenIndicator() { public void releaseVisualIndicator() { if (mViewHost == null) return; if (mViewHost != null) { mViewHost.release(); Loading @@ -136,20 +179,28 @@ public class DesktopModeVisualIndicator { }); } } /** * Returns true if visual indicator is fullscreen */ public boolean isFullscreen() { return mIsFullscreen; } /** * Animator for Desktop Mode transitions which supports bounds and alpha animation. */ private static class VisualIndicatorAnimator extends ValueAnimator { private static final int FULLSCREEN_INDICATOR_DURATION = 200; private static final float SCALE_ADJUSTMENT_PERCENT = 0.015f; private static final float FULLSCREEN_SCALE_ADJUSTMENT_PERCENT = 0.015f; private static final float INDICATOR_FINAL_OPACITY = 0.7f; private final ImageView mView; private final View mView; private final Rect mStartBounds; private final Rect mEndBounds; private final RectEvaluator mRectEvaluator; private VisualIndicatorAnimator(ImageView view, Rect startBounds, private VisualIndicatorAnimator(View view, Rect startBounds, Rect endBounds) { mView = view; mStartBounds = new Rect(startBounds); Loading @@ -162,29 +213,65 @@ public class DesktopModeVisualIndicator { * Create animator for visual indicator of fullscreen transition * * @param view the view for this indicator * @param startBounds the starting bounds of the fullscreen indicator */ public static VisualIndicatorAnimator fullscreenIndicator(ImageView view, Rect startBounds) { view.getDrawable().setBounds(startBounds); int width = startBounds.width(); int height = startBounds.height(); Rect endBounds = new Rect((int) (startBounds.left - (SCALE_ADJUSTMENT_PERCENT * width)), (int) (startBounds.top - (SCALE_ADJUSTMENT_PERCENT * height)), (int) (startBounds.right + (SCALE_ADJUSTMENT_PERCENT * width)), (int) (startBounds.bottom + (SCALE_ADJUSTMENT_PERCENT * height))); VisualIndicatorAnimator animator = new VisualIndicatorAnimator( view, startBounds, endBounds); * @param displayLayout information about the display the transitioning task is currently on */ public static VisualIndicatorAnimator toFullscreenAnimator(@NonNull View view, @NonNull DisplayLayout displayLayout) { final Rect bounds = getMaxBounds(displayLayout); final VisualIndicatorAnimator animator = new VisualIndicatorAnimator( view, bounds, bounds); animator.setInterpolator(new DecelerateInterpolator()); setupIndicatorAnimation(animator); return animator; } /** * Create animator for visual indicator of fullscreen transition * * @param view the view for this indicator * @param displayLayout information about the display the transitioning task is currently on */ public static VisualIndicatorAnimator toFullscreenAnimatorWithAnimatedBounds( @NonNull View view, @NonNull DisplayLayout displayLayout) { final int padding = displayLayout.stableInsets().top; Rect startBounds = new Rect(padding, padding, displayLayout.width() - padding, displayLayout.height() - padding); view.getBackground().setBounds(startBounds); final VisualIndicatorAnimator animator = new VisualIndicatorAnimator( view, startBounds, getMaxBounds(displayLayout)); animator.setInterpolator(new DecelerateInterpolator()); setupIndicatorAnimation(animator); return animator; } /** * Create animator for visual indicator of freeform transition * * @param view the view for this indicator * @param displayLayout information about the display the transitioning task is currently on */ public static VisualIndicatorAnimator toFreeformAnimator(@NonNull View view, @NonNull DisplayLayout displayLayout) { final float adjustmentPercentage = 1f - FINAL_FREEFORM_SCALE; final int width = displayLayout.width(); final int height = displayLayout.height(); Rect endBounds = new Rect((int) (adjustmentPercentage * width / 2), (int) (adjustmentPercentage * height / 2), (int) (displayLayout.width() - (adjustmentPercentage * width / 2)), (int) (displayLayout.height() - (adjustmentPercentage * height / 2))); final VisualIndicatorAnimator animator = new VisualIndicatorAnimator( view, getMaxBounds(displayLayout), endBounds); animator.setInterpolator(new DecelerateInterpolator()); setupFullscreenIndicatorAnimation(animator); setupIndicatorAnimation(animator); return animator; } /** * Add necessary listener for animation of fullscreen indicator * Add necessary listener for animation of indicator */ private static void setupFullscreenIndicatorAnimation( VisualIndicatorAnimator animator) { private static void setupIndicatorAnimation(@NonNull VisualIndicatorAnimator animator) { animator.addUpdateListener(a -> { if (animator.mView != null) { animator.updateBounds(a.getAnimatedFraction(), animator.mView); Loading @@ -196,7 +283,7 @@ public class DesktopModeVisualIndicator { animator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { animator.mView.getDrawable().setBounds(animator.mEndBounds); animator.mView.getBackground().setBounds(animator.mEndBounds); } }); animator.setDuration(FULLSCREEN_INDICATOR_DURATION); Loading @@ -210,9 +297,12 @@ public class DesktopModeVisualIndicator { * @param fraction fraction to use, compared against previous fraction * @param view the view to update */ private void updateBounds(float fraction, ImageView view) { private void updateBounds(float fraction, View view) { if (mStartBounds.equals(mEndBounds)) { return; } Rect currentBounds = mRectEvaluator.evaluate(fraction, mStartBounds, mEndBounds); view.getDrawable().setBounds(currentBounds); view.getBackground().setBounds(currentBounds); } /** Loading @@ -223,5 +313,23 @@ public class DesktopModeVisualIndicator { private void updateIndicatorAlpha(float fraction, View view) { view.setAlpha(fraction * INDICATOR_FINAL_OPACITY); } /** * Return the max bounds of a fullscreen indicator */ private static Rect getMaxBounds(@NonNull DisplayLayout displayLayout) { final int padding = displayLayout.stableInsets().top; final int width = displayLayout.width() - 2 * padding; final int height = displayLayout.height() - 2 * padding; Rect endBounds = new Rect((int) (padding - (FULLSCREEN_SCALE_ADJUSTMENT_PERCENT * width)), (int) (padding - (FULLSCREEN_SCALE_ADJUSTMENT_PERCENT * height)), (int) (displayLayout.width() - padding + (FULLSCREEN_SCALE_ADJUSTMENT_PERCENT * width)), (int) (displayLayout.height() - padding + (FULLSCREEN_SCALE_ADJUSTMENT_PERCENT * height))); return endBounds; } } } libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt +67 −11 Original line number Diff line number Diff line Loading @@ -122,7 +122,7 @@ class DesktopTasksController( } /** Move a task to desktop */ fun moveToDesktop(task: ActivityManager.RunningTaskInfo) { fun moveToDesktop(task: RunningTaskInfo) { ProtoLog.v(WM_SHELL_DESKTOP_MODE, "moveToDesktop: %d", task.taskId) val wct = WindowContainerTransaction() Loading Loading @@ -181,7 +181,7 @@ class DesktopTasksController( } /** Move a task to fullscreen */ fun moveToFullscreen(task: ActivityManager.RunningTaskInfo) { fun moveToFullscreen(task: RunningTaskInfo) { ProtoLog.v(WM_SHELL_DESKTOP_MODE, "moveToFullscreen: %d", task.taskId) val wct = WindowContainerTransaction() Loading @@ -206,7 +206,7 @@ class DesktopTasksController( } /** Move a task to the front **/ fun moveTaskToFront(taskInfo: ActivityManager.RunningTaskInfo) { fun moveTaskToFront(taskInfo: RunningTaskInfo) { val wct = WindowContainerTransaction() wct.reorder(taskInfo.token, true) if (Transitions.ENABLE_SHELL_TRANSITIONS) { Loading Loading @@ -273,7 +273,7 @@ class DesktopTasksController( request: TransitionRequestInfo ): WindowContainerTransaction? { // Check if we should skip handling this transition val task: ActivityManager.RunningTaskInfo? = request.triggerTask val task: RunningTaskInfo? = request.triggerTask val shouldHandleRequest = when { // Only handle open or to front transitions Loading Loading @@ -382,16 +382,15 @@ class DesktopTasksController( taskSurface: SurfaceControl, y: Float ) { val statusBarHeight = displayController .getDisplayLayout(taskInfo.displayId)?.stableInsets()?.top ?: 0 if (taskInfo.windowingMode == WINDOWING_MODE_FREEFORM) { val statusBarHeight = getStatusBarHeight(taskInfo) if (y <= statusBarHeight && visualIndicator == null) { visualIndicator = DesktopModeVisualIndicator(syncQueue, taskInfo, displayController, context, taskSurface, shellTaskOrganizer, rootTaskDisplayAreaOrganizer) visualIndicator?.createFullscreenIndicator() visualIndicator?.createFullscreenIndicatorWithAnimatedBounds() } else if (y > statusBarHeight && visualIndicator != null) { visualIndicator?.releaseFullscreenIndicator() visualIndicator?.releaseVisualIndicator() visualIndicator = null } } Loading @@ -407,15 +406,72 @@ class DesktopTasksController( taskInfo: RunningTaskInfo, y: Float ) { val statusBarHeight = displayController .getDisplayLayout(taskInfo.displayId)?.stableInsets()?.top ?: 0 val statusBarHeight = getStatusBarHeight(taskInfo) if (y <= statusBarHeight && taskInfo.windowingMode == WINDOWING_MODE_FREEFORM) { visualIndicator?.releaseFullscreenIndicator() visualIndicator?.releaseVisualIndicator() visualIndicator = null moveToFullscreenWithAnimation(taskInfo) } } /** * Perform checks required on drag move. Create/release fullscreen indicator and transitions * indicator to freeform or fullscreen dimensions as needed. * * @param taskInfo the task being dragged. * @param taskSurface SurfaceControl of dragged task. * @param y coordinate of dragged task. Used for checks against status bar height. */ fun onDragPositioningMoveThroughStatusBar( taskInfo: RunningTaskInfo, taskSurface: SurfaceControl, y: Float ) { if (visualIndicator == null) { visualIndicator = DesktopModeVisualIndicator(syncQueue, taskInfo, displayController, context, taskSurface, shellTaskOrganizer, rootTaskDisplayAreaOrganizer) visualIndicator?.createFullscreenIndicator() } val indicator = visualIndicator ?: return if (y >= getFreeformTransitionStatusBarDragThreshold(taskInfo)) { if (indicator.isFullscreen) { indicator.transitionFullscreenIndicatorToFreeform() } } else if (!indicator.isFullscreen) { indicator.transitionFreeformIndicatorToFullscreen() } } /** * Perform checks required when drag ends under status bar area. * * @param taskInfo the task being dragged. * @param y height of drag, to be checked against status bar height. */ fun onDragPositioningEndThroughStatusBar( taskInfo: RunningTaskInfo, freeformBounds: Rect ) { moveToDesktopWithAnimation(taskInfo, freeformBounds) visualIndicator?.releaseVisualIndicator() visualIndicator = null } private fun getStatusBarHeight(taskInfo: RunningTaskInfo): Int { return displayController.getDisplayLayout(taskInfo.displayId)?.stableInsets()?.top ?: 0 } /** * Returns the threshold at which we transition a task into freeform when dragging a * fullscreen task down from the status bar */ private fun getFreeformTransitionStatusBarDragThreshold(taskInfo: RunningTaskInfo): Int { return 2 * getStatusBarHeight(taskInfo) } /** * Adds a listener to find out about changes in the visibility of freeform tasks. * Loading libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java +9 −5 Original line number Diff line number Diff line Loading @@ -79,6 +79,7 @@ import java.util.function.Supplier; public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { private static final String TAG = "DesktopModeWindowDecorViewModel"; private final DesktopModeWindowDecoration.Factory mDesktopModeWindowDecorFactory; private final ActivityTaskManager mActivityTaskManager; private final ShellTaskOrganizer mTaskOrganizer; Loading Loading @@ -542,7 +543,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { mTransitionDragActive = false; final int statusBarHeight = getStatusBarHeight( relevantDecor.mTaskInfo.displayId); if (ev.getY() > statusBarHeight) { if (ev.getY() > 2 * statusBarHeight) { if (DesktopModeStatus.isProto2Enabled()) { mPauseRelayoutForTask = relevantDecor.mTaskInfo.taskId; centerAndMoveToDesktopWithAnimation(relevantDecor, ev); Loading @@ -567,9 +568,11 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { return; } if (mTransitionDragActive) { final int statusBarHeight = mDisplayController .getDisplayLayout( relevantDecor.mTaskInfo.displayId).stableInsets().top; mDesktopTasksController.ifPresent( c -> c.onDragPositioningMoveThroughStatusBar(relevantDecor.mTaskInfo, relevantDecor.mTaskSurface, ev.getY())); final int statusBarHeight = getStatusBarHeight( relevantDecor.mTaskInfo.displayId); if (ev.getY() > statusBarHeight) { if (!mDragToDesktopAnimationStarted) { mDragToDesktopAnimationStarted = true; Loading Loading @@ -644,7 +647,8 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { @Override public void onAnimationEnd(Animator animation) { mDesktopTasksController.ifPresent( c -> c.moveToDesktopWithAnimation(relevantDecor.mTaskInfo, c -> c.onDragPositioningEndThroughStatusBar( relevantDecor.mTaskInfo, calculateFreeformBounds(FINAL_FREEFORM_SCALE))); } }); Loading Loading
libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicator.java +144 −36 Original line number Diff line number Diff line Loading @@ -16,10 +16,13 @@ package com.android.wm.shell.desktopmode; import static com.android.wm.shell.desktopmode.EnterDesktopTaskTransitionHandler.FINAL_FREEFORM_SCALE; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.RectEvaluator; import android.animation.ValueAnimator; import android.annotation.NonNull; import android.app.ActivityManager; import android.content.Context; import android.content.res.Resources; Loading @@ -32,12 +35,12 @@ import android.view.View; import android.view.WindowManager; import android.view.WindowlessWindowManager; import android.view.animation.DecelerateInterpolator; import android.widget.ImageView; import com.android.wm.shell.R; import com.android.wm.shell.RootTaskDisplayAreaOrganizer; import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.common.DisplayController; import com.android.wm.shell.common.DisplayLayout; import com.android.wm.shell.common.SyncTransactionQueue; /** Loading @@ -56,6 +59,9 @@ public class DesktopModeVisualIndicator { private final SyncTransactionQueue mSyncQueue; private SurfaceControlViewHost mViewHost; private View mView; private boolean mIsFullscreen; public DesktopModeVisualIndicator(SyncTransactionQueue syncQueue, ActivityManager.RunningTaskInfo taskInfo, DisplayController displayController, Context context, SurfaceControl taskSurface, ShellTaskOrganizer taskOrganizer, Loading @@ -67,21 +73,19 @@ public class DesktopModeVisualIndicator { mTaskSurface = taskSurface; mTaskOrganizer = taskOrganizer; mRootTdaOrganizer = taskDisplayAreaOrganizer; createView(); } /** * Create and animate the indicator for the exit desktop mode transition. * Create a fullscreen indicator with no animation */ public void createFullscreenIndicator() { private void createView() { final SurfaceControl.Transaction t = new SurfaceControl.Transaction(); final Resources resources = mContext.getResources(); final DisplayMetrics metrics = resources.getDisplayMetrics(); final int screenWidth = metrics.widthPixels; final int screenHeight = metrics.heightPixels; final int padding = mDisplayController .getDisplayLayout(mTaskInfo.displayId).stableInsets().top; final ImageView v = new ImageView(mContext); v.setImageResource(R.drawable.desktop_windowing_transition_background); mView = new View(mContext); final SurfaceControl.Builder builder = new SurfaceControl.Builder(); mRootTdaOrganizer.attachToDisplayArea(mTaskInfo.displayId, builder); mLeash = builder Loading @@ -101,7 +105,7 @@ public class DesktopModeVisualIndicator { mViewHost = new SurfaceControlViewHost(mContext, mDisplayController.getDisplay(mTaskInfo.displayId), windowManager, "FullscreenVisualIndicator"); mViewHost.setView(v, lp); mViewHost.setView(mView, lp); // We want this indicator to be behind the dragged task, but in front of all others. t.setRelativeLayer(mLeash, mTaskSurface, -1); Loading @@ -109,17 +113,56 @@ public class DesktopModeVisualIndicator { transaction.merge(t); t.close(); }); final Rect startBounds = new Rect(padding, padding, screenWidth - padding, screenHeight - padding); final VisualIndicatorAnimator animator = VisualIndicatorAnimator.fullscreenIndicator(v, startBounds); } /** * Create fullscreen indicator and fades it in. */ public void createFullscreenIndicator() { mIsFullscreen = true; mView.setBackgroundResource(R.drawable.desktop_windowing_transition_background); final VisualIndicatorAnimator animator = VisualIndicatorAnimator.toFullscreenAnimator( mView, mDisplayController.getDisplayLayout(mTaskInfo.displayId)); animator.start(); } /** * Create a fullscreen indicator. Animator fades it in while expanding the bounds outwards. */ public void createFullscreenIndicatorWithAnimatedBounds() { mIsFullscreen = true; mView.setBackgroundResource(R.drawable.desktop_windowing_transition_background); final VisualIndicatorAnimator animator = VisualIndicatorAnimator .toFullscreenAnimatorWithAnimatedBounds(mView, mDisplayController.getDisplayLayout(mTaskInfo.displayId)); animator.start(); } /** * Takes existing fullscreen indicator and animates it to freeform bounds */ public void transitionFullscreenIndicatorToFreeform() { mIsFullscreen = false; final VisualIndicatorAnimator animator = VisualIndicatorAnimator.toFreeformAnimator( mView, mDisplayController.getDisplayLayout(mTaskInfo.displayId)); animator.start(); } /** * Takes the existing freeform indicator and animates it to fullscreen */ public void transitionFreeformIndicatorToFullscreen() { mIsFullscreen = true; final VisualIndicatorAnimator animator = VisualIndicatorAnimator.toFullscreenAnimatorWithAnimatedBounds( mView, mDisplayController.getDisplayLayout(mTaskInfo.displayId)); animator.start(); } /** * Release the indicator and its components when it is no longer needed. */ public void releaseFullscreenIndicator() { public void releaseVisualIndicator() { if (mViewHost == null) return; if (mViewHost != null) { mViewHost.release(); Loading @@ -136,20 +179,28 @@ public class DesktopModeVisualIndicator { }); } } /** * Returns true if visual indicator is fullscreen */ public boolean isFullscreen() { return mIsFullscreen; } /** * Animator for Desktop Mode transitions which supports bounds and alpha animation. */ private static class VisualIndicatorAnimator extends ValueAnimator { private static final int FULLSCREEN_INDICATOR_DURATION = 200; private static final float SCALE_ADJUSTMENT_PERCENT = 0.015f; private static final float FULLSCREEN_SCALE_ADJUSTMENT_PERCENT = 0.015f; private static final float INDICATOR_FINAL_OPACITY = 0.7f; private final ImageView mView; private final View mView; private final Rect mStartBounds; private final Rect mEndBounds; private final RectEvaluator mRectEvaluator; private VisualIndicatorAnimator(ImageView view, Rect startBounds, private VisualIndicatorAnimator(View view, Rect startBounds, Rect endBounds) { mView = view; mStartBounds = new Rect(startBounds); Loading @@ -162,29 +213,65 @@ public class DesktopModeVisualIndicator { * Create animator for visual indicator of fullscreen transition * * @param view the view for this indicator * @param startBounds the starting bounds of the fullscreen indicator */ public static VisualIndicatorAnimator fullscreenIndicator(ImageView view, Rect startBounds) { view.getDrawable().setBounds(startBounds); int width = startBounds.width(); int height = startBounds.height(); Rect endBounds = new Rect((int) (startBounds.left - (SCALE_ADJUSTMENT_PERCENT * width)), (int) (startBounds.top - (SCALE_ADJUSTMENT_PERCENT * height)), (int) (startBounds.right + (SCALE_ADJUSTMENT_PERCENT * width)), (int) (startBounds.bottom + (SCALE_ADJUSTMENT_PERCENT * height))); VisualIndicatorAnimator animator = new VisualIndicatorAnimator( view, startBounds, endBounds); * @param displayLayout information about the display the transitioning task is currently on */ public static VisualIndicatorAnimator toFullscreenAnimator(@NonNull View view, @NonNull DisplayLayout displayLayout) { final Rect bounds = getMaxBounds(displayLayout); final VisualIndicatorAnimator animator = new VisualIndicatorAnimator( view, bounds, bounds); animator.setInterpolator(new DecelerateInterpolator()); setupIndicatorAnimation(animator); return animator; } /** * Create animator for visual indicator of fullscreen transition * * @param view the view for this indicator * @param displayLayout information about the display the transitioning task is currently on */ public static VisualIndicatorAnimator toFullscreenAnimatorWithAnimatedBounds( @NonNull View view, @NonNull DisplayLayout displayLayout) { final int padding = displayLayout.stableInsets().top; Rect startBounds = new Rect(padding, padding, displayLayout.width() - padding, displayLayout.height() - padding); view.getBackground().setBounds(startBounds); final VisualIndicatorAnimator animator = new VisualIndicatorAnimator( view, startBounds, getMaxBounds(displayLayout)); animator.setInterpolator(new DecelerateInterpolator()); setupIndicatorAnimation(animator); return animator; } /** * Create animator for visual indicator of freeform transition * * @param view the view for this indicator * @param displayLayout information about the display the transitioning task is currently on */ public static VisualIndicatorAnimator toFreeformAnimator(@NonNull View view, @NonNull DisplayLayout displayLayout) { final float adjustmentPercentage = 1f - FINAL_FREEFORM_SCALE; final int width = displayLayout.width(); final int height = displayLayout.height(); Rect endBounds = new Rect((int) (adjustmentPercentage * width / 2), (int) (adjustmentPercentage * height / 2), (int) (displayLayout.width() - (adjustmentPercentage * width / 2)), (int) (displayLayout.height() - (adjustmentPercentage * height / 2))); final VisualIndicatorAnimator animator = new VisualIndicatorAnimator( view, getMaxBounds(displayLayout), endBounds); animator.setInterpolator(new DecelerateInterpolator()); setupFullscreenIndicatorAnimation(animator); setupIndicatorAnimation(animator); return animator; } /** * Add necessary listener for animation of fullscreen indicator * Add necessary listener for animation of indicator */ private static void setupFullscreenIndicatorAnimation( VisualIndicatorAnimator animator) { private static void setupIndicatorAnimation(@NonNull VisualIndicatorAnimator animator) { animator.addUpdateListener(a -> { if (animator.mView != null) { animator.updateBounds(a.getAnimatedFraction(), animator.mView); Loading @@ -196,7 +283,7 @@ public class DesktopModeVisualIndicator { animator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { animator.mView.getDrawable().setBounds(animator.mEndBounds); animator.mView.getBackground().setBounds(animator.mEndBounds); } }); animator.setDuration(FULLSCREEN_INDICATOR_DURATION); Loading @@ -210,9 +297,12 @@ public class DesktopModeVisualIndicator { * @param fraction fraction to use, compared against previous fraction * @param view the view to update */ private void updateBounds(float fraction, ImageView view) { private void updateBounds(float fraction, View view) { if (mStartBounds.equals(mEndBounds)) { return; } Rect currentBounds = mRectEvaluator.evaluate(fraction, mStartBounds, mEndBounds); view.getDrawable().setBounds(currentBounds); view.getBackground().setBounds(currentBounds); } /** Loading @@ -223,5 +313,23 @@ public class DesktopModeVisualIndicator { private void updateIndicatorAlpha(float fraction, View view) { view.setAlpha(fraction * INDICATOR_FINAL_OPACITY); } /** * Return the max bounds of a fullscreen indicator */ private static Rect getMaxBounds(@NonNull DisplayLayout displayLayout) { final int padding = displayLayout.stableInsets().top; final int width = displayLayout.width() - 2 * padding; final int height = displayLayout.height() - 2 * padding; Rect endBounds = new Rect((int) (padding - (FULLSCREEN_SCALE_ADJUSTMENT_PERCENT * width)), (int) (padding - (FULLSCREEN_SCALE_ADJUSTMENT_PERCENT * height)), (int) (displayLayout.width() - padding + (FULLSCREEN_SCALE_ADJUSTMENT_PERCENT * width)), (int) (displayLayout.height() - padding + (FULLSCREEN_SCALE_ADJUSTMENT_PERCENT * height))); return endBounds; } } }
libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt +67 −11 Original line number Diff line number Diff line Loading @@ -122,7 +122,7 @@ class DesktopTasksController( } /** Move a task to desktop */ fun moveToDesktop(task: ActivityManager.RunningTaskInfo) { fun moveToDesktop(task: RunningTaskInfo) { ProtoLog.v(WM_SHELL_DESKTOP_MODE, "moveToDesktop: %d", task.taskId) val wct = WindowContainerTransaction() Loading Loading @@ -181,7 +181,7 @@ class DesktopTasksController( } /** Move a task to fullscreen */ fun moveToFullscreen(task: ActivityManager.RunningTaskInfo) { fun moveToFullscreen(task: RunningTaskInfo) { ProtoLog.v(WM_SHELL_DESKTOP_MODE, "moveToFullscreen: %d", task.taskId) val wct = WindowContainerTransaction() Loading @@ -206,7 +206,7 @@ class DesktopTasksController( } /** Move a task to the front **/ fun moveTaskToFront(taskInfo: ActivityManager.RunningTaskInfo) { fun moveTaskToFront(taskInfo: RunningTaskInfo) { val wct = WindowContainerTransaction() wct.reorder(taskInfo.token, true) if (Transitions.ENABLE_SHELL_TRANSITIONS) { Loading Loading @@ -273,7 +273,7 @@ class DesktopTasksController( request: TransitionRequestInfo ): WindowContainerTransaction? { // Check if we should skip handling this transition val task: ActivityManager.RunningTaskInfo? = request.triggerTask val task: RunningTaskInfo? = request.triggerTask val shouldHandleRequest = when { // Only handle open or to front transitions Loading Loading @@ -382,16 +382,15 @@ class DesktopTasksController( taskSurface: SurfaceControl, y: Float ) { val statusBarHeight = displayController .getDisplayLayout(taskInfo.displayId)?.stableInsets()?.top ?: 0 if (taskInfo.windowingMode == WINDOWING_MODE_FREEFORM) { val statusBarHeight = getStatusBarHeight(taskInfo) if (y <= statusBarHeight && visualIndicator == null) { visualIndicator = DesktopModeVisualIndicator(syncQueue, taskInfo, displayController, context, taskSurface, shellTaskOrganizer, rootTaskDisplayAreaOrganizer) visualIndicator?.createFullscreenIndicator() visualIndicator?.createFullscreenIndicatorWithAnimatedBounds() } else if (y > statusBarHeight && visualIndicator != null) { visualIndicator?.releaseFullscreenIndicator() visualIndicator?.releaseVisualIndicator() visualIndicator = null } } Loading @@ -407,15 +406,72 @@ class DesktopTasksController( taskInfo: RunningTaskInfo, y: Float ) { val statusBarHeight = displayController .getDisplayLayout(taskInfo.displayId)?.stableInsets()?.top ?: 0 val statusBarHeight = getStatusBarHeight(taskInfo) if (y <= statusBarHeight && taskInfo.windowingMode == WINDOWING_MODE_FREEFORM) { visualIndicator?.releaseFullscreenIndicator() visualIndicator?.releaseVisualIndicator() visualIndicator = null moveToFullscreenWithAnimation(taskInfo) } } /** * Perform checks required on drag move. Create/release fullscreen indicator and transitions * indicator to freeform or fullscreen dimensions as needed. * * @param taskInfo the task being dragged. * @param taskSurface SurfaceControl of dragged task. * @param y coordinate of dragged task. Used for checks against status bar height. */ fun onDragPositioningMoveThroughStatusBar( taskInfo: RunningTaskInfo, taskSurface: SurfaceControl, y: Float ) { if (visualIndicator == null) { visualIndicator = DesktopModeVisualIndicator(syncQueue, taskInfo, displayController, context, taskSurface, shellTaskOrganizer, rootTaskDisplayAreaOrganizer) visualIndicator?.createFullscreenIndicator() } val indicator = visualIndicator ?: return if (y >= getFreeformTransitionStatusBarDragThreshold(taskInfo)) { if (indicator.isFullscreen) { indicator.transitionFullscreenIndicatorToFreeform() } } else if (!indicator.isFullscreen) { indicator.transitionFreeformIndicatorToFullscreen() } } /** * Perform checks required when drag ends under status bar area. * * @param taskInfo the task being dragged. * @param y height of drag, to be checked against status bar height. */ fun onDragPositioningEndThroughStatusBar( taskInfo: RunningTaskInfo, freeformBounds: Rect ) { moveToDesktopWithAnimation(taskInfo, freeformBounds) visualIndicator?.releaseVisualIndicator() visualIndicator = null } private fun getStatusBarHeight(taskInfo: RunningTaskInfo): Int { return displayController.getDisplayLayout(taskInfo.displayId)?.stableInsets()?.top ?: 0 } /** * Returns the threshold at which we transition a task into freeform when dragging a * fullscreen task down from the status bar */ private fun getFreeformTransitionStatusBarDragThreshold(taskInfo: RunningTaskInfo): Int { return 2 * getStatusBarHeight(taskInfo) } /** * Adds a listener to find out about changes in the visibility of freeform tasks. * Loading
libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java +9 −5 Original line number Diff line number Diff line Loading @@ -79,6 +79,7 @@ import java.util.function.Supplier; public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { private static final String TAG = "DesktopModeWindowDecorViewModel"; private final DesktopModeWindowDecoration.Factory mDesktopModeWindowDecorFactory; private final ActivityTaskManager mActivityTaskManager; private final ShellTaskOrganizer mTaskOrganizer; Loading Loading @@ -542,7 +543,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { mTransitionDragActive = false; final int statusBarHeight = getStatusBarHeight( relevantDecor.mTaskInfo.displayId); if (ev.getY() > statusBarHeight) { if (ev.getY() > 2 * statusBarHeight) { if (DesktopModeStatus.isProto2Enabled()) { mPauseRelayoutForTask = relevantDecor.mTaskInfo.taskId; centerAndMoveToDesktopWithAnimation(relevantDecor, ev); Loading @@ -567,9 +568,11 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { return; } if (mTransitionDragActive) { final int statusBarHeight = mDisplayController .getDisplayLayout( relevantDecor.mTaskInfo.displayId).stableInsets().top; mDesktopTasksController.ifPresent( c -> c.onDragPositioningMoveThroughStatusBar(relevantDecor.mTaskInfo, relevantDecor.mTaskSurface, ev.getY())); final int statusBarHeight = getStatusBarHeight( relevantDecor.mTaskInfo.displayId); if (ev.getY() > statusBarHeight) { if (!mDragToDesktopAnimationStarted) { mDragToDesktopAnimationStarted = true; Loading Loading @@ -644,7 +647,8 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { @Override public void onAnimationEnd(Animator animation) { mDesktopTasksController.ifPresent( c -> c.moveToDesktopWithAnimation(relevantDecor.mTaskInfo, c -> c.onDragPositioningEndThroughStatusBar( relevantDecor.mTaskInfo, calculateFreeformBounds(FINAL_FREEFORM_SCALE))); } }); Loading