Loading libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicator.java +120 −145 Original line number Diff line number Diff line Loading @@ -16,6 +16,8 @@ package com.android.wm.shell.desktopmode; import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static com.android.wm.shell.desktopmode.EnterDesktopTaskTransitionHandler.FINAL_FREEFORM_SCALE; import android.animation.Animator; Loading @@ -39,7 +41,6 @@ import android.view.animation.DecelerateInterpolator; 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 @@ -48,100 +49,71 @@ import com.android.wm.shell.common.SyncTransactionQueue; * Animated visual indicator for Desktop Mode windowing transitions. */ public class DesktopModeVisualIndicator { public static final int INVALID_INDICATOR = -1; public enum IndicatorType { /** To be used when we don't want to indicate any transition */ NO_INDICATOR, /** Indicates impending transition into desktop mode */ public static final int TO_DESKTOP_INDICATOR = 1; TO_DESKTOP_INDICATOR, /** Indicates impending transition into fullscreen */ public static final int TO_FULLSCREEN_INDICATOR = 2; TO_FULLSCREEN_INDICATOR, /** Indicates impending transition into split select on the left side */ public static final int TO_SPLIT_LEFT_INDICATOR = 3; TO_SPLIT_LEFT_INDICATOR, /** Indicates impending transition into split select on the right side */ public static final int TO_SPLIT_RIGHT_INDICATOR = 4; TO_SPLIT_RIGHT_INDICATOR } private final Context mContext; private final DisplayController mDisplayController; private final ShellTaskOrganizer mTaskOrganizer; private final RootTaskDisplayAreaOrganizer mRootTdaOrganizer; private final ActivityManager.RunningTaskInfo mTaskInfo; private final SurfaceControl mTaskSurface; private final Rect mIndicatorRange = new Rect(); private SurfaceControl mLeash; private final SyncTransactionQueue mSyncQueue; private SurfaceControlViewHost mViewHost; private View mView; private boolean mIsFullscreen; private int mType; private IndicatorType mCurrentType; public DesktopModeVisualIndicator(SyncTransactionQueue syncQueue, ActivityManager.RunningTaskInfo taskInfo, DisplayController displayController, Context context, SurfaceControl taskSurface, ShellTaskOrganizer taskOrganizer, RootTaskDisplayAreaOrganizer taskDisplayAreaOrganizer, int type) { Context context, SurfaceControl taskSurface, RootTaskDisplayAreaOrganizer taskDisplayAreaOrganizer) { mSyncQueue = syncQueue; mTaskInfo = taskInfo; mDisplayController = displayController; mContext = context; mTaskSurface = taskSurface; mTaskOrganizer = taskOrganizer; mRootTdaOrganizer = taskDisplayAreaOrganizer; mType = type; defineIndicatorRange(); mCurrentType = IndicatorType.NO_INDICATOR; createView(); } /** * If an indicator is warranted based on the input and task bounds, return the type of * indicator that should be created. */ public static int determineIndicatorType(PointF inputCoordinates, Rect taskBounds, DisplayLayout layout, Context context) { int transitionAreaHeight = context.getResources().getDimensionPixelSize( com.android.wm.shell.R.dimen.desktop_mode_transition_area_height); int transitionAreaWidth = context.getResources().getDimensionPixelSize( com.android.wm.shell.R.dimen.desktop_mode_transition_area_width); if (taskBounds.top <= transitionAreaHeight) return TO_FULLSCREEN_INDICATOR; if (inputCoordinates.x <= transitionAreaWidth) return TO_SPLIT_LEFT_INDICATOR; if (inputCoordinates.x >= layout.width() - transitionAreaWidth) { return TO_SPLIT_RIGHT_INDICATOR; } return INVALID_INDICATOR; } /** * Determine range of inputs that will keep this indicator displaying. * Based on the coordinates of the current drag event, determine which indicator type we should * display, including no visible indicator. * TODO(b/280828642): Update drag zones per starting windowing mode. */ private void defineIndicatorRange() { DisplayLayout layout = mDisplayController.getDisplayLayout(mTaskInfo.displayId); int captionHeight = mContext.getResources().getDimensionPixelSize( com.android.wm.shell.R.dimen.freeform_decor_caption_height); IndicatorType updateIndicatorType(PointF inputCoordinates) { final DisplayLayout layout = mDisplayController.getDisplayLayout(mTaskInfo.displayId); // If we are in freeform, we don't want a visible indicator in the "freeform" drag zone. IndicatorType result = mTaskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM ? IndicatorType.NO_INDICATOR : IndicatorType.TO_DESKTOP_INDICATOR; int transitionAreaHeight = mContext.getResources().getDimensionPixelSize( com.android.wm.shell.R.dimen.desktop_mode_transition_area_height); int transitionAreaWidth = mContext.getResources().getDimensionPixelSize( com.android.wm.shell.R.dimen.desktop_mode_transition_area_width); switch (mType) { case TO_DESKTOP_INDICATOR: // TO_DESKTOP indicator is only dismissed on release; entire display is valid. mIndicatorRange.set(0, 0, layout.width(), layout.height()); break; case TO_FULLSCREEN_INDICATOR: // If drag results in caption going above the top edge of the display, we still // want to transition to fullscreen. mIndicatorRange.set(0, -captionHeight, layout.width(), transitionAreaHeight); break; case TO_SPLIT_LEFT_INDICATOR: mIndicatorRange.set(0, transitionAreaHeight, transitionAreaWidth, layout.height()); break; case TO_SPLIT_RIGHT_INDICATOR: mIndicatorRange.set(layout.width() - transitionAreaWidth, transitionAreaHeight, layout.width(), layout.height()); break; default: break; if (inputCoordinates.y <= transitionAreaHeight) { result = IndicatorType.TO_FULLSCREEN_INDICATOR; } else if (inputCoordinates.x <= transitionAreaWidth) { result = IndicatorType.TO_SPLIT_LEFT_INDICATOR; } else if (inputCoordinates.x >= layout.width() - transitionAreaWidth) { result = IndicatorType.TO_SPLIT_RIGHT_INDICATOR; } transitionIndicator(result); return result; } /** * Create a fullscreen indicator with no animation */ Loading @@ -156,7 +128,7 @@ public class DesktopModeVisualIndicator { final SurfaceControl.Builder builder = new SurfaceControl.Builder(); mRootTdaOrganizer.attachToDisplayArea(mTaskInfo.displayId, builder); String description; switch (mType) { switch (mCurrentType) { case TO_DESKTOP_INDICATOR: description = "Desktop indicator"; break; Loading Loading @@ -201,46 +173,45 @@ public class DesktopModeVisualIndicator { } /** * Create an indicator. Animator fades it in while expanding the bounds outwards. * Fade indicator in as provided type. Animator fades it in while expanding the bounds outwards. */ public void createIndicatorWithAnimatedBounds() { mIsFullscreen = mType == TO_FULLSCREEN_INDICATOR; private void fadeInIndicator(IndicatorType type) { mView.setBackgroundResource(R.drawable.desktop_windowing_transition_background); final VisualIndicatorAnimator animator = VisualIndicatorAnimator .animateBounds(mView, mType, .fadeBoundsIn(mView, type, mDisplayController.getDisplayLayout(mTaskInfo.displayId)); animator.start(); mCurrentType = type; } /** * Takes existing fullscreen indicator and animates it to freeform bounds * Fade out indicator without fully releasing it. Animator fades it out while shrinking bounds. */ public void transitionFullscreenIndicatorToFreeform() { mIsFullscreen = false; mType = TO_DESKTOP_INDICATOR; final VisualIndicatorAnimator animator = VisualIndicatorAnimator.toFreeformAnimator( mView, mDisplayController.getDisplayLayout(mTaskInfo.displayId)); private void fadeOutIndicator() { final VisualIndicatorAnimator animator = VisualIndicatorAnimator .fadeBoundsOut(mView, mCurrentType, mDisplayController.getDisplayLayout(mTaskInfo.displayId)); animator.start(); mCurrentType = IndicatorType.NO_INDICATOR; } /** * Takes the existing freeform indicator and animates it to fullscreen * Takes existing indicator and animates it to bounds reflecting a new indicator type. */ public void transitionFreeformIndicatorToFullscreen() { mIsFullscreen = true; mType = TO_FULLSCREEN_INDICATOR; final VisualIndicatorAnimator animator = VisualIndicatorAnimator.toFullscreenAnimatorWithAnimatedBounds( mView, mDisplayController.getDisplayLayout(mTaskInfo.displayId)); private void transitionIndicator(IndicatorType newType) { if (mCurrentType == newType) return; if (mCurrentType == IndicatorType.NO_INDICATOR) { fadeInIndicator(newType); } else if (newType == IndicatorType.NO_INDICATOR) { fadeOutIndicator(); } else { final VisualIndicatorAnimator animator = VisualIndicatorAnimator.animateIndicatorType( mView, mDisplayController.getDisplayLayout(mTaskInfo.displayId), mCurrentType, newType); mCurrentType = newType; animator.start(); } /** * Determine if a MotionEvent is in the same range that enabled the indicator. * Used to dismiss the indicator when a transition will no longer result from releasing. */ public boolean eventOutsideRange(float x, float y) { return !mIndicatorRange.contains((int) x, (int) y); } /** Loading @@ -259,13 +230,6 @@ 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. */ Loading @@ -274,6 +238,13 @@ public class DesktopModeVisualIndicator { private static final float FULLSCREEN_SCALE_ADJUSTMENT_PERCENT = 0.015f; private static final float INDICATOR_FINAL_OPACITY = 0.7f; /** Determines how this animator will interact with the view's alpha: * Fade in, fade out, or no change to alpha */ private enum AlphaAnimType{ ALPHA_FADE_IN_ANIM, ALPHA_FADE_OUT_ANIM, ALPHA_NO_CHANGE_ANIM } private final View mView; private final Rect mStartBounds; private final Rect mEndBounds; Loading @@ -288,87 +259,91 @@ public class DesktopModeVisualIndicator { mRectEvaluator = new RectEvaluator(new Rect()); } /** * 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); private static VisualIndicatorAnimator fadeBoundsIn( @NonNull View view, IndicatorType type, @NonNull DisplayLayout displayLayout) { final Rect startBounds = getIndicatorBounds(displayLayout, type); view.getBackground().setBounds(startBounds); final VisualIndicatorAnimator animator = new VisualIndicatorAnimator( view, startBounds, getMaxBounds(startBounds)); animator.setInterpolator(new DecelerateInterpolator()); setupIndicatorAnimation(animator); setupIndicatorAnimation(animator, AlphaAnimType.ALPHA_FADE_IN_ANIM); return animator; } public static VisualIndicatorAnimator animateBounds( @NonNull View view, int type, @NonNull DisplayLayout displayLayout) { final int padding = displayLayout.stableInsets().top; Rect startBounds = new Rect(); switch (type) { case TO_FULLSCREEN_INDICATOR: startBounds.set(padding, padding, displayLayout.width() - padding, displayLayout.height() - padding); break; case TO_SPLIT_LEFT_INDICATOR: startBounds.set(padding, padding, displayLayout.width() / 2 - padding, displayLayout.height() - padding); break; case TO_SPLIT_RIGHT_INDICATOR: startBounds.set(displayLayout.width() / 2 + padding, padding, displayLayout.width() - padding, displayLayout.height() - padding); break; } private static VisualIndicatorAnimator fadeBoundsOut( @NonNull View view, IndicatorType type, @NonNull DisplayLayout displayLayout) { final Rect endBounds = getIndicatorBounds(displayLayout, type); final Rect startBounds = getMaxBounds(endBounds); view.getBackground().setBounds(startBounds); final VisualIndicatorAnimator animator = new VisualIndicatorAnimator( view, startBounds, getMaxBounds(startBounds)); view, startBounds, endBounds); animator.setInterpolator(new DecelerateInterpolator()); setupIndicatorAnimation(animator); setupIndicatorAnimation(animator, AlphaAnimType.ALPHA_FADE_OUT_ANIM); return animator; } /** * Create animator for visual indicator of freeform transition * Create animator for visual indicator changing type (i.e., fullscreen to freeform, * freeform to split, etc.) * * @param view the view for this indicator * @param displayLayout information about the display the transitioning task is currently on * @param origType the original indicator type * @param newType the new indicator type */ 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 startBounds = new Rect(0, 0, width, 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))); private static VisualIndicatorAnimator animateIndicatorType(@NonNull View view, @NonNull DisplayLayout displayLayout, IndicatorType origType, IndicatorType newType) { final Rect startBounds = getIndicatorBounds(displayLayout, origType); final Rect endBounds = getIndicatorBounds(displayLayout, newType); final VisualIndicatorAnimator animator = new VisualIndicatorAnimator( view, startBounds, endBounds); animator.setInterpolator(new DecelerateInterpolator()); setupIndicatorAnimation(animator); setupIndicatorAnimation(animator, AlphaAnimType.ALPHA_NO_CHANGE_ANIM); return animator; } private static Rect getIndicatorBounds(DisplayLayout layout, IndicatorType type) { final int padding = layout.stableInsets().top; switch (type) { case TO_FULLSCREEN_INDICATOR: return new Rect(padding, padding, layout.width() - padding, layout.height() - padding); case TO_DESKTOP_INDICATOR: final float adjustmentPercentage = 1f - FINAL_FREEFORM_SCALE; return new Rect((int) (adjustmentPercentage * layout.width() / 2), (int) (adjustmentPercentage * layout.height() / 2), (int) (layout.width() - (adjustmentPercentage * layout.width() / 2)), (int) (layout.height() - (adjustmentPercentage * layout.height() / 2))); case TO_SPLIT_LEFT_INDICATOR: return new Rect(padding, padding, layout.width() / 2 - padding, layout.height() - padding); case TO_SPLIT_RIGHT_INDICATOR: return new Rect(layout.width() / 2 + padding, padding, layout.width() - padding, layout.height() - padding); default: throw new IllegalArgumentException("Invalid indicator type provided."); } } /** * Add necessary listener for animation of indicator */ private static void setupIndicatorAnimation(@NonNull VisualIndicatorAnimator animator) { private static void setupIndicatorAnimation(@NonNull VisualIndicatorAnimator animator, AlphaAnimType animType) { animator.addUpdateListener(a -> { if (animator.mView != null) { animator.updateBounds(a.getAnimatedFraction(), animator.mView); if (animType == AlphaAnimType.ALPHA_FADE_IN_ANIM) { animator.updateIndicatorAlpha(a.getAnimatedFraction(), animator.mView); } else if (animType == AlphaAnimType.ALPHA_FADE_OUT_ANIM) { animator.updateIndicatorAlpha(1 - a.getAnimatedFraction(), animator.mView); } } else { animator.cancel(); } Loading @@ -394,7 +369,7 @@ public class DesktopModeVisualIndicator { if (mStartBounds.equals(mEndBounds)) { return; } Rect currentBounds = mRectEvaluator.evaluate(fraction, mStartBounds, mEndBounds); final Rect currentBounds = mRectEvaluator.evaluate(fraction, mStartBounds, mEndBounds); view.getBackground().setBounds(currentBounds); } Loading libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt +18 −63 Original line number Diff line number Diff line Loading @@ -57,7 +57,6 @@ import com.android.wm.shell.common.annotations.ShellMainThread import com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT import com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT import com.android.wm.shell.desktopmode.DesktopModeTaskRepository.VisibleTasksListener import com.android.wm.shell.desktopmode.DesktopModeVisualIndicator.TO_DESKTOP_INDICATOR import com.android.wm.shell.desktopmode.DragToDesktopTransitionHandler.DragToDesktopStateListener import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE import com.android.wm.shell.recents.RecentsTransitionHandler Loading Loading @@ -871,31 +870,34 @@ class DesktopTasksController( * * @param taskInfo the task being dragged. * @param taskSurface SurfaceControl of dragged task. * @param inputCoordinate coordinates of input. Used for checks against left/right edge of screen. * @param inputX x coordinate of input. Used for checks against left/right edge of screen. * @param taskBounds bounds of dragged task. Used for checks against status bar height. */ fun onDragPositioningMove( taskInfo: RunningTaskInfo, taskSurface: SurfaceControl, inputCoordinate: PointF, inputX: Float, taskBounds: Rect ) { val displayLayout = displayController.getDisplayLayout(taskInfo.displayId) ?: return if (taskInfo.windowingMode != WINDOWING_MODE_FREEFORM) return var type = DesktopModeVisualIndicator.determineIndicatorType(inputCoordinate, taskBounds, displayLayout, context) if (type != DesktopModeVisualIndicator.INVALID_INDICATOR && visualIndicator == null) { visualIndicator = DesktopModeVisualIndicator( syncQueue, taskInfo, displayController, context, taskSurface, shellTaskOrganizer, rootTaskDisplayAreaOrganizer, type) visualIndicator?.createIndicatorWithAnimatedBounds() return updateVisualIndicator(taskInfo, taskSurface, inputX, taskBounds.top.toFloat()) } if (visualIndicator?.eventOutsideRange(inputCoordinate.x, taskBounds.top.toFloat()) == true) { releaseVisualIndicator() fun updateVisualIndicator( taskInfo: RunningTaskInfo, taskSurface: SurfaceControl, inputX: Float, taskTop: Float ) { // If the visual indicator does not exist, create it. if (visualIndicator == null) { visualIndicator = DesktopModeVisualIndicator( syncQueue, taskInfo, displayController, context, taskSurface, rootTaskDisplayAreaOrganizer) } // Then, update the indicator type. val indicator = visualIndicator ?: return indicator.updateIndicatorType(PointF(inputX, taskTop)) } /** Loading Loading @@ -935,45 +937,6 @@ class DesktopTasksController( } } /** * 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 the motion event is above the status bar and the visual indicator is not yet visible, // return since we do not need to show the visual indicator at this point. if (y < getStatusBarHeight(taskInfo) && visualIndicator == null) { return } if (visualIndicator == null) { visualIndicator = DesktopModeVisualIndicator(syncQueue, taskInfo, displayController, context, taskSurface, shellTaskOrganizer, rootTaskDisplayAreaOrganizer, TO_DESKTOP_INDICATOR) // TODO(b/301106941): don't show the indicator until the drag-to-desktop animation has // started, or it'll be visible too early on top of the task surface, especially in // the cancel-early case. Also because it shouldn't even be shown in the cancel-early // case since its dismissal is tied to the cancel animation end, which doesn't even run // in cancel-early. visualIndicator?.createIndicatorWithAnimatedBounds() } 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. * Loading @@ -991,14 +954,6 @@ class DesktopTasksController( 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) } /** * Update the exclusion region for a specified task */ Loading libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java +3 −3 File changed.Preview size limit exceeded, changes collapsed. Show changes Loading
libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicator.java +120 −145 Original line number Diff line number Diff line Loading @@ -16,6 +16,8 @@ package com.android.wm.shell.desktopmode; import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static com.android.wm.shell.desktopmode.EnterDesktopTaskTransitionHandler.FINAL_FREEFORM_SCALE; import android.animation.Animator; Loading @@ -39,7 +41,6 @@ import android.view.animation.DecelerateInterpolator; 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 @@ -48,100 +49,71 @@ import com.android.wm.shell.common.SyncTransactionQueue; * Animated visual indicator for Desktop Mode windowing transitions. */ public class DesktopModeVisualIndicator { public static final int INVALID_INDICATOR = -1; public enum IndicatorType { /** To be used when we don't want to indicate any transition */ NO_INDICATOR, /** Indicates impending transition into desktop mode */ public static final int TO_DESKTOP_INDICATOR = 1; TO_DESKTOP_INDICATOR, /** Indicates impending transition into fullscreen */ public static final int TO_FULLSCREEN_INDICATOR = 2; TO_FULLSCREEN_INDICATOR, /** Indicates impending transition into split select on the left side */ public static final int TO_SPLIT_LEFT_INDICATOR = 3; TO_SPLIT_LEFT_INDICATOR, /** Indicates impending transition into split select on the right side */ public static final int TO_SPLIT_RIGHT_INDICATOR = 4; TO_SPLIT_RIGHT_INDICATOR } private final Context mContext; private final DisplayController mDisplayController; private final ShellTaskOrganizer mTaskOrganizer; private final RootTaskDisplayAreaOrganizer mRootTdaOrganizer; private final ActivityManager.RunningTaskInfo mTaskInfo; private final SurfaceControl mTaskSurface; private final Rect mIndicatorRange = new Rect(); private SurfaceControl mLeash; private final SyncTransactionQueue mSyncQueue; private SurfaceControlViewHost mViewHost; private View mView; private boolean mIsFullscreen; private int mType; private IndicatorType mCurrentType; public DesktopModeVisualIndicator(SyncTransactionQueue syncQueue, ActivityManager.RunningTaskInfo taskInfo, DisplayController displayController, Context context, SurfaceControl taskSurface, ShellTaskOrganizer taskOrganizer, RootTaskDisplayAreaOrganizer taskDisplayAreaOrganizer, int type) { Context context, SurfaceControl taskSurface, RootTaskDisplayAreaOrganizer taskDisplayAreaOrganizer) { mSyncQueue = syncQueue; mTaskInfo = taskInfo; mDisplayController = displayController; mContext = context; mTaskSurface = taskSurface; mTaskOrganizer = taskOrganizer; mRootTdaOrganizer = taskDisplayAreaOrganizer; mType = type; defineIndicatorRange(); mCurrentType = IndicatorType.NO_INDICATOR; createView(); } /** * If an indicator is warranted based on the input and task bounds, return the type of * indicator that should be created. */ public static int determineIndicatorType(PointF inputCoordinates, Rect taskBounds, DisplayLayout layout, Context context) { int transitionAreaHeight = context.getResources().getDimensionPixelSize( com.android.wm.shell.R.dimen.desktop_mode_transition_area_height); int transitionAreaWidth = context.getResources().getDimensionPixelSize( com.android.wm.shell.R.dimen.desktop_mode_transition_area_width); if (taskBounds.top <= transitionAreaHeight) return TO_FULLSCREEN_INDICATOR; if (inputCoordinates.x <= transitionAreaWidth) return TO_SPLIT_LEFT_INDICATOR; if (inputCoordinates.x >= layout.width() - transitionAreaWidth) { return TO_SPLIT_RIGHT_INDICATOR; } return INVALID_INDICATOR; } /** * Determine range of inputs that will keep this indicator displaying. * Based on the coordinates of the current drag event, determine which indicator type we should * display, including no visible indicator. * TODO(b/280828642): Update drag zones per starting windowing mode. */ private void defineIndicatorRange() { DisplayLayout layout = mDisplayController.getDisplayLayout(mTaskInfo.displayId); int captionHeight = mContext.getResources().getDimensionPixelSize( com.android.wm.shell.R.dimen.freeform_decor_caption_height); IndicatorType updateIndicatorType(PointF inputCoordinates) { final DisplayLayout layout = mDisplayController.getDisplayLayout(mTaskInfo.displayId); // If we are in freeform, we don't want a visible indicator in the "freeform" drag zone. IndicatorType result = mTaskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM ? IndicatorType.NO_INDICATOR : IndicatorType.TO_DESKTOP_INDICATOR; int transitionAreaHeight = mContext.getResources().getDimensionPixelSize( com.android.wm.shell.R.dimen.desktop_mode_transition_area_height); int transitionAreaWidth = mContext.getResources().getDimensionPixelSize( com.android.wm.shell.R.dimen.desktop_mode_transition_area_width); switch (mType) { case TO_DESKTOP_INDICATOR: // TO_DESKTOP indicator is only dismissed on release; entire display is valid. mIndicatorRange.set(0, 0, layout.width(), layout.height()); break; case TO_FULLSCREEN_INDICATOR: // If drag results in caption going above the top edge of the display, we still // want to transition to fullscreen. mIndicatorRange.set(0, -captionHeight, layout.width(), transitionAreaHeight); break; case TO_SPLIT_LEFT_INDICATOR: mIndicatorRange.set(0, transitionAreaHeight, transitionAreaWidth, layout.height()); break; case TO_SPLIT_RIGHT_INDICATOR: mIndicatorRange.set(layout.width() - transitionAreaWidth, transitionAreaHeight, layout.width(), layout.height()); break; default: break; if (inputCoordinates.y <= transitionAreaHeight) { result = IndicatorType.TO_FULLSCREEN_INDICATOR; } else if (inputCoordinates.x <= transitionAreaWidth) { result = IndicatorType.TO_SPLIT_LEFT_INDICATOR; } else if (inputCoordinates.x >= layout.width() - transitionAreaWidth) { result = IndicatorType.TO_SPLIT_RIGHT_INDICATOR; } transitionIndicator(result); return result; } /** * Create a fullscreen indicator with no animation */ Loading @@ -156,7 +128,7 @@ public class DesktopModeVisualIndicator { final SurfaceControl.Builder builder = new SurfaceControl.Builder(); mRootTdaOrganizer.attachToDisplayArea(mTaskInfo.displayId, builder); String description; switch (mType) { switch (mCurrentType) { case TO_DESKTOP_INDICATOR: description = "Desktop indicator"; break; Loading Loading @@ -201,46 +173,45 @@ public class DesktopModeVisualIndicator { } /** * Create an indicator. Animator fades it in while expanding the bounds outwards. * Fade indicator in as provided type. Animator fades it in while expanding the bounds outwards. */ public void createIndicatorWithAnimatedBounds() { mIsFullscreen = mType == TO_FULLSCREEN_INDICATOR; private void fadeInIndicator(IndicatorType type) { mView.setBackgroundResource(R.drawable.desktop_windowing_transition_background); final VisualIndicatorAnimator animator = VisualIndicatorAnimator .animateBounds(mView, mType, .fadeBoundsIn(mView, type, mDisplayController.getDisplayLayout(mTaskInfo.displayId)); animator.start(); mCurrentType = type; } /** * Takes existing fullscreen indicator and animates it to freeform bounds * Fade out indicator without fully releasing it. Animator fades it out while shrinking bounds. */ public void transitionFullscreenIndicatorToFreeform() { mIsFullscreen = false; mType = TO_DESKTOP_INDICATOR; final VisualIndicatorAnimator animator = VisualIndicatorAnimator.toFreeformAnimator( mView, mDisplayController.getDisplayLayout(mTaskInfo.displayId)); private void fadeOutIndicator() { final VisualIndicatorAnimator animator = VisualIndicatorAnimator .fadeBoundsOut(mView, mCurrentType, mDisplayController.getDisplayLayout(mTaskInfo.displayId)); animator.start(); mCurrentType = IndicatorType.NO_INDICATOR; } /** * Takes the existing freeform indicator and animates it to fullscreen * Takes existing indicator and animates it to bounds reflecting a new indicator type. */ public void transitionFreeformIndicatorToFullscreen() { mIsFullscreen = true; mType = TO_FULLSCREEN_INDICATOR; final VisualIndicatorAnimator animator = VisualIndicatorAnimator.toFullscreenAnimatorWithAnimatedBounds( mView, mDisplayController.getDisplayLayout(mTaskInfo.displayId)); private void transitionIndicator(IndicatorType newType) { if (mCurrentType == newType) return; if (mCurrentType == IndicatorType.NO_INDICATOR) { fadeInIndicator(newType); } else if (newType == IndicatorType.NO_INDICATOR) { fadeOutIndicator(); } else { final VisualIndicatorAnimator animator = VisualIndicatorAnimator.animateIndicatorType( mView, mDisplayController.getDisplayLayout(mTaskInfo.displayId), mCurrentType, newType); mCurrentType = newType; animator.start(); } /** * Determine if a MotionEvent is in the same range that enabled the indicator. * Used to dismiss the indicator when a transition will no longer result from releasing. */ public boolean eventOutsideRange(float x, float y) { return !mIndicatorRange.contains((int) x, (int) y); } /** Loading @@ -259,13 +230,6 @@ 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. */ Loading @@ -274,6 +238,13 @@ public class DesktopModeVisualIndicator { private static final float FULLSCREEN_SCALE_ADJUSTMENT_PERCENT = 0.015f; private static final float INDICATOR_FINAL_OPACITY = 0.7f; /** Determines how this animator will interact with the view's alpha: * Fade in, fade out, or no change to alpha */ private enum AlphaAnimType{ ALPHA_FADE_IN_ANIM, ALPHA_FADE_OUT_ANIM, ALPHA_NO_CHANGE_ANIM } private final View mView; private final Rect mStartBounds; private final Rect mEndBounds; Loading @@ -288,87 +259,91 @@ public class DesktopModeVisualIndicator { mRectEvaluator = new RectEvaluator(new Rect()); } /** * 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); private static VisualIndicatorAnimator fadeBoundsIn( @NonNull View view, IndicatorType type, @NonNull DisplayLayout displayLayout) { final Rect startBounds = getIndicatorBounds(displayLayout, type); view.getBackground().setBounds(startBounds); final VisualIndicatorAnimator animator = new VisualIndicatorAnimator( view, startBounds, getMaxBounds(startBounds)); animator.setInterpolator(new DecelerateInterpolator()); setupIndicatorAnimation(animator); setupIndicatorAnimation(animator, AlphaAnimType.ALPHA_FADE_IN_ANIM); return animator; } public static VisualIndicatorAnimator animateBounds( @NonNull View view, int type, @NonNull DisplayLayout displayLayout) { final int padding = displayLayout.stableInsets().top; Rect startBounds = new Rect(); switch (type) { case TO_FULLSCREEN_INDICATOR: startBounds.set(padding, padding, displayLayout.width() - padding, displayLayout.height() - padding); break; case TO_SPLIT_LEFT_INDICATOR: startBounds.set(padding, padding, displayLayout.width() / 2 - padding, displayLayout.height() - padding); break; case TO_SPLIT_RIGHT_INDICATOR: startBounds.set(displayLayout.width() / 2 + padding, padding, displayLayout.width() - padding, displayLayout.height() - padding); break; } private static VisualIndicatorAnimator fadeBoundsOut( @NonNull View view, IndicatorType type, @NonNull DisplayLayout displayLayout) { final Rect endBounds = getIndicatorBounds(displayLayout, type); final Rect startBounds = getMaxBounds(endBounds); view.getBackground().setBounds(startBounds); final VisualIndicatorAnimator animator = new VisualIndicatorAnimator( view, startBounds, getMaxBounds(startBounds)); view, startBounds, endBounds); animator.setInterpolator(new DecelerateInterpolator()); setupIndicatorAnimation(animator); setupIndicatorAnimation(animator, AlphaAnimType.ALPHA_FADE_OUT_ANIM); return animator; } /** * Create animator for visual indicator of freeform transition * Create animator for visual indicator changing type (i.e., fullscreen to freeform, * freeform to split, etc.) * * @param view the view for this indicator * @param displayLayout information about the display the transitioning task is currently on * @param origType the original indicator type * @param newType the new indicator type */ 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 startBounds = new Rect(0, 0, width, 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))); private static VisualIndicatorAnimator animateIndicatorType(@NonNull View view, @NonNull DisplayLayout displayLayout, IndicatorType origType, IndicatorType newType) { final Rect startBounds = getIndicatorBounds(displayLayout, origType); final Rect endBounds = getIndicatorBounds(displayLayout, newType); final VisualIndicatorAnimator animator = new VisualIndicatorAnimator( view, startBounds, endBounds); animator.setInterpolator(new DecelerateInterpolator()); setupIndicatorAnimation(animator); setupIndicatorAnimation(animator, AlphaAnimType.ALPHA_NO_CHANGE_ANIM); return animator; } private static Rect getIndicatorBounds(DisplayLayout layout, IndicatorType type) { final int padding = layout.stableInsets().top; switch (type) { case TO_FULLSCREEN_INDICATOR: return new Rect(padding, padding, layout.width() - padding, layout.height() - padding); case TO_DESKTOP_INDICATOR: final float adjustmentPercentage = 1f - FINAL_FREEFORM_SCALE; return new Rect((int) (adjustmentPercentage * layout.width() / 2), (int) (adjustmentPercentage * layout.height() / 2), (int) (layout.width() - (adjustmentPercentage * layout.width() / 2)), (int) (layout.height() - (adjustmentPercentage * layout.height() / 2))); case TO_SPLIT_LEFT_INDICATOR: return new Rect(padding, padding, layout.width() / 2 - padding, layout.height() - padding); case TO_SPLIT_RIGHT_INDICATOR: return new Rect(layout.width() / 2 + padding, padding, layout.width() - padding, layout.height() - padding); default: throw new IllegalArgumentException("Invalid indicator type provided."); } } /** * Add necessary listener for animation of indicator */ private static void setupIndicatorAnimation(@NonNull VisualIndicatorAnimator animator) { private static void setupIndicatorAnimation(@NonNull VisualIndicatorAnimator animator, AlphaAnimType animType) { animator.addUpdateListener(a -> { if (animator.mView != null) { animator.updateBounds(a.getAnimatedFraction(), animator.mView); if (animType == AlphaAnimType.ALPHA_FADE_IN_ANIM) { animator.updateIndicatorAlpha(a.getAnimatedFraction(), animator.mView); } else if (animType == AlphaAnimType.ALPHA_FADE_OUT_ANIM) { animator.updateIndicatorAlpha(1 - a.getAnimatedFraction(), animator.mView); } } else { animator.cancel(); } Loading @@ -394,7 +369,7 @@ public class DesktopModeVisualIndicator { if (mStartBounds.equals(mEndBounds)) { return; } Rect currentBounds = mRectEvaluator.evaluate(fraction, mStartBounds, mEndBounds); final Rect currentBounds = mRectEvaluator.evaluate(fraction, mStartBounds, mEndBounds); view.getBackground().setBounds(currentBounds); } Loading
libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt +18 −63 Original line number Diff line number Diff line Loading @@ -57,7 +57,6 @@ import com.android.wm.shell.common.annotations.ShellMainThread import com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT import com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT import com.android.wm.shell.desktopmode.DesktopModeTaskRepository.VisibleTasksListener import com.android.wm.shell.desktopmode.DesktopModeVisualIndicator.TO_DESKTOP_INDICATOR import com.android.wm.shell.desktopmode.DragToDesktopTransitionHandler.DragToDesktopStateListener import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE import com.android.wm.shell.recents.RecentsTransitionHandler Loading Loading @@ -871,31 +870,34 @@ class DesktopTasksController( * * @param taskInfo the task being dragged. * @param taskSurface SurfaceControl of dragged task. * @param inputCoordinate coordinates of input. Used for checks against left/right edge of screen. * @param inputX x coordinate of input. Used for checks against left/right edge of screen. * @param taskBounds bounds of dragged task. Used for checks against status bar height. */ fun onDragPositioningMove( taskInfo: RunningTaskInfo, taskSurface: SurfaceControl, inputCoordinate: PointF, inputX: Float, taskBounds: Rect ) { val displayLayout = displayController.getDisplayLayout(taskInfo.displayId) ?: return if (taskInfo.windowingMode != WINDOWING_MODE_FREEFORM) return var type = DesktopModeVisualIndicator.determineIndicatorType(inputCoordinate, taskBounds, displayLayout, context) if (type != DesktopModeVisualIndicator.INVALID_INDICATOR && visualIndicator == null) { visualIndicator = DesktopModeVisualIndicator( syncQueue, taskInfo, displayController, context, taskSurface, shellTaskOrganizer, rootTaskDisplayAreaOrganizer, type) visualIndicator?.createIndicatorWithAnimatedBounds() return updateVisualIndicator(taskInfo, taskSurface, inputX, taskBounds.top.toFloat()) } if (visualIndicator?.eventOutsideRange(inputCoordinate.x, taskBounds.top.toFloat()) == true) { releaseVisualIndicator() fun updateVisualIndicator( taskInfo: RunningTaskInfo, taskSurface: SurfaceControl, inputX: Float, taskTop: Float ) { // If the visual indicator does not exist, create it. if (visualIndicator == null) { visualIndicator = DesktopModeVisualIndicator( syncQueue, taskInfo, displayController, context, taskSurface, rootTaskDisplayAreaOrganizer) } // Then, update the indicator type. val indicator = visualIndicator ?: return indicator.updateIndicatorType(PointF(inputX, taskTop)) } /** Loading Loading @@ -935,45 +937,6 @@ class DesktopTasksController( } } /** * 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 the motion event is above the status bar and the visual indicator is not yet visible, // return since we do not need to show the visual indicator at this point. if (y < getStatusBarHeight(taskInfo) && visualIndicator == null) { return } if (visualIndicator == null) { visualIndicator = DesktopModeVisualIndicator(syncQueue, taskInfo, displayController, context, taskSurface, shellTaskOrganizer, rootTaskDisplayAreaOrganizer, TO_DESKTOP_INDICATOR) // TODO(b/301106941): don't show the indicator until the drag-to-desktop animation has // started, or it'll be visible too early on top of the task surface, especially in // the cancel-early case. Also because it shouldn't even be shown in the cancel-early // case since its dismissal is tied to the cancel animation end, which doesn't even run // in cancel-early. visualIndicator?.createIndicatorWithAnimatedBounds() } 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. * Loading @@ -991,14 +954,6 @@ class DesktopTasksController( 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) } /** * Update the exclusion region for a specified task */ Loading
libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java +3 −3 File changed.Preview size limit exceeded, changes collapsed. Show changes