Loading libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.java +15 −8 Original line number Diff line number Diff line Loading @@ -70,8 +70,8 @@ class HandleMenu { private int mMarginMenuStart; private int mMenuHeight; private int mMenuWidth; private final int mCaptionHeight; private HandleMenuAnimator mHandleMenuAnimator; HandleMenu(WindowDecoration parentDecor, int layoutResId, int captionX, int captionY, Loading Loading @@ -111,20 +111,19 @@ class HandleMenu { mHandleMenuWindow = mParentDecor.addWindow( R.layout.desktop_mode_window_decor_handle_menu, "Handle Menu", t, ssg, x, y, mMenuWidth, mMenuHeight); final View handleMenuView = mHandleMenuWindow.mWindowViewHost.getView(); mHandleMenuAnimator = new HandleMenuAnimator(handleMenuView, mMenuWidth, mCaptionHeight); } /** * Animates the appearance of the handle menu and its three pills. */ private void animateHandleMenu() { final View handleMenuView = mHandleMenuWindow.mWindowViewHost.getView(); final HandleMenuAnimator handleMenuAnimator = new HandleMenuAnimator(handleMenuView, mMenuWidth, mCaptionHeight); if (mTaskInfo.getWindowingMode() == WINDOWING_MODE_FULLSCREEN || mTaskInfo.getWindowingMode() == WINDOWING_MODE_MULTI_WINDOW) { handleMenuAnimator.animateCaptionHandleExpandToOpen(); mHandleMenuAnimator.animateCaptionHandleExpandToOpen(); } else { handleMenuAnimator.animateOpen(); mHandleMenuAnimator.animateOpen(); } } Loading Loading @@ -328,8 +327,16 @@ class HandleMenu { } void close() { final Runnable after = () -> { mHandleMenuWindow.releaseView(); mHandleMenuWindow = null; }; if (mTaskInfo.getWindowingMode() == WINDOWING_MODE_FULLSCREEN || mTaskInfo.getWindowingMode() == WINDOWING_MODE_MULTI_WINDOW) { mHandleMenuAnimator.animateCollapseIntoHandleClose(after); } else { mHandleMenuAnimator.animateClose(after); } } static final class Builder { Loading libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenuAnimator.kt +218 −58 Original line number Diff line number Diff line Loading @@ -26,6 +26,7 @@ import android.view.View.SCALE_Y import android.view.View.TRANSLATION_Y import android.view.View.TRANSLATION_Z import android.view.ViewGroup import androidx.core.animation.doOnEnd import androidx.core.view.children import com.android.wm.shell.R import com.android.wm.shell.animation.Interpolators Loading @@ -37,27 +38,36 @@ class HandleMenuAnimator( private val captionHeight: Float ) { companion object { private const val MENU_Y_TRANSLATION_DURATION: Long = 150 private const val HEADER_NONFREEFORM_SCALE_DURATION: Long = 150 private const val HEADER_FREEFORM_SCALE_DURATION: Long = 217 private const val HEADER_ELEVATION_DURATION: Long = 83 private const val HEADER_CONTENT_ALPHA_DURATION: Long = 100 private const val BODY_SCALE_DURATION: Long = 180 private const val BODY_ALPHA_DURATION: Long = 150 private const val BODY_ELEVATION_DURATION: Long = 83 private const val BODY_CONTENT_ALPHA_DURATION: Long = 167 private const val ELEVATION_DELAY: Long = 33 private const val HEADER_CONTENT_ALPHA_DELAY: Long = 67 private const val BODY_SCALE_DELAY: Long = 50 private const val BODY_ALPHA_DELAY: Long = 133 // Open animation constants private const val MENU_Y_TRANSLATION_OPEN_DURATION: Long = 150 private const val HEADER_NONFREEFORM_SCALE_OPEN_DURATION: Long = 150 private const val HEADER_FREEFORM_SCALE_OPEN_DURATION: Long = 217 private const val HEADER_ELEVATION_OPEN_DURATION: Long = 83 private const val HEADER_CONTENT_ALPHA_OPEN_DURATION: Long = 100 private const val BODY_SCALE_OPEN_DURATION: Long = 180 private const val BODY_ALPHA_OPEN_DURATION: Long = 150 private const val BODY_ELEVATION_OPEN_DURATION: Long = 83 private const val BODY_CONTENT_ALPHA_OPEN_DURATION: Long = 167 private const val ELEVATION_OPEN_DELAY: Long = 33 private const val HEADER_CONTENT_ALPHA_OPEN_DELAY: Long = 67 private const val BODY_SCALE_OPEN_DELAY: Long = 50 private const val BODY_ALPHA_OPEN_DELAY: Long = 133 private const val HALF_INITIAL_SCALE: Float = 0.5f private const val NONFREEFORM_HEADER_INITIAL_SCALE_X: Float = 0.6f private const val NONFREEFORM_HEADER_INITIAL_SCALE_Y: Float = 0.05f // Close animation constants private const val HEADER_CLOSE_DELAY: Long = 20 private const val HEADER_CLOSE_DURATION: Long = 50 private const val HEADER_CONTENT_OPACITY_CLOSE_DELAY: Long = 25 private const val HEADER_CONTENT_OPACITY_CLOSE_DURATION: Long = 25 private const val BODY_CLOSE_DURATION: Long = 50 } private val animators: MutableList<Animator> = mutableListOf() private var runningAnimation: AnimatorSet? = null private val appInfoPill: ViewGroup = handleMenu.requireViewById(R.id.app_info_pill) private val windowingPill: ViewGroup = handleMenu.requireViewById(R.id.windowing_pill) Loading @@ -67,9 +77,9 @@ class HandleMenuAnimator( fun animateOpen() { prepareMenuForAnimation() appInfoPillExpand() animateAppInfoPill() animateWindowingPill() animateMoreActionsPill() animateAppInfoPillOpen() animateWindowingPillOpen() animateMoreActionsPillOpen() runAnimations() } Loading @@ -81,12 +91,43 @@ class HandleMenuAnimator( fun animateCaptionHandleExpandToOpen() { prepareMenuForAnimation() captionHandleExpandIntoAppInfoPill() animateAppInfoPill() animateWindowingPill() animateMoreActionsPill() animateAppInfoPillOpen() animateWindowingPillOpen() animateMoreActionsPillOpen() runAnimations() } /** * Animates the closing of the handle menu. The windowing and more actions pill vanish. Then, * the app info pill will collapse into the shape of the caption handle in full screen and split * screen. * * @param after runs after the animation finishes. */ fun animateCollapseIntoHandleClose(after: Runnable) { appInfoCollapseToHandle() animateAppInfoPillFadeOut() windowingPillClose() moreActionsPillClose() runAnimations(after) } /** * Animates the closing of the handle menu. The windowing and more actions pill vanish. Then, * the app info pill will collapse into the shape of the caption handle in full screen and split * screen. * * @param after runs after animation finishes. * */ fun animateClose(after: Runnable) { appInfoPillCollapse() animateAppInfoPillFadeOut() windowingPillClose() moreActionsPillClose() runAnimations(after) } /** * Prepares the handle menu for animation. Presets the opacity of necessary menu components. * Presets pivots of handle menu and body pills for scaling animation. Loading @@ -108,20 +149,20 @@ class HandleMenuAnimator( moreActionsPill.pivotY = appInfoPill.measuredHeight.toFloat() } private fun animateAppInfoPill() { private fun animateAppInfoPillOpen() { // Header Elevation Animation animators += ObjectAnimator.ofFloat(appInfoPill, TRANSLATION_Z, 1f).apply { startDelay = ELEVATION_DELAY duration = HEADER_ELEVATION_DURATION startDelay = ELEVATION_OPEN_DELAY duration = HEADER_ELEVATION_OPEN_DURATION } // Content Opacity Animation appInfoPill.children.forEach { animators += ObjectAnimator.ofFloat(it, ALPHA, 1f).apply { startDelay = HEADER_CONTENT_ALPHA_DELAY duration = HEADER_CONTENT_ALPHA_DURATION startDelay = HEADER_CONTENT_ALPHA_OPEN_DELAY duration = HEADER_CONTENT_ALPHA_OPEN_DURATION } } } Loading @@ -130,17 +171,17 @@ class HandleMenuAnimator( // Header scaling animation animators += ObjectAnimator.ofFloat(appInfoPill, SCALE_X, NONFREEFORM_HEADER_INITIAL_SCALE_X, 1f) .apply { duration = HEADER_NONFREEFORM_SCALE_DURATION } .apply { duration = HEADER_NONFREEFORM_SCALE_OPEN_DURATION } animators += ObjectAnimator.ofFloat(appInfoPill, SCALE_Y, NONFREEFORM_HEADER_INITIAL_SCALE_Y, 1f) .apply { duration = HEADER_NONFREEFORM_SCALE_DURATION } .apply { duration = HEADER_NONFREEFORM_SCALE_OPEN_DURATION } // Downward y-translation animation val yStart: Float = -captionHeight / 2 animators += ObjectAnimator.ofFloat(handleMenu, TRANSLATION_Y, yStart, 0f).apply { duration = MENU_Y_TRANSLATION_DURATION duration = MENU_Y_TRANSLATION_OPEN_DURATION } } Loading @@ -148,98 +189,217 @@ class HandleMenuAnimator( // Header scaling animation animators += ObjectAnimator.ofFloat(appInfoPill, SCALE_X, HALF_INITIAL_SCALE, 1f).apply { duration = HEADER_FREEFORM_SCALE_DURATION duration = HEADER_FREEFORM_SCALE_OPEN_DURATION } animators += ObjectAnimator.ofFloat(appInfoPill, SCALE_Y, HALF_INITIAL_SCALE, 1f).apply { duration = HEADER_FREEFORM_SCALE_DURATION duration = HEADER_FREEFORM_SCALE_OPEN_DURATION } } private fun animateWindowingPill() { private fun animateWindowingPillOpen() { // Windowing X & Y Scaling Animation animators += ObjectAnimator.ofFloat(windowingPill, SCALE_X, HALF_INITIAL_SCALE, 1f).apply { startDelay = BODY_SCALE_DELAY duration = BODY_SCALE_DURATION startDelay = BODY_SCALE_OPEN_DELAY duration = BODY_SCALE_OPEN_DURATION } animators += ObjectAnimator.ofFloat(windowingPill, SCALE_Y, HALF_INITIAL_SCALE, 1f).apply { startDelay = BODY_SCALE_DELAY duration = BODY_SCALE_DURATION startDelay = BODY_SCALE_OPEN_DELAY duration = BODY_SCALE_OPEN_DURATION } // Windowing Opacity Animation animators += ObjectAnimator.ofFloat(windowingPill, ALPHA, 1f).apply { startDelay = BODY_ALPHA_DELAY duration = BODY_ALPHA_DURATION startDelay = BODY_ALPHA_OPEN_DELAY duration = BODY_ALPHA_OPEN_DURATION } // Windowing Elevation Animation animators += ObjectAnimator.ofFloat(windowingPill, TRANSLATION_Z, 1f).apply { startDelay = ELEVATION_DELAY duration = BODY_ELEVATION_DURATION startDelay = ELEVATION_OPEN_DELAY duration = BODY_ELEVATION_OPEN_DURATION } // Windowing Content Opacity Animation windowingPill.children.forEach { animators += ObjectAnimator.ofFloat(it, ALPHA, 1f).apply { startDelay = BODY_ALPHA_DELAY duration = BODY_CONTENT_ALPHA_DURATION startDelay = BODY_ALPHA_OPEN_DELAY duration = BODY_CONTENT_ALPHA_OPEN_DURATION interpolator = Interpolators.FAST_OUT_SLOW_IN } } } private fun animateMoreActionsPill() { private fun animateMoreActionsPillOpen() { // More Actions X & Y Scaling Animation animators += ObjectAnimator.ofFloat(moreActionsPill, SCALE_X, HALF_INITIAL_SCALE, 1f).apply { startDelay = BODY_SCALE_DELAY duration = BODY_SCALE_DURATION startDelay = BODY_SCALE_OPEN_DELAY duration = BODY_SCALE_OPEN_DURATION } animators += ObjectAnimator.ofFloat(moreActionsPill, SCALE_Y, HALF_INITIAL_SCALE, 1f).apply { startDelay = BODY_SCALE_DELAY duration = BODY_SCALE_DURATION startDelay = BODY_SCALE_OPEN_DELAY duration = BODY_SCALE_OPEN_DURATION } // More Actions Opacity Animation animators += ObjectAnimator.ofFloat(moreActionsPill, ALPHA, 1f).apply { startDelay = BODY_ALPHA_DELAY duration = BODY_ALPHA_DURATION startDelay = BODY_ALPHA_OPEN_DELAY duration = BODY_ALPHA_OPEN_DURATION } // More Actions Elevation Animation animators += ObjectAnimator.ofFloat(moreActionsPill, TRANSLATION_Z, 1f).apply { startDelay = ELEVATION_DELAY duration = BODY_ELEVATION_DURATION startDelay = ELEVATION_OPEN_DELAY duration = BODY_ELEVATION_OPEN_DURATION } // More Actions Content Opacity Animation moreActionsPill.children.forEach { animators += ObjectAnimator.ofFloat(it, ALPHA, 1f).apply { startDelay = BODY_ALPHA_DELAY duration = BODY_CONTENT_ALPHA_DURATION startDelay = BODY_ALPHA_OPEN_DELAY duration = BODY_CONTENT_ALPHA_OPEN_DURATION interpolator = Interpolators.FAST_OUT_SLOW_IN } } } /** Runs the list of animators concurrently. */ private fun runAnimations() { val animatorSet = AnimatorSet() animatorSet.playTogether(animators) animatorSet.start() private fun appInfoPillCollapse() { // Header scaling animation animators += ObjectAnimator.ofFloat(appInfoPill, SCALE_X, 0f).apply { startDelay = HEADER_CLOSE_DELAY duration = HEADER_CLOSE_DURATION } animators += ObjectAnimator.ofFloat(appInfoPill, SCALE_Y, 0f).apply { startDelay = HEADER_CLOSE_DELAY duration = HEADER_CLOSE_DURATION } } private fun appInfoCollapseToHandle() { // Header X & Y Scaling Animation animators += ObjectAnimator.ofFloat(appInfoPill, SCALE_X, NONFREEFORM_HEADER_INITIAL_SCALE_X).apply { startDelay = HEADER_CLOSE_DELAY duration = HEADER_CLOSE_DURATION } animators += ObjectAnimator.ofFloat(appInfoPill, SCALE_Y, NONFREEFORM_HEADER_INITIAL_SCALE_Y).apply { startDelay = HEADER_CLOSE_DELAY duration = HEADER_CLOSE_DURATION } // Upward y-translation animation val yStart: Float = -captionHeight / 2 animators += ObjectAnimator.ofFloat(appInfoPill, TRANSLATION_Y, yStart).apply { startDelay = HEADER_CLOSE_DELAY duration = HEADER_CLOSE_DURATION } } private fun animateAppInfoPillFadeOut() { // Header Content Opacity Animation appInfoPill.children.forEach { animators += ObjectAnimator.ofFloat(it, ALPHA, 0f).apply { startDelay = HEADER_CONTENT_OPACITY_CLOSE_DELAY duration = HEADER_CONTENT_OPACITY_CLOSE_DURATION } } } private fun windowingPillClose() { // Windowing X & Y Scaling Animation animators += ObjectAnimator.ofFloat(windowingPill, SCALE_X, HALF_INITIAL_SCALE).apply { duration = BODY_CLOSE_DURATION } animators += ObjectAnimator.ofFloat(windowingPill, SCALE_Y, HALF_INITIAL_SCALE).apply { duration = BODY_CLOSE_DURATION } // windowing Animation animators += ObjectAnimator.ofFloat(windowingPill, ALPHA, 0f).apply { duration = BODY_CLOSE_DURATION } animators += ObjectAnimator.ofFloat(windowingPill, ALPHA, 0f).apply { duration = BODY_CLOSE_DURATION } } private fun moreActionsPillClose() { // More Actions X & Y Scaling Animation animators += ObjectAnimator.ofFloat(moreActionsPill, SCALE_X, HALF_INITIAL_SCALE).apply { duration = BODY_CLOSE_DURATION } animators += ObjectAnimator.ofFloat(moreActionsPill, SCALE_Y, HALF_INITIAL_SCALE).apply { duration = BODY_CLOSE_DURATION } // More Actions Opacity Animation animators += ObjectAnimator.ofFloat(moreActionsPill, ALPHA, 0f).apply { duration = BODY_CLOSE_DURATION } animators += ObjectAnimator.ofFloat(moreActionsPill, ALPHA, 0f).apply { duration = BODY_CLOSE_DURATION } // upward more actions pill y-translation animation val yStart: Float = -captionHeight / 2 animators += ObjectAnimator.ofFloat(moreActionsPill, TRANSLATION_Y, yStart).apply { duration = BODY_CLOSE_DURATION } } /** * Runs the list of hide animators concurrently. * * @param after runs after animation finishes. */ private fun runAnimations(after: Runnable? = null) { runningAnimation?.apply { // Remove all listeners, so that after runnable isn't triggered upon cancel. removeAllListeners() // If an animation runs while running animation is triggered, gracefully cancel. cancel() } runningAnimation = AnimatorSet().apply { playTogether(animators) animators.clear() doOnEnd { after?.run() runningAnimation = null } start() } } } Loading
libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.java +15 −8 Original line number Diff line number Diff line Loading @@ -70,8 +70,8 @@ class HandleMenu { private int mMarginMenuStart; private int mMenuHeight; private int mMenuWidth; private final int mCaptionHeight; private HandleMenuAnimator mHandleMenuAnimator; HandleMenu(WindowDecoration parentDecor, int layoutResId, int captionX, int captionY, Loading Loading @@ -111,20 +111,19 @@ class HandleMenu { mHandleMenuWindow = mParentDecor.addWindow( R.layout.desktop_mode_window_decor_handle_menu, "Handle Menu", t, ssg, x, y, mMenuWidth, mMenuHeight); final View handleMenuView = mHandleMenuWindow.mWindowViewHost.getView(); mHandleMenuAnimator = new HandleMenuAnimator(handleMenuView, mMenuWidth, mCaptionHeight); } /** * Animates the appearance of the handle menu and its three pills. */ private void animateHandleMenu() { final View handleMenuView = mHandleMenuWindow.mWindowViewHost.getView(); final HandleMenuAnimator handleMenuAnimator = new HandleMenuAnimator(handleMenuView, mMenuWidth, mCaptionHeight); if (mTaskInfo.getWindowingMode() == WINDOWING_MODE_FULLSCREEN || mTaskInfo.getWindowingMode() == WINDOWING_MODE_MULTI_WINDOW) { handleMenuAnimator.animateCaptionHandleExpandToOpen(); mHandleMenuAnimator.animateCaptionHandleExpandToOpen(); } else { handleMenuAnimator.animateOpen(); mHandleMenuAnimator.animateOpen(); } } Loading Loading @@ -328,8 +327,16 @@ class HandleMenu { } void close() { final Runnable after = () -> { mHandleMenuWindow.releaseView(); mHandleMenuWindow = null; }; if (mTaskInfo.getWindowingMode() == WINDOWING_MODE_FULLSCREEN || mTaskInfo.getWindowingMode() == WINDOWING_MODE_MULTI_WINDOW) { mHandleMenuAnimator.animateCollapseIntoHandleClose(after); } else { mHandleMenuAnimator.animateClose(after); } } static final class Builder { Loading
libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenuAnimator.kt +218 −58 Original line number Diff line number Diff line Loading @@ -26,6 +26,7 @@ import android.view.View.SCALE_Y import android.view.View.TRANSLATION_Y import android.view.View.TRANSLATION_Z import android.view.ViewGroup import androidx.core.animation.doOnEnd import androidx.core.view.children import com.android.wm.shell.R import com.android.wm.shell.animation.Interpolators Loading @@ -37,27 +38,36 @@ class HandleMenuAnimator( private val captionHeight: Float ) { companion object { private const val MENU_Y_TRANSLATION_DURATION: Long = 150 private const val HEADER_NONFREEFORM_SCALE_DURATION: Long = 150 private const val HEADER_FREEFORM_SCALE_DURATION: Long = 217 private const val HEADER_ELEVATION_DURATION: Long = 83 private const val HEADER_CONTENT_ALPHA_DURATION: Long = 100 private const val BODY_SCALE_DURATION: Long = 180 private const val BODY_ALPHA_DURATION: Long = 150 private const val BODY_ELEVATION_DURATION: Long = 83 private const val BODY_CONTENT_ALPHA_DURATION: Long = 167 private const val ELEVATION_DELAY: Long = 33 private const val HEADER_CONTENT_ALPHA_DELAY: Long = 67 private const val BODY_SCALE_DELAY: Long = 50 private const val BODY_ALPHA_DELAY: Long = 133 // Open animation constants private const val MENU_Y_TRANSLATION_OPEN_DURATION: Long = 150 private const val HEADER_NONFREEFORM_SCALE_OPEN_DURATION: Long = 150 private const val HEADER_FREEFORM_SCALE_OPEN_DURATION: Long = 217 private const val HEADER_ELEVATION_OPEN_DURATION: Long = 83 private const val HEADER_CONTENT_ALPHA_OPEN_DURATION: Long = 100 private const val BODY_SCALE_OPEN_DURATION: Long = 180 private const val BODY_ALPHA_OPEN_DURATION: Long = 150 private const val BODY_ELEVATION_OPEN_DURATION: Long = 83 private const val BODY_CONTENT_ALPHA_OPEN_DURATION: Long = 167 private const val ELEVATION_OPEN_DELAY: Long = 33 private const val HEADER_CONTENT_ALPHA_OPEN_DELAY: Long = 67 private const val BODY_SCALE_OPEN_DELAY: Long = 50 private const val BODY_ALPHA_OPEN_DELAY: Long = 133 private const val HALF_INITIAL_SCALE: Float = 0.5f private const val NONFREEFORM_HEADER_INITIAL_SCALE_X: Float = 0.6f private const val NONFREEFORM_HEADER_INITIAL_SCALE_Y: Float = 0.05f // Close animation constants private const val HEADER_CLOSE_DELAY: Long = 20 private const val HEADER_CLOSE_DURATION: Long = 50 private const val HEADER_CONTENT_OPACITY_CLOSE_DELAY: Long = 25 private const val HEADER_CONTENT_OPACITY_CLOSE_DURATION: Long = 25 private const val BODY_CLOSE_DURATION: Long = 50 } private val animators: MutableList<Animator> = mutableListOf() private var runningAnimation: AnimatorSet? = null private val appInfoPill: ViewGroup = handleMenu.requireViewById(R.id.app_info_pill) private val windowingPill: ViewGroup = handleMenu.requireViewById(R.id.windowing_pill) Loading @@ -67,9 +77,9 @@ class HandleMenuAnimator( fun animateOpen() { prepareMenuForAnimation() appInfoPillExpand() animateAppInfoPill() animateWindowingPill() animateMoreActionsPill() animateAppInfoPillOpen() animateWindowingPillOpen() animateMoreActionsPillOpen() runAnimations() } Loading @@ -81,12 +91,43 @@ class HandleMenuAnimator( fun animateCaptionHandleExpandToOpen() { prepareMenuForAnimation() captionHandleExpandIntoAppInfoPill() animateAppInfoPill() animateWindowingPill() animateMoreActionsPill() animateAppInfoPillOpen() animateWindowingPillOpen() animateMoreActionsPillOpen() runAnimations() } /** * Animates the closing of the handle menu. The windowing and more actions pill vanish. Then, * the app info pill will collapse into the shape of the caption handle in full screen and split * screen. * * @param after runs after the animation finishes. */ fun animateCollapseIntoHandleClose(after: Runnable) { appInfoCollapseToHandle() animateAppInfoPillFadeOut() windowingPillClose() moreActionsPillClose() runAnimations(after) } /** * Animates the closing of the handle menu. The windowing and more actions pill vanish. Then, * the app info pill will collapse into the shape of the caption handle in full screen and split * screen. * * @param after runs after animation finishes. * */ fun animateClose(after: Runnable) { appInfoPillCollapse() animateAppInfoPillFadeOut() windowingPillClose() moreActionsPillClose() runAnimations(after) } /** * Prepares the handle menu for animation. Presets the opacity of necessary menu components. * Presets pivots of handle menu and body pills for scaling animation. Loading @@ -108,20 +149,20 @@ class HandleMenuAnimator( moreActionsPill.pivotY = appInfoPill.measuredHeight.toFloat() } private fun animateAppInfoPill() { private fun animateAppInfoPillOpen() { // Header Elevation Animation animators += ObjectAnimator.ofFloat(appInfoPill, TRANSLATION_Z, 1f).apply { startDelay = ELEVATION_DELAY duration = HEADER_ELEVATION_DURATION startDelay = ELEVATION_OPEN_DELAY duration = HEADER_ELEVATION_OPEN_DURATION } // Content Opacity Animation appInfoPill.children.forEach { animators += ObjectAnimator.ofFloat(it, ALPHA, 1f).apply { startDelay = HEADER_CONTENT_ALPHA_DELAY duration = HEADER_CONTENT_ALPHA_DURATION startDelay = HEADER_CONTENT_ALPHA_OPEN_DELAY duration = HEADER_CONTENT_ALPHA_OPEN_DURATION } } } Loading @@ -130,17 +171,17 @@ class HandleMenuAnimator( // Header scaling animation animators += ObjectAnimator.ofFloat(appInfoPill, SCALE_X, NONFREEFORM_HEADER_INITIAL_SCALE_X, 1f) .apply { duration = HEADER_NONFREEFORM_SCALE_DURATION } .apply { duration = HEADER_NONFREEFORM_SCALE_OPEN_DURATION } animators += ObjectAnimator.ofFloat(appInfoPill, SCALE_Y, NONFREEFORM_HEADER_INITIAL_SCALE_Y, 1f) .apply { duration = HEADER_NONFREEFORM_SCALE_DURATION } .apply { duration = HEADER_NONFREEFORM_SCALE_OPEN_DURATION } // Downward y-translation animation val yStart: Float = -captionHeight / 2 animators += ObjectAnimator.ofFloat(handleMenu, TRANSLATION_Y, yStart, 0f).apply { duration = MENU_Y_TRANSLATION_DURATION duration = MENU_Y_TRANSLATION_OPEN_DURATION } } Loading @@ -148,98 +189,217 @@ class HandleMenuAnimator( // Header scaling animation animators += ObjectAnimator.ofFloat(appInfoPill, SCALE_X, HALF_INITIAL_SCALE, 1f).apply { duration = HEADER_FREEFORM_SCALE_DURATION duration = HEADER_FREEFORM_SCALE_OPEN_DURATION } animators += ObjectAnimator.ofFloat(appInfoPill, SCALE_Y, HALF_INITIAL_SCALE, 1f).apply { duration = HEADER_FREEFORM_SCALE_DURATION duration = HEADER_FREEFORM_SCALE_OPEN_DURATION } } private fun animateWindowingPill() { private fun animateWindowingPillOpen() { // Windowing X & Y Scaling Animation animators += ObjectAnimator.ofFloat(windowingPill, SCALE_X, HALF_INITIAL_SCALE, 1f).apply { startDelay = BODY_SCALE_DELAY duration = BODY_SCALE_DURATION startDelay = BODY_SCALE_OPEN_DELAY duration = BODY_SCALE_OPEN_DURATION } animators += ObjectAnimator.ofFloat(windowingPill, SCALE_Y, HALF_INITIAL_SCALE, 1f).apply { startDelay = BODY_SCALE_DELAY duration = BODY_SCALE_DURATION startDelay = BODY_SCALE_OPEN_DELAY duration = BODY_SCALE_OPEN_DURATION } // Windowing Opacity Animation animators += ObjectAnimator.ofFloat(windowingPill, ALPHA, 1f).apply { startDelay = BODY_ALPHA_DELAY duration = BODY_ALPHA_DURATION startDelay = BODY_ALPHA_OPEN_DELAY duration = BODY_ALPHA_OPEN_DURATION } // Windowing Elevation Animation animators += ObjectAnimator.ofFloat(windowingPill, TRANSLATION_Z, 1f).apply { startDelay = ELEVATION_DELAY duration = BODY_ELEVATION_DURATION startDelay = ELEVATION_OPEN_DELAY duration = BODY_ELEVATION_OPEN_DURATION } // Windowing Content Opacity Animation windowingPill.children.forEach { animators += ObjectAnimator.ofFloat(it, ALPHA, 1f).apply { startDelay = BODY_ALPHA_DELAY duration = BODY_CONTENT_ALPHA_DURATION startDelay = BODY_ALPHA_OPEN_DELAY duration = BODY_CONTENT_ALPHA_OPEN_DURATION interpolator = Interpolators.FAST_OUT_SLOW_IN } } } private fun animateMoreActionsPill() { private fun animateMoreActionsPillOpen() { // More Actions X & Y Scaling Animation animators += ObjectAnimator.ofFloat(moreActionsPill, SCALE_X, HALF_INITIAL_SCALE, 1f).apply { startDelay = BODY_SCALE_DELAY duration = BODY_SCALE_DURATION startDelay = BODY_SCALE_OPEN_DELAY duration = BODY_SCALE_OPEN_DURATION } animators += ObjectAnimator.ofFloat(moreActionsPill, SCALE_Y, HALF_INITIAL_SCALE, 1f).apply { startDelay = BODY_SCALE_DELAY duration = BODY_SCALE_DURATION startDelay = BODY_SCALE_OPEN_DELAY duration = BODY_SCALE_OPEN_DURATION } // More Actions Opacity Animation animators += ObjectAnimator.ofFloat(moreActionsPill, ALPHA, 1f).apply { startDelay = BODY_ALPHA_DELAY duration = BODY_ALPHA_DURATION startDelay = BODY_ALPHA_OPEN_DELAY duration = BODY_ALPHA_OPEN_DURATION } // More Actions Elevation Animation animators += ObjectAnimator.ofFloat(moreActionsPill, TRANSLATION_Z, 1f).apply { startDelay = ELEVATION_DELAY duration = BODY_ELEVATION_DURATION startDelay = ELEVATION_OPEN_DELAY duration = BODY_ELEVATION_OPEN_DURATION } // More Actions Content Opacity Animation moreActionsPill.children.forEach { animators += ObjectAnimator.ofFloat(it, ALPHA, 1f).apply { startDelay = BODY_ALPHA_DELAY duration = BODY_CONTENT_ALPHA_DURATION startDelay = BODY_ALPHA_OPEN_DELAY duration = BODY_CONTENT_ALPHA_OPEN_DURATION interpolator = Interpolators.FAST_OUT_SLOW_IN } } } /** Runs the list of animators concurrently. */ private fun runAnimations() { val animatorSet = AnimatorSet() animatorSet.playTogether(animators) animatorSet.start() private fun appInfoPillCollapse() { // Header scaling animation animators += ObjectAnimator.ofFloat(appInfoPill, SCALE_X, 0f).apply { startDelay = HEADER_CLOSE_DELAY duration = HEADER_CLOSE_DURATION } animators += ObjectAnimator.ofFloat(appInfoPill, SCALE_Y, 0f).apply { startDelay = HEADER_CLOSE_DELAY duration = HEADER_CLOSE_DURATION } } private fun appInfoCollapseToHandle() { // Header X & Y Scaling Animation animators += ObjectAnimator.ofFloat(appInfoPill, SCALE_X, NONFREEFORM_HEADER_INITIAL_SCALE_X).apply { startDelay = HEADER_CLOSE_DELAY duration = HEADER_CLOSE_DURATION } animators += ObjectAnimator.ofFloat(appInfoPill, SCALE_Y, NONFREEFORM_HEADER_INITIAL_SCALE_Y).apply { startDelay = HEADER_CLOSE_DELAY duration = HEADER_CLOSE_DURATION } // Upward y-translation animation val yStart: Float = -captionHeight / 2 animators += ObjectAnimator.ofFloat(appInfoPill, TRANSLATION_Y, yStart).apply { startDelay = HEADER_CLOSE_DELAY duration = HEADER_CLOSE_DURATION } } private fun animateAppInfoPillFadeOut() { // Header Content Opacity Animation appInfoPill.children.forEach { animators += ObjectAnimator.ofFloat(it, ALPHA, 0f).apply { startDelay = HEADER_CONTENT_OPACITY_CLOSE_DELAY duration = HEADER_CONTENT_OPACITY_CLOSE_DURATION } } } private fun windowingPillClose() { // Windowing X & Y Scaling Animation animators += ObjectAnimator.ofFloat(windowingPill, SCALE_X, HALF_INITIAL_SCALE).apply { duration = BODY_CLOSE_DURATION } animators += ObjectAnimator.ofFloat(windowingPill, SCALE_Y, HALF_INITIAL_SCALE).apply { duration = BODY_CLOSE_DURATION } // windowing Animation animators += ObjectAnimator.ofFloat(windowingPill, ALPHA, 0f).apply { duration = BODY_CLOSE_DURATION } animators += ObjectAnimator.ofFloat(windowingPill, ALPHA, 0f).apply { duration = BODY_CLOSE_DURATION } } private fun moreActionsPillClose() { // More Actions X & Y Scaling Animation animators += ObjectAnimator.ofFloat(moreActionsPill, SCALE_X, HALF_INITIAL_SCALE).apply { duration = BODY_CLOSE_DURATION } animators += ObjectAnimator.ofFloat(moreActionsPill, SCALE_Y, HALF_INITIAL_SCALE).apply { duration = BODY_CLOSE_DURATION } // More Actions Opacity Animation animators += ObjectAnimator.ofFloat(moreActionsPill, ALPHA, 0f).apply { duration = BODY_CLOSE_DURATION } animators += ObjectAnimator.ofFloat(moreActionsPill, ALPHA, 0f).apply { duration = BODY_CLOSE_DURATION } // upward more actions pill y-translation animation val yStart: Float = -captionHeight / 2 animators += ObjectAnimator.ofFloat(moreActionsPill, TRANSLATION_Y, yStart).apply { duration = BODY_CLOSE_DURATION } } /** * Runs the list of hide animators concurrently. * * @param after runs after animation finishes. */ private fun runAnimations(after: Runnable? = null) { runningAnimation?.apply { // Remove all listeners, so that after runnable isn't triggered upon cancel. removeAllListeners() // If an animation runs while running animation is triggered, gracefully cancel. cancel() } runningAnimation = AnimatorSet().apply { playTogether(animators) animators.clear() doOnEnd { after?.run() runningAnimation = null } start() } } }