Loading libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java +2 −1 Original line number Diff line number Diff line Loading @@ -1619,7 +1619,8 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin openInAppOrBrowserIntent = null; } final View captionView = isAppHandle(mWindowDecorViewHolder) ? asAppHandle(mWindowDecorViewHolder).getCaptionHandle() : null; ? asAppHandle(mWindowDecorViewHolder).getCaptionHandle() : asAppHeader(mWindowDecorViewHolder).getRootView(); mHandleMenu = mHandleMenuFactory.create( mMainDispatcher, mMainScope, Loading libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.kt +8 −8 Original line number Diff line number Diff line Loading @@ -117,7 +117,7 @@ private constructor( private val isBrowserApp: Boolean, private val openInAppOrBrowserIntent: Intent?, private val desktopModeUiEventLogger: DesktopModeUiEventLogger, private val captionView: View?, private val captionView: View, private val captionWidth: Int, private val captionHeight: Int, captionX: Int, Loading Loading @@ -528,7 +528,7 @@ private constructor( private val windowDecorationActions: WindowDecorationActions, private val desktopModeUiEventLogger: DesktopModeUiEventLogger, menuWidth: Int, private val captionView: View?, private val captionView: View, captionHeight: Int, private val shouldShowWindowingPill: Boolean, private val shouldShowBrowserPill: Boolean, Loading Loading @@ -830,18 +830,18 @@ private constructor( /** Animates the menu opening. */ fun animateOpenMenu() { if (taskInfo.isFullscreen || taskInfo.isMultiWindow) { animator.animateCaptionHandleExpandToOpen(requireNotNull(captionView)) animator.animateCaptionHandleExpandToOpen(captionView) } else { animator.animateOpen() animator.animateCaptionHeaderExpandToOpen(captionView) } } /** Animates the menu closing. */ fun animateCloseMenu(onAnimFinish: () -> Unit) { if (taskInfo.isFullscreen || taskInfo.isMultiWindow) { animator.animateCollapseIntoHandleClose(requireNotNull(captionView), onAnimFinish) animator.animateCollapseIntoHandleClose(captionView, onAnimFinish) } else { animator.animateClose(onAnimFinish) animator.animateCollapseIntoHeaderClose(captionView, onAnimFinish) } } Loading Loading @@ -1132,7 +1132,7 @@ private constructor( isBrowserApp: Boolean, openInAppOrBrowserIntent: Intent?, desktopModeUiEventLogger: DesktopModeUiEventLogger, captionView: View?, captionView: View, captionWidth: Int, captionHeight: Int, captionX: Int, Loading Loading @@ -1198,7 +1198,7 @@ private constructor( isBrowserApp: Boolean, openInAppOrBrowserIntent: Intent?, desktopModeUiEventLogger: DesktopModeUiEventLogger, captionView: View?, captionView: View, captionWidth: Int, captionHeight: Int, captionX: Int, Loading libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenuAnimator.kt +178 −34 Original line number Diff line number Diff line Loading @@ -18,9 +18,11 @@ package com.android.wm.shell.windowdecor import android.animation.Animator import android.animation.AnimatorSet import android.animation.ArgbEvaluator import android.animation.ObjectAnimator import android.animation.ValueAnimator import android.content.Context import android.content.res.ColorStateList import android.view.View import android.view.View.ALPHA import android.view.View.SCALE_X Loading @@ -29,9 +31,12 @@ import android.view.View.TRANSLATION_Y import android.view.View.TRANSLATION_Z import android.view.ViewGroup import android.view.accessibility.AccessibilityEvent import android.widget.LinearLayout import android.widget.TextView import android.window.DesktopExperienceFlags import androidx.core.animation.doOnEnd import androidx.core.view.children import androidx.core.view.isGone import androidx.core.view.isVisible import com.android.app.animation.Interpolators.EMPHASIZED import com.android.wm.shell.R Loading Loading @@ -76,10 +81,15 @@ class HandleMenuAnimator( // Handle->menu animation constants private const val WIDTH_SWAP_FRACTION = 0.19f private const val HEADER_ICON_NAME_SWAP_FRACTION = 0.1f private const val HEADER_MENU_NAME_LATE_FADE_IN_FRACTION = 0.8f private const val HANDLE_MENU_OPEN_CLOSE_DURATION: Long = 600 private const val HEADER_MENU_OPEN_CLOSE_DURATION: Long = 600 } private val animators: MutableList<Animator> = mutableListOf() private val argbEvaluator: ArgbEvaluator = ArgbEvaluator.getInstance() private var runningAnimation: AnimatorSet? = null private val appInfoPill: ViewGroup = handleMenu.requireViewById(R.id.app_info_pill) Loading @@ -100,24 +110,56 @@ class HandleMenuAnimator( handleMenu.context.getColor(com.android.internal.R.color.materialColorSurfaceBright) private val marginMenuTop = context.resources.getDimensionPixelSize(R.dimen.desktop_mode_handle_menu_margin_top) private val marginMenuLeftRightPadding = context.resources.getDimensionPixelSize( R.dimen.desktop_mode_handle_menu_padding_left_bottom_right ) private val menuItemElevation: Int = context.getResources().getDimensionPixelSize(R.dimen.app_menu_elevation) private val menuAppIconHeight: Int = context.resources.getDimensionPixelSize(R.dimen.desktop_mode_handle_menu_icon_radius) private val headerAppIconHeight: Int = context.resources.getDimensionPixelSize(R.dimen.desktop_mode_caption_icon_radius) /** Animates the opening of the handle menu. */ fun animateOpen() { /** * Animates the App Header from resting state to the menu, giving an illusion they are the same * surface. */ fun animateCaptionHeaderExpandToOpen(headerView: View) { if ( DesktopExperienceFlags.ENABLE_DRAWING_APP_HANDLE.isTrue && DesktopExperienceFlags.ENABLE_TALL_APP_HEADERS.isTrue ) { setupHeaderAnimator(headerView, true /* expand */) } else { prepareMenuForAnimation() appInfoPillExpand() animateAppInfoPillOpen() animateWindowingPillOpen() animateMoreActionsPillOpen() animateOpenInAppOrBrowserPill() runAnimations { } val animationCallback: () -> Unit = { appInfoPill.post { appInfoPill .requireViewById<View>(R.id.collapse_menu_button) .sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED) } } if (!handleMenu.isAttachedToWindow) { handleMenu.addOnAttachStateChangeListener( object : View.OnAttachStateChangeListener { override fun onViewAttachedToWindow(v: View) { runAnimations(animationCallback) handleMenu.removeOnAttachStateChangeListener(this) } override fun onViewDetachedFromWindow(v: View) {} } ) } else { runAnimations(animationCallback) } } /** Loading @@ -127,10 +169,8 @@ class HandleMenuAnimator( */ fun animateCaptionHandleExpandToOpen(handleView: View) { if (DesktopExperienceFlags.ENABLE_DRAWING_APP_HANDLE.isTrue) { val showMenuAnimation = ValueAnimator.ofFloat(0f, 1f) showMenuAnimation.setDuration(HANDLE_MENU_OPEN_CLOSE_DURATION) showMenuAnimation.setInterpolator(EMPHASIZED) setupAnimator(showMenuAnimation, handleView) setupHandleAnimator(handleView, true /* expand */) } else { prepareMenuForAnimation() captionHandleExpandIntoAppInfoPill() Loading Loading @@ -171,10 +211,7 @@ class HandleMenuAnimator( */ fun animateCollapseIntoHandleClose(handleView: View, after: () -> Unit) { if (DesktopExperienceFlags.ENABLE_DRAWING_APP_HANDLE.isTrue) { val closeMenuAnimation = ValueAnimator.ofFloat(1f, 0f) closeMenuAnimation.setDuration(HANDLE_MENU_OPEN_CLOSE_DURATION) closeMenuAnimation.setInterpolator(EMPHASIZED) setupAnimator(closeMenuAnimation, handleView) setupHandleAnimator(handleView, false /* expand */) } else { appInfoCollapseToHandle() animateAppInfoPillFadeOut() Loading @@ -192,16 +229,33 @@ class HandleMenuAnimator( * * @param after runs after animation finishes. */ fun animateClose(after: () -> Unit) { fun animateCollapseIntoHeaderClose(headerView: View, after: () -> Unit) { if ( DesktopExperienceFlags.ENABLE_DRAWING_APP_HANDLE.isTrue && DesktopExperienceFlags.ENABLE_TALL_APP_HEADERS.isTrue ) { setupHeaderAnimator(headerView, false /* expand */) } else { appInfoPillCollapse() animateAppInfoPillFadeOut() windowingPillClose() moreActionsPillClose() openInAppOrBrowserPillClose() } runAnimations(after) } private fun setupAnimator(showMenuAnimation: ValueAnimator, handleView: View) { private fun setupHandleAnimator(handleView: View, expand: Boolean) { val showMenuAnimation = if (expand) { ValueAnimator.ofFloat(0f, 1f) } else { ValueAnimator.ofFloat(1f, 0f) } .apply { duration = HANDLE_MENU_OPEN_CLOSE_DURATION interpolator = EMPHASIZED } val widthDiff: Int = (handleMenuWidth - handleView.width).toInt() val targetWidth: Float = handleView.width + widthDiff * WIDTH_SWAP_FRACTION val targetHeight: Float = targetWidth * appInfoPillHeight / handleMenuWidth Loading Loading @@ -236,23 +290,113 @@ class HandleMenuAnimator( handleMenu.translationY = diff * (1 - menuAnimationProgress) handleMenu.pivotY = 0f handleMenu.pivotX = handleMenu.width.toFloat() / 2 animateFromStartScale(currentMenuScale, menuAnimationProgress) handleMenu.scaleX = currentMenuScale handleMenu.scaleY = currentMenuScale appInfoPill.children.forEach { it.alpha = progress } appInfoPill.elevation = menuItemElevation * progress animateRestOfTheMenu(menuAnimationProgress) } } animators += showMenuAnimation } private fun animateFromStartScale(currentScale: Float, progress: Float) { val SHOW_MENU_STAGES_COUNT = 3 handleMenu.scaleX = currentScale handleMenu.scaleY = currentScale private fun setupHeaderAnimator(headerView: View, expand: Boolean) { val showMenuAnimation = if (expand) { ValueAnimator.ofFloat(0f, 1f) } else { ValueAnimator.ofFloat(1f, 0f) } .apply { duration = HEADER_MENU_OPEN_CLOSE_DURATION interpolator = EMPHASIZED } val openMenuView = headerView.findViewById<LinearLayout>(R.id.open_menu_button) val headerAppIcon = openMenuView.findViewById<View>(R.id.application_icon) val headerAppName = openMenuView.findViewById<TextView>(R.id.application_name) val expandMenuButton = openMenuView.findViewById<View>(R.id.expand_menu_button) val menuAppIcon = appInfoPill.findViewById<View>(R.id.application_icon) val menuAppName = appInfoPill.findViewById<TextView>(R.id.application_name) val startingMenuAppNameColor = headerAppName.textColors.defaultColor val finalMenuAppNameColor = menuAppName.textColors.defaultColor appInfoPill.children.forEach { it.alpha = progress } val shouldLateFadeInAppName = headerAppName.isGone || headerAppName.text == null || headerAppName.text.isEmpty() val startingScaleForMenu = headerAppIconHeight.toFloat() / menuAppIconHeight.toFloat() showMenuAnimation.addUpdateListener { animator -> val progress: Float = animator.animatedValue as Float if (progress < HEADER_ICON_NAME_SWAP_FRACTION) { val headerAppNameAndIconProgress = 1f - progress / HEADER_ICON_NAME_SWAP_FRACTION headerAppIcon.alpha = headerAppNameAndIconProgress headerAppName.alpha = headerAppNameAndIconProgress expandMenuButton.alpha = headerAppNameAndIconProgress val menuIconsAndNameProgress = progress / HEADER_ICON_NAME_SWAP_FRACTION menuAppIcon.alpha = menuIconsAndNameProgress if (!shouldLateFadeInAppName) { menuAppName.alpha = menuIconsAndNameProgress } } else { headerAppIcon.alpha = 0f headerAppName.alpha = 0f expandMenuButton.alpha = 0f menuAppIcon.alpha = 1f if (!shouldLateFadeInAppName) { menuAppName.alpha = 1f } } val currentMenuScale = (1 - startingScaleForMenu) * progress + startingScaleForMenu // First, scale and translate the menu itself accordingly handleMenu.pivotY = 0f handleMenu.pivotX = marginMenuLeftRightPadding.toFloat() * (1 / startingScaleForMenu) handleMenu.scaleX = currentMenuScale handleMenu.scaleY = currentMenuScale handleMenu.translationY = -marginMenuTop.toFloat() / 2 * (1 - progress) handleMenu.translationX = marginMenuLeftRightPadding.toFloat() / 3f * (1 / startingScaleForMenu) * (1 - progress) // Next, transform the individual parts of the app pill // appInfoPill: fade in the background // appName: since we want to keep the text the same size, we are un-scaling it, and // move it in the x-axis to keep the spacing the same at the beginning // CollapseMenuButton: fade it in, but after the handoff fraction period appInfoPill.background.alpha = (progress * 255f).toInt() appInfoPill.elevation = menuItemElevation * progress menuAppName.scaleX = 1f / currentMenuScale menuAppName.scaleY = 1f / currentMenuScale menuAppName.translationX = marginMenuLeftRightPadding.toFloat() * (3f) * (1f - progress) val color = argbEvaluator.evaluate(progress, startingMenuAppNameColor, finalMenuAppNameColor) as Int menuAppName.setTextColor(ColorStateList.valueOf(color)) if (shouldLateFadeInAppName) { if (progress > (1 - HEADER_MENU_NAME_LATE_FADE_IN_FRACTION)) { menuAppName.alpha = (progress - (1 - HEADER_MENU_NAME_LATE_FADE_IN_FRACTION)) / HEADER_MENU_NAME_LATE_FADE_IN_FRACTION } else { menuAppName.alpha = 0f } } val collapsedMenuButtonAnimationProgress: Float = (progress - HEADER_ICON_NAME_SWAP_FRACTION) / (1 - HEADER_ICON_NAME_SWAP_FRACTION) val collapseMenuButton = appInfoPill.findViewById<View>(R.id.collapse_menu_button) collapseMenuButton.alpha = collapsedMenuButtonAnimationProgress animateRestOfTheMenu(progress) } animators += showMenuAnimation } private fun animateRestOfTheMenu(progress: Float) { val showMenuStagesCount = 3 val actionsBackgroundAlpha = max(0f, (progress - 1f / SHOW_MENU_STAGES_COUNT) * (SHOW_MENU_STAGES_COUNT - 1)) val actionItemsAlpha = max(0f, (progress - 2f / SHOW_MENU_STAGES_COUNT) * SHOW_MENU_STAGES_COUNT) max(0f, (progress - 1f / showMenuStagesCount) * (showMenuStagesCount - 1)) val actionItemsAlpha = max(0f, (progress - 2f / showMenuStagesCount) * showMenuStagesCount) windowingPill.setAlpha(actionsBackgroundAlpha) windowingPill.setElevation(menuItemElevation * actionsBackgroundAlpha) windowingPill.children.forEach { it.alpha = actionItemsAlpha } Loading libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/caption/AppHeaderController.kt +1 −1 Original line number Diff line number Diff line Loading @@ -523,7 +523,7 @@ class AppHeaderController( isBrowserApp = isBrowserApp, openInAppOrBrowserIntent = openInAppOrBrowserIntent, desktopModeUiEventLogger = desktopModeUiEventLogger, captionView = null, captionView = viewHolder.rootView, captionWidth = captionLayoutResult.captionWidth, captionHeight = captionLayoutResult.captionHeight, captionX = captionLayoutResult.captionX, Loading libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/HandleMenuTest.kt +3 −2 Original line number Diff line number Diff line Loading @@ -301,6 +301,7 @@ class HandleMenuTest : ShellTestCase() { } else -> error("Invalid windowing mode") } val captionView = LayoutInflater.from(mContext).inflate(layoutId, null) val handleMenu = if (DesktopExperienceFlags.ENABLE_WINDOW_DECORATION_REFACTOR.isTrue) { handleMenuFactory.create( Loading @@ -324,7 +325,7 @@ class HandleMenuTest : ShellTestCase() { isBrowserApp = false, openInAppOrBrowserIntent = null, mockDesktopModeUiEventLogger, captionView = mock(), captionView = captionView, captionWidth = HANDLE_WIDTH, captionHeight = 50, captionX = captionX, Loading @@ -350,7 +351,7 @@ class HandleMenuTest : ShellTestCase() { isBrowserApp = false, openInAppOrBrowserIntent = null, mockDesktopModeUiEventLogger, captionView = mock(), captionView = captionView, captionWidth = HANDLE_WIDTH, captionHeight = 50, captionX = captionX, Loading Loading
libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java +2 −1 Original line number Diff line number Diff line Loading @@ -1619,7 +1619,8 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin openInAppOrBrowserIntent = null; } final View captionView = isAppHandle(mWindowDecorViewHolder) ? asAppHandle(mWindowDecorViewHolder).getCaptionHandle() : null; ? asAppHandle(mWindowDecorViewHolder).getCaptionHandle() : asAppHeader(mWindowDecorViewHolder).getRootView(); mHandleMenu = mHandleMenuFactory.create( mMainDispatcher, mMainScope, Loading
libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.kt +8 −8 Original line number Diff line number Diff line Loading @@ -117,7 +117,7 @@ private constructor( private val isBrowserApp: Boolean, private val openInAppOrBrowserIntent: Intent?, private val desktopModeUiEventLogger: DesktopModeUiEventLogger, private val captionView: View?, private val captionView: View, private val captionWidth: Int, private val captionHeight: Int, captionX: Int, Loading Loading @@ -528,7 +528,7 @@ private constructor( private val windowDecorationActions: WindowDecorationActions, private val desktopModeUiEventLogger: DesktopModeUiEventLogger, menuWidth: Int, private val captionView: View?, private val captionView: View, captionHeight: Int, private val shouldShowWindowingPill: Boolean, private val shouldShowBrowserPill: Boolean, Loading Loading @@ -830,18 +830,18 @@ private constructor( /** Animates the menu opening. */ fun animateOpenMenu() { if (taskInfo.isFullscreen || taskInfo.isMultiWindow) { animator.animateCaptionHandleExpandToOpen(requireNotNull(captionView)) animator.animateCaptionHandleExpandToOpen(captionView) } else { animator.animateOpen() animator.animateCaptionHeaderExpandToOpen(captionView) } } /** Animates the menu closing. */ fun animateCloseMenu(onAnimFinish: () -> Unit) { if (taskInfo.isFullscreen || taskInfo.isMultiWindow) { animator.animateCollapseIntoHandleClose(requireNotNull(captionView), onAnimFinish) animator.animateCollapseIntoHandleClose(captionView, onAnimFinish) } else { animator.animateClose(onAnimFinish) animator.animateCollapseIntoHeaderClose(captionView, onAnimFinish) } } Loading Loading @@ -1132,7 +1132,7 @@ private constructor( isBrowserApp: Boolean, openInAppOrBrowserIntent: Intent?, desktopModeUiEventLogger: DesktopModeUiEventLogger, captionView: View?, captionView: View, captionWidth: Int, captionHeight: Int, captionX: Int, Loading Loading @@ -1198,7 +1198,7 @@ private constructor( isBrowserApp: Boolean, openInAppOrBrowserIntent: Intent?, desktopModeUiEventLogger: DesktopModeUiEventLogger, captionView: View?, captionView: View, captionWidth: Int, captionHeight: Int, captionX: Int, Loading
libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenuAnimator.kt +178 −34 Original line number Diff line number Diff line Loading @@ -18,9 +18,11 @@ package com.android.wm.shell.windowdecor import android.animation.Animator import android.animation.AnimatorSet import android.animation.ArgbEvaluator import android.animation.ObjectAnimator import android.animation.ValueAnimator import android.content.Context import android.content.res.ColorStateList import android.view.View import android.view.View.ALPHA import android.view.View.SCALE_X Loading @@ -29,9 +31,12 @@ import android.view.View.TRANSLATION_Y import android.view.View.TRANSLATION_Z import android.view.ViewGroup import android.view.accessibility.AccessibilityEvent import android.widget.LinearLayout import android.widget.TextView import android.window.DesktopExperienceFlags import androidx.core.animation.doOnEnd import androidx.core.view.children import androidx.core.view.isGone import androidx.core.view.isVisible import com.android.app.animation.Interpolators.EMPHASIZED import com.android.wm.shell.R Loading Loading @@ -76,10 +81,15 @@ class HandleMenuAnimator( // Handle->menu animation constants private const val WIDTH_SWAP_FRACTION = 0.19f private const val HEADER_ICON_NAME_SWAP_FRACTION = 0.1f private const val HEADER_MENU_NAME_LATE_FADE_IN_FRACTION = 0.8f private const val HANDLE_MENU_OPEN_CLOSE_DURATION: Long = 600 private const val HEADER_MENU_OPEN_CLOSE_DURATION: Long = 600 } private val animators: MutableList<Animator> = mutableListOf() private val argbEvaluator: ArgbEvaluator = ArgbEvaluator.getInstance() private var runningAnimation: AnimatorSet? = null private val appInfoPill: ViewGroup = handleMenu.requireViewById(R.id.app_info_pill) Loading @@ -100,24 +110,56 @@ class HandleMenuAnimator( handleMenu.context.getColor(com.android.internal.R.color.materialColorSurfaceBright) private val marginMenuTop = context.resources.getDimensionPixelSize(R.dimen.desktop_mode_handle_menu_margin_top) private val marginMenuLeftRightPadding = context.resources.getDimensionPixelSize( R.dimen.desktop_mode_handle_menu_padding_left_bottom_right ) private val menuItemElevation: Int = context.getResources().getDimensionPixelSize(R.dimen.app_menu_elevation) private val menuAppIconHeight: Int = context.resources.getDimensionPixelSize(R.dimen.desktop_mode_handle_menu_icon_radius) private val headerAppIconHeight: Int = context.resources.getDimensionPixelSize(R.dimen.desktop_mode_caption_icon_radius) /** Animates the opening of the handle menu. */ fun animateOpen() { /** * Animates the App Header from resting state to the menu, giving an illusion they are the same * surface. */ fun animateCaptionHeaderExpandToOpen(headerView: View) { if ( DesktopExperienceFlags.ENABLE_DRAWING_APP_HANDLE.isTrue && DesktopExperienceFlags.ENABLE_TALL_APP_HEADERS.isTrue ) { setupHeaderAnimator(headerView, true /* expand */) } else { prepareMenuForAnimation() appInfoPillExpand() animateAppInfoPillOpen() animateWindowingPillOpen() animateMoreActionsPillOpen() animateOpenInAppOrBrowserPill() runAnimations { } val animationCallback: () -> Unit = { appInfoPill.post { appInfoPill .requireViewById<View>(R.id.collapse_menu_button) .sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED) } } if (!handleMenu.isAttachedToWindow) { handleMenu.addOnAttachStateChangeListener( object : View.OnAttachStateChangeListener { override fun onViewAttachedToWindow(v: View) { runAnimations(animationCallback) handleMenu.removeOnAttachStateChangeListener(this) } override fun onViewDetachedFromWindow(v: View) {} } ) } else { runAnimations(animationCallback) } } /** Loading @@ -127,10 +169,8 @@ class HandleMenuAnimator( */ fun animateCaptionHandleExpandToOpen(handleView: View) { if (DesktopExperienceFlags.ENABLE_DRAWING_APP_HANDLE.isTrue) { val showMenuAnimation = ValueAnimator.ofFloat(0f, 1f) showMenuAnimation.setDuration(HANDLE_MENU_OPEN_CLOSE_DURATION) showMenuAnimation.setInterpolator(EMPHASIZED) setupAnimator(showMenuAnimation, handleView) setupHandleAnimator(handleView, true /* expand */) } else { prepareMenuForAnimation() captionHandleExpandIntoAppInfoPill() Loading Loading @@ -171,10 +211,7 @@ class HandleMenuAnimator( */ fun animateCollapseIntoHandleClose(handleView: View, after: () -> Unit) { if (DesktopExperienceFlags.ENABLE_DRAWING_APP_HANDLE.isTrue) { val closeMenuAnimation = ValueAnimator.ofFloat(1f, 0f) closeMenuAnimation.setDuration(HANDLE_MENU_OPEN_CLOSE_DURATION) closeMenuAnimation.setInterpolator(EMPHASIZED) setupAnimator(closeMenuAnimation, handleView) setupHandleAnimator(handleView, false /* expand */) } else { appInfoCollapseToHandle() animateAppInfoPillFadeOut() Loading @@ -192,16 +229,33 @@ class HandleMenuAnimator( * * @param after runs after animation finishes. */ fun animateClose(after: () -> Unit) { fun animateCollapseIntoHeaderClose(headerView: View, after: () -> Unit) { if ( DesktopExperienceFlags.ENABLE_DRAWING_APP_HANDLE.isTrue && DesktopExperienceFlags.ENABLE_TALL_APP_HEADERS.isTrue ) { setupHeaderAnimator(headerView, false /* expand */) } else { appInfoPillCollapse() animateAppInfoPillFadeOut() windowingPillClose() moreActionsPillClose() openInAppOrBrowserPillClose() } runAnimations(after) } private fun setupAnimator(showMenuAnimation: ValueAnimator, handleView: View) { private fun setupHandleAnimator(handleView: View, expand: Boolean) { val showMenuAnimation = if (expand) { ValueAnimator.ofFloat(0f, 1f) } else { ValueAnimator.ofFloat(1f, 0f) } .apply { duration = HANDLE_MENU_OPEN_CLOSE_DURATION interpolator = EMPHASIZED } val widthDiff: Int = (handleMenuWidth - handleView.width).toInt() val targetWidth: Float = handleView.width + widthDiff * WIDTH_SWAP_FRACTION val targetHeight: Float = targetWidth * appInfoPillHeight / handleMenuWidth Loading Loading @@ -236,23 +290,113 @@ class HandleMenuAnimator( handleMenu.translationY = diff * (1 - menuAnimationProgress) handleMenu.pivotY = 0f handleMenu.pivotX = handleMenu.width.toFloat() / 2 animateFromStartScale(currentMenuScale, menuAnimationProgress) handleMenu.scaleX = currentMenuScale handleMenu.scaleY = currentMenuScale appInfoPill.children.forEach { it.alpha = progress } appInfoPill.elevation = menuItemElevation * progress animateRestOfTheMenu(menuAnimationProgress) } } animators += showMenuAnimation } private fun animateFromStartScale(currentScale: Float, progress: Float) { val SHOW_MENU_STAGES_COUNT = 3 handleMenu.scaleX = currentScale handleMenu.scaleY = currentScale private fun setupHeaderAnimator(headerView: View, expand: Boolean) { val showMenuAnimation = if (expand) { ValueAnimator.ofFloat(0f, 1f) } else { ValueAnimator.ofFloat(1f, 0f) } .apply { duration = HEADER_MENU_OPEN_CLOSE_DURATION interpolator = EMPHASIZED } val openMenuView = headerView.findViewById<LinearLayout>(R.id.open_menu_button) val headerAppIcon = openMenuView.findViewById<View>(R.id.application_icon) val headerAppName = openMenuView.findViewById<TextView>(R.id.application_name) val expandMenuButton = openMenuView.findViewById<View>(R.id.expand_menu_button) val menuAppIcon = appInfoPill.findViewById<View>(R.id.application_icon) val menuAppName = appInfoPill.findViewById<TextView>(R.id.application_name) val startingMenuAppNameColor = headerAppName.textColors.defaultColor val finalMenuAppNameColor = menuAppName.textColors.defaultColor appInfoPill.children.forEach { it.alpha = progress } val shouldLateFadeInAppName = headerAppName.isGone || headerAppName.text == null || headerAppName.text.isEmpty() val startingScaleForMenu = headerAppIconHeight.toFloat() / menuAppIconHeight.toFloat() showMenuAnimation.addUpdateListener { animator -> val progress: Float = animator.animatedValue as Float if (progress < HEADER_ICON_NAME_SWAP_FRACTION) { val headerAppNameAndIconProgress = 1f - progress / HEADER_ICON_NAME_SWAP_FRACTION headerAppIcon.alpha = headerAppNameAndIconProgress headerAppName.alpha = headerAppNameAndIconProgress expandMenuButton.alpha = headerAppNameAndIconProgress val menuIconsAndNameProgress = progress / HEADER_ICON_NAME_SWAP_FRACTION menuAppIcon.alpha = menuIconsAndNameProgress if (!shouldLateFadeInAppName) { menuAppName.alpha = menuIconsAndNameProgress } } else { headerAppIcon.alpha = 0f headerAppName.alpha = 0f expandMenuButton.alpha = 0f menuAppIcon.alpha = 1f if (!shouldLateFadeInAppName) { menuAppName.alpha = 1f } } val currentMenuScale = (1 - startingScaleForMenu) * progress + startingScaleForMenu // First, scale and translate the menu itself accordingly handleMenu.pivotY = 0f handleMenu.pivotX = marginMenuLeftRightPadding.toFloat() * (1 / startingScaleForMenu) handleMenu.scaleX = currentMenuScale handleMenu.scaleY = currentMenuScale handleMenu.translationY = -marginMenuTop.toFloat() / 2 * (1 - progress) handleMenu.translationX = marginMenuLeftRightPadding.toFloat() / 3f * (1 / startingScaleForMenu) * (1 - progress) // Next, transform the individual parts of the app pill // appInfoPill: fade in the background // appName: since we want to keep the text the same size, we are un-scaling it, and // move it in the x-axis to keep the spacing the same at the beginning // CollapseMenuButton: fade it in, but after the handoff fraction period appInfoPill.background.alpha = (progress * 255f).toInt() appInfoPill.elevation = menuItemElevation * progress menuAppName.scaleX = 1f / currentMenuScale menuAppName.scaleY = 1f / currentMenuScale menuAppName.translationX = marginMenuLeftRightPadding.toFloat() * (3f) * (1f - progress) val color = argbEvaluator.evaluate(progress, startingMenuAppNameColor, finalMenuAppNameColor) as Int menuAppName.setTextColor(ColorStateList.valueOf(color)) if (shouldLateFadeInAppName) { if (progress > (1 - HEADER_MENU_NAME_LATE_FADE_IN_FRACTION)) { menuAppName.alpha = (progress - (1 - HEADER_MENU_NAME_LATE_FADE_IN_FRACTION)) / HEADER_MENU_NAME_LATE_FADE_IN_FRACTION } else { menuAppName.alpha = 0f } } val collapsedMenuButtonAnimationProgress: Float = (progress - HEADER_ICON_NAME_SWAP_FRACTION) / (1 - HEADER_ICON_NAME_SWAP_FRACTION) val collapseMenuButton = appInfoPill.findViewById<View>(R.id.collapse_menu_button) collapseMenuButton.alpha = collapsedMenuButtonAnimationProgress animateRestOfTheMenu(progress) } animators += showMenuAnimation } private fun animateRestOfTheMenu(progress: Float) { val showMenuStagesCount = 3 val actionsBackgroundAlpha = max(0f, (progress - 1f / SHOW_MENU_STAGES_COUNT) * (SHOW_MENU_STAGES_COUNT - 1)) val actionItemsAlpha = max(0f, (progress - 2f / SHOW_MENU_STAGES_COUNT) * SHOW_MENU_STAGES_COUNT) max(0f, (progress - 1f / showMenuStagesCount) * (showMenuStagesCount - 1)) val actionItemsAlpha = max(0f, (progress - 2f / showMenuStagesCount) * showMenuStagesCount) windowingPill.setAlpha(actionsBackgroundAlpha) windowingPill.setElevation(menuItemElevation * actionsBackgroundAlpha) windowingPill.children.forEach { it.alpha = actionItemsAlpha } Loading
libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/caption/AppHeaderController.kt +1 −1 Original line number Diff line number Diff line Loading @@ -523,7 +523,7 @@ class AppHeaderController( isBrowserApp = isBrowserApp, openInAppOrBrowserIntent = openInAppOrBrowserIntent, desktopModeUiEventLogger = desktopModeUiEventLogger, captionView = null, captionView = viewHolder.rootView, captionWidth = captionLayoutResult.captionWidth, captionHeight = captionLayoutResult.captionHeight, captionX = captionLayoutResult.captionX, Loading
libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/HandleMenuTest.kt +3 −2 Original line number Diff line number Diff line Loading @@ -301,6 +301,7 @@ class HandleMenuTest : ShellTestCase() { } else -> error("Invalid windowing mode") } val captionView = LayoutInflater.from(mContext).inflate(layoutId, null) val handleMenu = if (DesktopExperienceFlags.ENABLE_WINDOW_DECORATION_REFACTOR.isTrue) { handleMenuFactory.create( Loading @@ -324,7 +325,7 @@ class HandleMenuTest : ShellTestCase() { isBrowserApp = false, openInAppOrBrowserIntent = null, mockDesktopModeUiEventLogger, captionView = mock(), captionView = captionView, captionWidth = HANDLE_WIDTH, captionHeight = 50, captionX = captionX, Loading @@ -350,7 +351,7 @@ class HandleMenuTest : ShellTestCase() { isBrowserApp = false, openInAppOrBrowserIntent = null, mockDesktopModeUiEventLogger, captionView = mock(), captionView = captionView, captionWidth = HANDLE_WIDTH, captionHeight = 50, captionX = captionX, Loading