Loading packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt +112 −61 Original line number Diff line number Diff line Loading @@ -27,7 +27,6 @@ import android.os.Looper import android.util.Log import android.util.MathUtils import android.view.GhostView import android.view.Gravity import android.view.View import android.view.ViewGroup import android.view.ViewTreeObserver.OnPreDrawListener Loading Loading @@ -87,10 +86,11 @@ class DialogLaunchAnimator( // If the parent of the view we are launching from is the background of some other animated // dialog, then this means the caller intent is to launch a dialog from another dialog. In // this case, we also animate the parent (which is the dialog background). val animatedParent = openedDialogs .firstOrNull { it.dialogContentParent == view.parent } val parentHostDialog = animatedParent?.hostDialog val animateFrom = animatedParent?.dialogContentParent ?: view val animatedParent = openedDialogs.firstOrNull { it.dialogContentWithBackground == view || it.dialogContentWithBackground == view.parent } val dialogContentWithBackground = animatedParent?.dialogContentWithBackground val animateFrom = dialogContentWithBackground ?: view // Make sure we don't run the launch animation from the same view twice at the same time. if (animateFrom.getTag(TAG_LAUNCH_ANIMATION_RUNNING) != null) { Loading @@ -109,7 +109,7 @@ class DialogLaunchAnimator( onDialogDismissed = { openedDialogs.remove(it) }, originalDialog = dialog, animateBackgroundBoundsChange, openedDialogs.firstOrNull { it.hostDialog == parentHostDialog } animatedParent ) val hostDialog = animatedDialog.hostDialog openedDialogs.add(animatedDialog) Loading Loading @@ -288,13 +288,12 @@ private class AnimatedDialog( private val hostDialogRoot = FrameLayout(context) /** * The parent of the original dialog content view, that serves as a fake window that will have * the same size as the original dialog window and to which we will set the original dialog * window background. * The dialog content with its background. When animating a fullscreen dialog, this is just the * first ViewGroup of the dialog that has a background. When animating a normal (not fullscreen) * dialog, this is an additional view that serves as a fake window that will have the same size * as the original dialog window and to which we will set the original dialog window background. */ val dialogContentParent = FrameLayout(context).apply { id = DIALOG_CONTENT_PARENT_ID } var dialogContentWithBackground: ViewGroup? = null /** * The background color of [originalDialogView], taking into consideration the [originalDialog] Loading Loading @@ -451,59 +450,87 @@ private class AnimatedDialog( hostDialogRoot.setOnClickListener { hostDialog.dismiss() } dialogView.isClickable = true // Set the background of the window dialog to the dialog itself. // TODO(b/193634619): Support dialog windows without background. // TODO(b/193634619): Support dialog whose background comes from the content view instead of // the window. val typedArray = originalDialog.context.obtainStyledAttributes(com.android.internal.R.styleable.Window) val backgroundRes = typedArray.getResourceId(com.android.internal.R.styleable.Window_windowBackground, 0) typedArray.recycle() if (backgroundRes == 0) { throw IllegalStateException("Dialogs with no backgrounds on window are not supported") } // Add a parent view to the original dialog view to which we will set the original dialog // window background. This View serves as a fake window with background, so that we are sure // that we don't override the dialog view paddings with the window background that usually // has insets. dialogContentParent.setBackgroundResource(backgroundRes) // Remove the original dialog view from its parent. (dialogView.parent as? ViewGroup)?.removeView(dialogView) val originalDialogWindow = originalDialog.window!! val isOriginalWindowFullScreen = originalDialogWindow.attributes.width == ViewGroup.LayoutParams.MATCH_PARENT && originalDialogWindow.attributes.height == ViewGroup.LayoutParams.MATCH_PARENT if (isOriginalWindowFullScreen) { // If the original dialog window is fullscreen, then we look for the first ViewGroup // that has a background and animate towards that ViewGroup given that this is probably // what represents the actual dialog view. dialogContentWithBackground = findFirstViewGroupWithBackground(dialogView) ?: throw IllegalStateException("Unable to find ViewGroup with background") hostDialogRoot.addView( dialogContentParent, dialogView, // We give it the size of its original dialog window. FrameLayout.LayoutParams( originalDialog.window.attributes.width, originalDialog.window.attributes.height, Gravity.CENTER ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT ) ) } else { // Add a parent view to the original dialog view to which we will set the original // dialog window background. This View serves as a fake window with background, so that // we are sure that we don't override the original dialog content view paddings with the // window background that usually has insets. dialogContentWithBackground = FrameLayout(context).apply { id = DIALOG_CONTENT_PARENT_ID // Make the dialog view parent invisible for now, to make sure it's not drawn yet. dialogContentParent.visibility = View.INVISIBLE val background = dialogContentParent.background!! originalDialogBackgroundColor = GhostedViewLaunchAnimatorController.findGradientDrawable(background) ?.color ?.defaultColor ?: Color.BLACK // TODO(b/193634619): Support dialog windows without background. background = originalDialogWindow.decorView?.background ?: throw IllegalStateException( "Dialogs with no backgrounds on window are not supported") // Add the dialog view to its parent (that has the original window background). (dialogView.parent as? ViewGroup)?.removeView(dialogView) dialogContentParent.addView( addView( dialogView, // It should match its parent size, which is sized the same as the original dialog // window. // It should match its parent size, which is sized the same as the original // dialog window. FrameLayout.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT ) ) } // Add the parent (that has the background) to the host window. hostDialogRoot.addView( dialogContentWithBackground, // We give it the size and gravity of its original dialog window. FrameLayout.LayoutParams( originalDialogWindow.attributes.width, originalDialogWindow.attributes.height, originalDialogWindow.attributes.gravity ) ) } val dialogContentWithBackground = this.dialogContentWithBackground!! // Make the dialog and its background invisible for now, to make sure it's not drawn yet. dialogContentWithBackground.visibility = View.INVISIBLE val background = dialogContentWithBackground.background!! originalDialogBackgroundColor = GhostedViewLaunchAnimatorController.findGradientDrawable(background) ?.color ?.defaultColor ?: Color.BLACK if (isOriginalWindowFullScreen) { // If the original window is full screen, the ViewGroup with background might already be // correctly laid out. Make sure we relayout and that the layout listener below is still // called. dialogContentWithBackground.layout(0, 0, 0, 0) dialogContentWithBackground.requestLayout() } // Start the animation when the dialog is laid out in the center of the host dialog. dialogContentParent.addOnLayoutChangeListener(object : View.OnLayoutChangeListener { dialogContentWithBackground.addOnLayoutChangeListener(object : View.OnLayoutChangeListener { override fun onLayoutChange( view: View, left: Int, Loading @@ -515,7 +542,7 @@ private class AnimatedDialog( oldRight: Int, oldBottom: Int ) { dialogContentParent.removeOnLayoutChangeListener(this) dialogContentWithBackground.removeOnLayoutChangeListener(this) isOriginalDialogViewLaidOut = true maybeStartLaunchAnimation() Loading @@ -523,6 +550,25 @@ private class AnimatedDialog( }) } private fun findFirstViewGroupWithBackground(view: View): ViewGroup? { if (view !is ViewGroup) { return null } if (view.background != null) { return view } for (i in 0 until view.childCount) { val match = findFirstViewGroupWithBackground(view.getChildAt(i)) if (match != null) { return match } } return null } fun onOriginalDialogSizeChanged() { // The dialog is the single child of the root. if (hostDialogRoot.childCount != 1) { Loading Loading @@ -571,7 +617,8 @@ private class AnimatedDialog( // at the end of the launch animation, because the lauch animation already correctly // handles bounds changes. if (backgroundLayoutListener != null) { dialogContentParent.addOnLayoutChangeListener(backgroundLayoutListener) dialogContentWithBackground!! .addOnLayoutChangeListener(backgroundLayoutListener) } } ) Loading Loading @@ -638,10 +685,12 @@ private class AnimatedDialog( (touchSurface as? LaunchableView)?.setShouldBlockVisibilityChanges(false) touchSurface.visibility = View.VISIBLE dialogContentParent.visibility = View.INVISIBLE val dialogContentWithBackground = this.dialogContentWithBackground!! dialogContentWithBackground.visibility = View.INVISIBLE if (backgroundLayoutListener != null) { dialogContentParent.removeOnLayoutChangeListener(backgroundLayoutListener) dialogContentWithBackground .removeOnLayoutChangeListener(backgroundLayoutListener) } // The animated ghost was just removed. We create a temporary ghost that will be Loading Loading @@ -674,8 +723,8 @@ private class AnimatedDialog( ) { // Create 2 ghost controllers to animate both the dialog and the touch surface in the host // dialog. val startView = if (isLaunching) touchSurface else dialogContentParent val endView = if (isLaunching) dialogContentParent else touchSurface val startView = if (isLaunching) touchSurface else dialogContentWithBackground!! val endView = if (isLaunching) dialogContentWithBackground!! else touchSurface val startViewController = GhostedViewLaunchAnimatorController(startView) val endViewController = GhostedViewLaunchAnimatorController(endView) startViewController.launchContainer = hostDialogRoot Loading Loading @@ -736,7 +785,9 @@ private class AnimatedDialog( } private fun shouldAnimateDialogIntoView(): Boolean { if (exitAnimationDisabled) { // Don't animate if the dialog was previously hidden using hide() (either on the host dialog // or on the original dialog) or if we disabled the exit animation. if (exitAnimationDisabled || !hostDialog.isShowing) { return false } Loading packages/SystemUI/res/values/styles.xml +4 −4 Original line number Diff line number Diff line Loading @@ -373,11 +373,11 @@ <item name="android:windowIsFloating">true</item> </style> <style name="Theme.SystemUI.Dialog.GlobalActionsLite" parent="@android:style/Theme.DeviceDefault.Light.NoActionBar.Fullscreen"> <item name="android:windowIsFloating">true</item> <style name="Theme.SystemUI.Dialog.GlobalActionsLite" parent="Theme.SystemUI.Dialog"> <!-- Settings windowFullscreen: true is necessary to be able to intercept touch events --> <!-- that would otherwise be intercepted by the Shade. --> <item name="android:windowFullscreen">true</item> <item name="android:windowBackground">@android:color/transparent</item> <item name="android:backgroundDimEnabled">true</item> <item name="android:windowCloseOnTouchOutside">true</item> </style> <style name="QSBorderlessButton"> Loading packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java +89 −156 File changed.Preview size limit exceeded, changes collapsed. Show changes packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java +1 −1 Original line number Diff line number Diff line Loading @@ -82,7 +82,7 @@ public class GlobalActionsImpl implements GlobalActions, CommandQueue.Callbacks if (mDisabled) return; mGlobalActionsDialog = mGlobalActionsDialogLazy.get(); mGlobalActionsDialog.showOrHideDialog(mKeyguardStateController.isShowing(), mDeviceProvisionedController.isDeviceProvisioned()); mDeviceProvisionedController.isDeviceProvisioned(), null /* view */); } @Override Loading packages/SystemUI/src/com/android/systemui/qs/FooterActionsController.kt +1 −1 Original line number Diff line number Diff line Loading @@ -116,7 +116,7 @@ class FooterActionsController @Inject constructor( } } else if (v === powerMenuLite) { uiEventLogger.log(GlobalActionsDialogLite.GlobalActionsEvent.GA_OPEN_QS) globalActionsDialog.showOrHideDialog(false, true) globalActionsDialog.showOrHideDialog(false, true, v) } } Loading Loading
packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt +112 −61 Original line number Diff line number Diff line Loading @@ -27,7 +27,6 @@ import android.os.Looper import android.util.Log import android.util.MathUtils import android.view.GhostView import android.view.Gravity import android.view.View import android.view.ViewGroup import android.view.ViewTreeObserver.OnPreDrawListener Loading Loading @@ -87,10 +86,11 @@ class DialogLaunchAnimator( // If the parent of the view we are launching from is the background of some other animated // dialog, then this means the caller intent is to launch a dialog from another dialog. In // this case, we also animate the parent (which is the dialog background). val animatedParent = openedDialogs .firstOrNull { it.dialogContentParent == view.parent } val parentHostDialog = animatedParent?.hostDialog val animateFrom = animatedParent?.dialogContentParent ?: view val animatedParent = openedDialogs.firstOrNull { it.dialogContentWithBackground == view || it.dialogContentWithBackground == view.parent } val dialogContentWithBackground = animatedParent?.dialogContentWithBackground val animateFrom = dialogContentWithBackground ?: view // Make sure we don't run the launch animation from the same view twice at the same time. if (animateFrom.getTag(TAG_LAUNCH_ANIMATION_RUNNING) != null) { Loading @@ -109,7 +109,7 @@ class DialogLaunchAnimator( onDialogDismissed = { openedDialogs.remove(it) }, originalDialog = dialog, animateBackgroundBoundsChange, openedDialogs.firstOrNull { it.hostDialog == parentHostDialog } animatedParent ) val hostDialog = animatedDialog.hostDialog openedDialogs.add(animatedDialog) Loading Loading @@ -288,13 +288,12 @@ private class AnimatedDialog( private val hostDialogRoot = FrameLayout(context) /** * The parent of the original dialog content view, that serves as a fake window that will have * the same size as the original dialog window and to which we will set the original dialog * window background. * The dialog content with its background. When animating a fullscreen dialog, this is just the * first ViewGroup of the dialog that has a background. When animating a normal (not fullscreen) * dialog, this is an additional view that serves as a fake window that will have the same size * as the original dialog window and to which we will set the original dialog window background. */ val dialogContentParent = FrameLayout(context).apply { id = DIALOG_CONTENT_PARENT_ID } var dialogContentWithBackground: ViewGroup? = null /** * The background color of [originalDialogView], taking into consideration the [originalDialog] Loading Loading @@ -451,59 +450,87 @@ private class AnimatedDialog( hostDialogRoot.setOnClickListener { hostDialog.dismiss() } dialogView.isClickable = true // Set the background of the window dialog to the dialog itself. // TODO(b/193634619): Support dialog windows without background. // TODO(b/193634619): Support dialog whose background comes from the content view instead of // the window. val typedArray = originalDialog.context.obtainStyledAttributes(com.android.internal.R.styleable.Window) val backgroundRes = typedArray.getResourceId(com.android.internal.R.styleable.Window_windowBackground, 0) typedArray.recycle() if (backgroundRes == 0) { throw IllegalStateException("Dialogs with no backgrounds on window are not supported") } // Add a parent view to the original dialog view to which we will set the original dialog // window background. This View serves as a fake window with background, so that we are sure // that we don't override the dialog view paddings with the window background that usually // has insets. dialogContentParent.setBackgroundResource(backgroundRes) // Remove the original dialog view from its parent. (dialogView.parent as? ViewGroup)?.removeView(dialogView) val originalDialogWindow = originalDialog.window!! val isOriginalWindowFullScreen = originalDialogWindow.attributes.width == ViewGroup.LayoutParams.MATCH_PARENT && originalDialogWindow.attributes.height == ViewGroup.LayoutParams.MATCH_PARENT if (isOriginalWindowFullScreen) { // If the original dialog window is fullscreen, then we look for the first ViewGroup // that has a background and animate towards that ViewGroup given that this is probably // what represents the actual dialog view. dialogContentWithBackground = findFirstViewGroupWithBackground(dialogView) ?: throw IllegalStateException("Unable to find ViewGroup with background") hostDialogRoot.addView( dialogContentParent, dialogView, // We give it the size of its original dialog window. FrameLayout.LayoutParams( originalDialog.window.attributes.width, originalDialog.window.attributes.height, Gravity.CENTER ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT ) ) } else { // Add a parent view to the original dialog view to which we will set the original // dialog window background. This View serves as a fake window with background, so that // we are sure that we don't override the original dialog content view paddings with the // window background that usually has insets. dialogContentWithBackground = FrameLayout(context).apply { id = DIALOG_CONTENT_PARENT_ID // Make the dialog view parent invisible for now, to make sure it's not drawn yet. dialogContentParent.visibility = View.INVISIBLE val background = dialogContentParent.background!! originalDialogBackgroundColor = GhostedViewLaunchAnimatorController.findGradientDrawable(background) ?.color ?.defaultColor ?: Color.BLACK // TODO(b/193634619): Support dialog windows without background. background = originalDialogWindow.decorView?.background ?: throw IllegalStateException( "Dialogs with no backgrounds on window are not supported") // Add the dialog view to its parent (that has the original window background). (dialogView.parent as? ViewGroup)?.removeView(dialogView) dialogContentParent.addView( addView( dialogView, // It should match its parent size, which is sized the same as the original dialog // window. // It should match its parent size, which is sized the same as the original // dialog window. FrameLayout.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT ) ) } // Add the parent (that has the background) to the host window. hostDialogRoot.addView( dialogContentWithBackground, // We give it the size and gravity of its original dialog window. FrameLayout.LayoutParams( originalDialogWindow.attributes.width, originalDialogWindow.attributes.height, originalDialogWindow.attributes.gravity ) ) } val dialogContentWithBackground = this.dialogContentWithBackground!! // Make the dialog and its background invisible for now, to make sure it's not drawn yet. dialogContentWithBackground.visibility = View.INVISIBLE val background = dialogContentWithBackground.background!! originalDialogBackgroundColor = GhostedViewLaunchAnimatorController.findGradientDrawable(background) ?.color ?.defaultColor ?: Color.BLACK if (isOriginalWindowFullScreen) { // If the original window is full screen, the ViewGroup with background might already be // correctly laid out. Make sure we relayout and that the layout listener below is still // called. dialogContentWithBackground.layout(0, 0, 0, 0) dialogContentWithBackground.requestLayout() } // Start the animation when the dialog is laid out in the center of the host dialog. dialogContentParent.addOnLayoutChangeListener(object : View.OnLayoutChangeListener { dialogContentWithBackground.addOnLayoutChangeListener(object : View.OnLayoutChangeListener { override fun onLayoutChange( view: View, left: Int, Loading @@ -515,7 +542,7 @@ private class AnimatedDialog( oldRight: Int, oldBottom: Int ) { dialogContentParent.removeOnLayoutChangeListener(this) dialogContentWithBackground.removeOnLayoutChangeListener(this) isOriginalDialogViewLaidOut = true maybeStartLaunchAnimation() Loading @@ -523,6 +550,25 @@ private class AnimatedDialog( }) } private fun findFirstViewGroupWithBackground(view: View): ViewGroup? { if (view !is ViewGroup) { return null } if (view.background != null) { return view } for (i in 0 until view.childCount) { val match = findFirstViewGroupWithBackground(view.getChildAt(i)) if (match != null) { return match } } return null } fun onOriginalDialogSizeChanged() { // The dialog is the single child of the root. if (hostDialogRoot.childCount != 1) { Loading Loading @@ -571,7 +617,8 @@ private class AnimatedDialog( // at the end of the launch animation, because the lauch animation already correctly // handles bounds changes. if (backgroundLayoutListener != null) { dialogContentParent.addOnLayoutChangeListener(backgroundLayoutListener) dialogContentWithBackground!! .addOnLayoutChangeListener(backgroundLayoutListener) } } ) Loading Loading @@ -638,10 +685,12 @@ private class AnimatedDialog( (touchSurface as? LaunchableView)?.setShouldBlockVisibilityChanges(false) touchSurface.visibility = View.VISIBLE dialogContentParent.visibility = View.INVISIBLE val dialogContentWithBackground = this.dialogContentWithBackground!! dialogContentWithBackground.visibility = View.INVISIBLE if (backgroundLayoutListener != null) { dialogContentParent.removeOnLayoutChangeListener(backgroundLayoutListener) dialogContentWithBackground .removeOnLayoutChangeListener(backgroundLayoutListener) } // The animated ghost was just removed. We create a temporary ghost that will be Loading Loading @@ -674,8 +723,8 @@ private class AnimatedDialog( ) { // Create 2 ghost controllers to animate both the dialog and the touch surface in the host // dialog. val startView = if (isLaunching) touchSurface else dialogContentParent val endView = if (isLaunching) dialogContentParent else touchSurface val startView = if (isLaunching) touchSurface else dialogContentWithBackground!! val endView = if (isLaunching) dialogContentWithBackground!! else touchSurface val startViewController = GhostedViewLaunchAnimatorController(startView) val endViewController = GhostedViewLaunchAnimatorController(endView) startViewController.launchContainer = hostDialogRoot Loading Loading @@ -736,7 +785,9 @@ private class AnimatedDialog( } private fun shouldAnimateDialogIntoView(): Boolean { if (exitAnimationDisabled) { // Don't animate if the dialog was previously hidden using hide() (either on the host dialog // or on the original dialog) or if we disabled the exit animation. if (exitAnimationDisabled || !hostDialog.isShowing) { return false } Loading
packages/SystemUI/res/values/styles.xml +4 −4 Original line number Diff line number Diff line Loading @@ -373,11 +373,11 @@ <item name="android:windowIsFloating">true</item> </style> <style name="Theme.SystemUI.Dialog.GlobalActionsLite" parent="@android:style/Theme.DeviceDefault.Light.NoActionBar.Fullscreen"> <item name="android:windowIsFloating">true</item> <style name="Theme.SystemUI.Dialog.GlobalActionsLite" parent="Theme.SystemUI.Dialog"> <!-- Settings windowFullscreen: true is necessary to be able to intercept touch events --> <!-- that would otherwise be intercepted by the Shade. --> <item name="android:windowFullscreen">true</item> <item name="android:windowBackground">@android:color/transparent</item> <item name="android:backgroundDimEnabled">true</item> <item name="android:windowCloseOnTouchOutside">true</item> </style> <style name="QSBorderlessButton"> Loading
packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java +89 −156 File changed.Preview size limit exceeded, changes collapsed. Show changes
packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java +1 −1 Original line number Diff line number Diff line Loading @@ -82,7 +82,7 @@ public class GlobalActionsImpl implements GlobalActions, CommandQueue.Callbacks if (mDisabled) return; mGlobalActionsDialog = mGlobalActionsDialogLazy.get(); mGlobalActionsDialog.showOrHideDialog(mKeyguardStateController.isShowing(), mDeviceProvisionedController.isDeviceProvisioned()); mDeviceProvisionedController.isDeviceProvisioned(), null /* view */); } @Override Loading
packages/SystemUI/src/com/android/systemui/qs/FooterActionsController.kt +1 −1 Original line number Diff line number Diff line Loading @@ -116,7 +116,7 @@ class FooterActionsController @Inject constructor( } } else if (v === powerMenuLite) { uiEventLogger.log(GlobalActionsDialogLite.GlobalActionsEvent.GA_OPEN_QS) globalActionsDialog.showOrHideDialog(false, true) globalActionsDialog.showOrHideDialog(false, true, v) } } Loading