Merge "Use Expandable instead of View in FooterActionsViewModel (1/2)" into tm-qpr-dev

This commit is contained in:
TreeHugger Robot
2022-10-20 20:16:10 +00:00
committed by Android (Google) Code Review
26 changed files with 384 additions and 278 deletions

View File

@@ -25,7 +25,6 @@ import android.graphics.Rect
import android.os.Looper import android.os.Looper
import android.util.Log import android.util.Log
import android.util.MathUtils import android.util.MathUtils
import android.view.GhostView
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.view.ViewGroup.LayoutParams.MATCH_PARENT import android.view.ViewGroup.LayoutParams.MATCH_PARENT
@@ -86,6 +85,9 @@ constructor(
*/ */
val sourceIdentity: Any val sourceIdentity: Any
/** The CUJ associated to this controller. */
val cuj: DialogCuj?
/** /**
* Move the drawing of the source in the overlay of [viewGroup]. * Move the drawing of the source in the overlay of [viewGroup].
* *
@@ -142,7 +144,31 @@ constructor(
* controlled by this controller. * controlled by this controller.
*/ */
// TODO(b/252723237): Make this non-nullable // TODO(b/252723237): Make this non-nullable
fun jankConfigurationBuilder(cuj: Int): InteractionJankMonitor.Configuration.Builder? fun jankConfigurationBuilder(): InteractionJankMonitor.Configuration.Builder?
companion object {
/**
* Create a [Controller] that can animate [source] to and from a dialog.
*
* Important: The view must be attached to a [ViewGroup] when calling this function and
* during the animation. For safety, this method will return null when it is not.
*
* Note: The background of [view] should be a (rounded) rectangle so that it can be
* properly animated.
*/
fun fromView(source: View, cuj: DialogCuj? = null): Controller? {
if (source.parent !is ViewGroup) {
Log.e(
TAG,
"Skipping animation as view $source is not attached to a ViewGroup",
Exception(),
)
return null
}
return ViewDialogLaunchAnimatorController(source, cuj)
}
}
} }
/** /**
@@ -172,7 +198,12 @@ constructor(
cuj: DialogCuj? = null, cuj: DialogCuj? = null,
animateBackgroundBoundsChange: Boolean = false animateBackgroundBoundsChange: Boolean = false
) { ) {
show(dialog, createController(view), cuj, animateBackgroundBoundsChange) val controller = Controller.fromView(view, cuj)
if (controller == null) {
dialog.show()
} else {
show(dialog, controller, animateBackgroundBoundsChange)
}
} }
/** /**
@@ -187,10 +218,10 @@ constructor(
* Caveats: When calling this function and [dialog] is not a fullscreen dialog, then it will be * Caveats: When calling this function and [dialog] is not a fullscreen dialog, then it will be
* made fullscreen and 2 views will be inserted between the dialog DecorView and its children. * made fullscreen and 2 views will be inserted between the dialog DecorView and its children.
*/ */
@JvmOverloads
fun show( fun show(
dialog: Dialog, dialog: Dialog,
controller: Controller, controller: Controller,
cuj: DialogCuj? = null,
animateBackgroundBoundsChange: Boolean = false animateBackgroundBoundsChange: Boolean = false
) { ) {
if (Looper.myLooper() != Looper.getMainLooper()) { if (Looper.myLooper() != Looper.getMainLooper()) {
@@ -207,7 +238,10 @@ constructor(
it.dialog.window.decorView.viewRootImpl == controller.viewRoot it.dialog.window.decorView.viewRootImpl == controller.viewRoot
} }
val animateFrom = val animateFrom =
animatedParent?.dialogContentWithBackground?.let { createController(it) } ?: controller animatedParent?.dialogContentWithBackground?.let {
Controller.fromView(it, controller.cuj)
}
?: controller
if (animatedParent == null && animateFrom !is LaunchableView) { if (animatedParent == null && animateFrom !is LaunchableView) {
// Make sure the View we launch from implements LaunchableView to avoid visibility // Make sure the View we launch from implements LaunchableView to avoid visibility
@@ -244,96 +278,12 @@ constructor(
animateBackgroundBoundsChange, animateBackgroundBoundsChange,
animatedParent, animatedParent,
isForTesting, isForTesting,
cuj,
) )
openedDialogs.add(animatedDialog) openedDialogs.add(animatedDialog)
animatedDialog.start() animatedDialog.start()
} }
/** Create a [Controller] that can animate [source] to & from a dialog. */
private fun createController(source: View): Controller {
return object : Controller {
override val viewRoot: ViewRootImpl
get() = source.viewRootImpl
override val sourceIdentity: Any = source
override fun startDrawingInOverlayOf(viewGroup: ViewGroup) {
// Create a temporary ghost of the source (which will make it invisible) and add it
// to the host dialog.
GhostView.addGhost(source, viewGroup)
// The ghost of the source was just created, so the source is currently invisible.
// We need to make sure that it stays invisible as long as the dialog is shown or
// animating.
(source as? LaunchableView)?.setShouldBlockVisibilityChanges(true)
}
override fun stopDrawingInOverlay() {
// Note: here we should remove the ghost from the overlay, but in practice this is
// already done by the launch controllers created below.
// Make sure we allow the source to change its visibility again.
(source as? LaunchableView)?.setShouldBlockVisibilityChanges(false)
source.visibility = View.VISIBLE
}
override fun createLaunchController(): LaunchAnimator.Controller {
val delegate = GhostedViewLaunchAnimatorController(source)
return object : LaunchAnimator.Controller by delegate {
override fun onLaunchAnimationStart(isExpandingFullyAbove: Boolean) {
// Remove the temporary ghost added by [startDrawingInOverlayOf]. Another
// ghost (that ghosts only the source content, and not its background) will
// be added right after this by the delegate and will be animated.
GhostView.removeGhost(source)
delegate.onLaunchAnimationStart(isExpandingFullyAbove)
}
override fun onLaunchAnimationEnd(isExpandingFullyAbove: Boolean) {
delegate.onLaunchAnimationEnd(isExpandingFullyAbove)
// We hide the source when the dialog is showing. We will make this view
// visible again when dismissing the dialog. This does nothing if the source
// implements [LaunchableView], as it's already INVISIBLE in that case.
source.visibility = View.INVISIBLE
}
}
}
override fun createExitController(): LaunchAnimator.Controller {
return GhostedViewLaunchAnimatorController(source)
}
override fun shouldAnimateExit(): Boolean {
// The source should be invisible by now, if it's not then something else changed
// its visibility and we probably don't want to run the animation.
if (source.visibility != View.INVISIBLE) {
return false
}
return source.isAttachedToWindow && ((source.parent as? View)?.isShown ?: true)
}
override fun onExitAnimationCancelled() {
// Make sure we allow the source to change its visibility again.
(source as? LaunchableView)?.setShouldBlockVisibilityChanges(false)
// If the view is invisible it's probably because of us, so we make it visible
// again.
if (source.visibility == View.INVISIBLE) {
source.visibility = View.VISIBLE
}
}
override fun jankConfigurationBuilder(
cuj: Int
): InteractionJankMonitor.Configuration.Builder? {
return InteractionJankMonitor.Configuration.Builder.withView(cuj, source)
}
}
}
/** /**
* Launch [dialog] from [another dialog][animateFrom] that was shown using [show]. This will * Launch [dialog] from [another dialog][animateFrom] that was shown using [show]. This will
* allow for dismissing the whole stack. * allow for dismissing the whole stack.
@@ -563,9 +513,6 @@ private class AnimatedDialog(
* Whether synchronization should be disabled, which can be useful if we are running in a test. * Whether synchronization should be disabled, which can be useful if we are running in a test.
*/ */
private val forceDisableSynchronization: Boolean, private val forceDisableSynchronization: Boolean,
/** Interaction to which the dialog animation is associated. */
private val cuj: DialogCuj? = null
) { ) {
/** /**
* The DecorView of this dialog window. * The DecorView of this dialog window.
@@ -618,8 +565,9 @@ private class AnimatedDialog(
private var hasInstrumentedJank = false private var hasInstrumentedJank = false
fun start() { fun start() {
val cuj = controller.cuj
if (cuj != null) { if (cuj != null) {
val config = controller.jankConfigurationBuilder(cuj.cujType) val config = controller.jankConfigurationBuilder()
if (config != null) { if (config != null) {
if (cuj.tag != null) { if (cuj.tag != null) {
config.setTag(cuj.tag) config.setTag(cuj.tag)
@@ -917,7 +865,7 @@ private class AnimatedDialog(
} }
if (hasInstrumentedJank) { if (hasInstrumentedJank) {
interactionJankMonitor.end(cuj!!.cujType) interactionJankMonitor.end(controller.cuj!!.cujType)
} }
} }
) )

View File

@@ -30,7 +30,12 @@ interface Expandable {
*/ */
fun activityLaunchController(cujType: Int? = null): ActivityLaunchAnimator.Controller? fun activityLaunchController(cujType: Int? = null): ActivityLaunchAnimator.Controller?
// TODO(b/230830644): Introduce DialogLaunchAnimator and a function to expose it here. /**
* Create a [DialogLaunchAnimator.Controller] that can be used to expand this [Expandable] into
* a Dialog, or return `null` if this [Expandable] should not be animated (e.g. if it is
* currently not attached or visible).
*/
fun dialogLaunchController(cuj: DialogCuj? = null): DialogLaunchAnimator.Controller?
companion object { companion object {
/** /**
@@ -39,6 +44,7 @@ interface Expandable {
* Note: The background of [view] should be a (rounded) rectangle so that it can be properly * Note: The background of [view] should be a (rounded) rectangle so that it can be properly
* animated. * animated.
*/ */
@JvmStatic
fun fromView(view: View): Expandable { fun fromView(view: View): Expandable {
return object : Expandable { return object : Expandable {
override fun activityLaunchController( override fun activityLaunchController(
@@ -46,6 +52,12 @@ interface Expandable {
): ActivityLaunchAnimator.Controller? { ): ActivityLaunchAnimator.Controller? {
return ActivityLaunchAnimator.Controller.fromView(view, cujType) return ActivityLaunchAnimator.Controller.fromView(view, cujType)
} }
override fun dialogLaunchController(
cuj: DialogCuj?
): DialogLaunchAnimator.Controller? {
return DialogLaunchAnimator.Controller.fromView(view, cuj)
}
} }
} }
} }

View File

@@ -0,0 +1,107 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.systemui.animation
import android.view.GhostView
import android.view.View
import android.view.ViewGroup
import android.view.ViewRootImpl
import com.android.internal.jank.InteractionJankMonitor
/** A [DialogLaunchAnimator.Controller] that can animate a [View] from/to a dialog. */
class ViewDialogLaunchAnimatorController
internal constructor(
private val source: View,
override val cuj: DialogCuj?,
) : DialogLaunchAnimator.Controller {
override val viewRoot: ViewRootImpl
get() = source.viewRootImpl
override val sourceIdentity: Any = source
override fun startDrawingInOverlayOf(viewGroup: ViewGroup) {
// Create a temporary ghost of the source (which will make it invisible) and add it
// to the host dialog.
GhostView.addGhost(source, viewGroup)
// The ghost of the source was just created, so the source is currently invisible.
// We need to make sure that it stays invisible as long as the dialog is shown or
// animating.
(source as? LaunchableView)?.setShouldBlockVisibilityChanges(true)
}
override fun stopDrawingInOverlay() {
// Note: here we should remove the ghost from the overlay, but in practice this is
// already done by the launch controllers created below.
// Make sure we allow the source to change its visibility again.
(source as? LaunchableView)?.setShouldBlockVisibilityChanges(false)
source.visibility = View.VISIBLE
}
override fun createLaunchController(): LaunchAnimator.Controller {
val delegate = GhostedViewLaunchAnimatorController(source)
return object : LaunchAnimator.Controller by delegate {
override fun onLaunchAnimationStart(isExpandingFullyAbove: Boolean) {
// Remove the temporary ghost added by [startDrawingInOverlayOf]. Another
// ghost (that ghosts only the source content, and not its background) will
// be added right after this by the delegate and will be animated.
GhostView.removeGhost(source)
delegate.onLaunchAnimationStart(isExpandingFullyAbove)
}
override fun onLaunchAnimationEnd(isExpandingFullyAbove: Boolean) {
delegate.onLaunchAnimationEnd(isExpandingFullyAbove)
// We hide the source when the dialog is showing. We will make this view
// visible again when dismissing the dialog. This does nothing if the source
// implements [LaunchableView], as it's already INVISIBLE in that case.
source.visibility = View.INVISIBLE
}
}
}
override fun createExitController(): LaunchAnimator.Controller {
return GhostedViewLaunchAnimatorController(source)
}
override fun shouldAnimateExit(): Boolean {
// The source should be invisible by now, if it's not then something else changed
// its visibility and we probably don't want to run the animation.
if (source.visibility != View.INVISIBLE) {
return false
}
return source.isAttachedToWindow && ((source.parent as? View)?.isShown ?: true)
}
override fun onExitAnimationCancelled() {
// Make sure we allow the source to change its visibility again.
(source as? LaunchableView)?.setShouldBlockVisibilityChanges(false)
// If the view is invisible it's probably because of us, so we make it visible
// again.
if (source.visibility == View.INVISIBLE) {
source.visibility = View.VISIBLE
}
}
override fun jankConfigurationBuilder(): InteractionJankMonitor.Configuration.Builder? {
val type = cuj?.cujType ?: return null
return InteractionJankMonitor.Configuration.Builder.withView(type, source)
}
}

View File

@@ -40,17 +40,16 @@ import androidx.compose.ui.unit.Density
import androidx.compose.ui.unit.LayoutDirection import androidx.compose.ui.unit.LayoutDirection
import com.android.internal.jank.InteractionJankMonitor import com.android.internal.jank.InteractionJankMonitor
import com.android.systemui.animation.ActivityLaunchAnimator import com.android.systemui.animation.ActivityLaunchAnimator
import com.android.systemui.animation.DialogCuj
import com.android.systemui.animation.DialogLaunchAnimator import com.android.systemui.animation.DialogLaunchAnimator
import com.android.systemui.animation.Expandable
import com.android.systemui.animation.LaunchAnimator import com.android.systemui.animation.LaunchAnimator
import kotlin.math.roundToInt import kotlin.math.roundToInt
/** A controller that can control animated launches. */ /** A controller that can control animated launches from an [Expandable]. */
interface ExpandableController { interface ExpandableController {
/** Create an [ActivityLaunchAnimator.Controller] to animate into an Activity. */ /** The [Expandable] controlled by this controller. */
fun forActivity(): ActivityLaunchAnimator.Controller val expandable: Expandable
/** Create a [DialogLaunchAnimator.Controller] to animate into a Dialog. */
fun forDialog(): DialogLaunchAnimator.Controller
} }
/** /**
@@ -120,12 +119,25 @@ internal class ExpandableControllerImpl(
private val layoutDirection: LayoutDirection, private val layoutDirection: LayoutDirection,
private val isComposed: State<Boolean>, private val isComposed: State<Boolean>,
) : ExpandableController { ) : ExpandableController {
override fun forActivity(): ActivityLaunchAnimator.Controller { override val expandable: Expandable =
return activityController() object : Expandable {
override fun activityLaunchController(
cujType: Int?,
): ActivityLaunchAnimator.Controller? {
if (!isComposed.value) {
return null
} }
override fun forDialog(): DialogLaunchAnimator.Controller { return activityController(cujType)
return dialogController() }
override fun dialogLaunchController(cuj: DialogCuj?): DialogLaunchAnimator.Controller? {
if (!isComposed.value) {
return null
}
return dialogController(cuj)
}
} }
/** /**
@@ -233,7 +245,7 @@ internal class ExpandableControllerImpl(
} }
/** Create an [ActivityLaunchAnimator.Controller] that can be used to animate activities. */ /** Create an [ActivityLaunchAnimator.Controller] that can be used to animate activities. */
private fun activityController(): ActivityLaunchAnimator.Controller { private fun activityController(cujType: Int?): ActivityLaunchAnimator.Controller {
val delegate = launchController() val delegate = launchController()
return object : ActivityLaunchAnimator.Controller, LaunchAnimator.Controller by delegate { return object : ActivityLaunchAnimator.Controller, LaunchAnimator.Controller by delegate {
override fun onLaunchAnimationStart(isExpandingFullyAbove: Boolean) { override fun onLaunchAnimationStart(isExpandingFullyAbove: Boolean) {
@@ -248,10 +260,11 @@ internal class ExpandableControllerImpl(
} }
} }
private fun dialogController(): DialogLaunchAnimator.Controller { private fun dialogController(cuj: DialogCuj?): DialogLaunchAnimator.Controller {
return object : DialogLaunchAnimator.Controller { return object : DialogLaunchAnimator.Controller {
override val viewRoot: ViewRootImpl = composeViewRoot.viewRootImpl override val viewRoot: ViewRootImpl = composeViewRoot.viewRootImpl
override val sourceIdentity: Any = this@ExpandableControllerImpl override val sourceIdentity: Any = this@ExpandableControllerImpl
override val cuj: DialogCuj? = cuj
override fun startDrawingInOverlayOf(viewGroup: ViewGroup) { override fun startDrawingInOverlayOf(viewGroup: ViewGroup) {
val newOverlay = viewGroup.overlay as ViewGroupOverlay val newOverlay = viewGroup.overlay as ViewGroupOverlay
@@ -294,9 +307,7 @@ internal class ExpandableControllerImpl(
isDialogShowing.value = false isDialogShowing.value = false
} }
override fun jankConfigurationBuilder( override fun jankConfigurationBuilder(): InteractionJankMonitor.Configuration.Builder? {
cuj: Int
): InteractionJankMonitor.Configuration.Builder? {
// TODO(b/252723237): Add support for jank monitoring when animating from a // TODO(b/252723237): Add support for jank monitoring when animating from a
// Composable. // Composable.
return null return null

View File

@@ -116,6 +116,7 @@ import com.android.systemui.MultiListLayout;
import com.android.systemui.MultiListLayout.MultiListAdapter; import com.android.systemui.MultiListLayout.MultiListAdapter;
import com.android.systemui.animation.DialogCuj; import com.android.systemui.animation.DialogCuj;
import com.android.systemui.animation.DialogLaunchAnimator; import com.android.systemui.animation.DialogLaunchAnimator;
import com.android.systemui.animation.Expandable;
import com.android.systemui.animation.Interpolators; import com.android.systemui.animation.Interpolators;
import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.colorextraction.SysuiColorExtractor; import com.android.systemui.colorextraction.SysuiColorExtractor;
@@ -448,10 +449,11 @@ public class GlobalActionsDialogLite implements DialogInterface.OnDismissListene
* *
* @param keyguardShowing True if keyguard is showing * @param keyguardShowing True if keyguard is showing
* @param isDeviceProvisioned True if device is provisioned * @param isDeviceProvisioned True if device is provisioned
* @param view The view from which we should animate the dialog when showing it * @param expandable The expandable from which we should animate the dialog when
* showing it
*/ */
public void showOrHideDialog(boolean keyguardShowing, boolean isDeviceProvisioned, public void showOrHideDialog(boolean keyguardShowing, boolean isDeviceProvisioned,
@Nullable View view) { @Nullable Expandable expandable) {
mKeyguardShowing = keyguardShowing; mKeyguardShowing = keyguardShowing;
mDeviceProvisioned = isDeviceProvisioned; mDeviceProvisioned = isDeviceProvisioned;
if (mDialog != null && mDialog.isShowing()) { if (mDialog != null && mDialog.isShowing()) {
@@ -463,7 +465,7 @@ public class GlobalActionsDialogLite implements DialogInterface.OnDismissListene
mDialog.dismiss(); mDialog.dismiss();
mDialog = null; mDialog = null;
} else { } else {
handleShow(view); handleShow(expandable);
} }
} }
@@ -495,7 +497,7 @@ public class GlobalActionsDialogLite implements DialogInterface.OnDismissListene
} }
} }
protected void handleShow(@Nullable View view) { protected void handleShow(@Nullable Expandable expandable) {
awakenIfNecessary(); awakenIfNecessary();
mDialog = createDialog(); mDialog = createDialog();
prepareDialog(); prepareDialog();
@@ -507,10 +509,12 @@ public class GlobalActionsDialogLite implements DialogInterface.OnDismissListene
// Don't acquire soft keyboard focus, to avoid destroying state when capturing bugreports // Don't acquire soft keyboard focus, to avoid destroying state when capturing bugreports
mDialog.getWindow().addFlags(FLAG_ALT_FOCUSABLE_IM); mDialog.getWindow().addFlags(FLAG_ALT_FOCUSABLE_IM);
if (view != null) { DialogLaunchAnimator.Controller controller =
mDialogLaunchAnimator.showFromView(mDialog, view, expandable != null ? expandable.dialogLaunchController(
new DialogCuj(InteractionJankMonitor.CUJ_SHADE_DIALOG_OPEN, new DialogCuj(InteractionJankMonitor.CUJ_SHADE_DIALOG_OPEN,
INTERACTION_JANK_TAG)); INTERACTION_JANK_TAG)) : null;
if (controller != null) {
mDialogLaunchAnimator.show(mDialog, controller);
} else { } else {
mDialog.show(); mDialog.show();
} }

View File

@@ -52,6 +52,7 @@ import com.android.systemui.Dumpable
import com.android.systemui.R import com.android.systemui.R
import com.android.systemui.animation.DialogCuj import com.android.systemui.animation.DialogCuj
import com.android.systemui.animation.DialogLaunchAnimator import com.android.systemui.animation.DialogLaunchAnimator
import com.android.systemui.animation.Expandable
import com.android.systemui.broadcast.BroadcastDispatcher import com.android.systemui.broadcast.BroadcastDispatcher
import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.dagger.qualifiers.Background
@@ -98,10 +99,10 @@ interface FgsManagerController {
fun init() fun init()
/** /**
* Show the foreground services dialog. The dialog will be expanded from [viewLaunchedFrom] if * Show the foreground services dialog. The dialog will be expanded from [expandable] if
* it's not `null`. * it's not `null`.
*/ */
fun showDialog(viewLaunchedFrom: View?) fun showDialog(expandable: Expandable?)
/** Add a [OnNumberOfPackagesChangedListener]. */ /** Add a [OnNumberOfPackagesChangedListener]. */
fun addOnNumberOfPackagesChangedListener(listener: OnNumberOfPackagesChangedListener) fun addOnNumberOfPackagesChangedListener(listener: OnNumberOfPackagesChangedListener)
@@ -367,7 +368,7 @@ class FgsManagerControllerImpl @Inject constructor(
override fun shouldUpdateFooterVisibility() = dialog == null override fun shouldUpdateFooterVisibility() = dialog == null
override fun showDialog(viewLaunchedFrom: View?) { override fun showDialog(expandable: Expandable?) {
synchronized(lock) { synchronized(lock) {
if (dialog == null) { if (dialog == null) {
@@ -403,16 +404,18 @@ class FgsManagerControllerImpl @Inject constructor(
} }
mainExecutor.execute { mainExecutor.execute {
viewLaunchedFrom val controller =
?.let { expandable?.dialogLaunchController(
dialogLaunchAnimator.showFromView( DialogCuj(
dialog, it,
cuj = DialogCuj(
InteractionJankMonitor.CUJ_SHADE_DIALOG_OPEN, InteractionJankMonitor.CUJ_SHADE_DIALOG_OPEN,
INTERACTION_JANK_TAG INTERACTION_JANK_TAG,
) )
) )
} ?: dialog.show() if (controller != null) {
dialogLaunchAnimator.show(dialog, controller)
} else {
dialog.show()
}
} }
backgroundExecutor.execute { backgroundExecutor.execute {

View File

@@ -32,6 +32,7 @@ import com.android.internal.logging.nano.MetricsProto
import com.android.keyguard.KeyguardUpdateMonitor import com.android.keyguard.KeyguardUpdateMonitor
import com.android.systemui.R import com.android.systemui.R
import com.android.systemui.animation.ActivityLaunchAnimator import com.android.systemui.animation.ActivityLaunchAnimator
import com.android.systemui.animation.Expandable
import com.android.systemui.globalactions.GlobalActionsDialogLite import com.android.systemui.globalactions.GlobalActionsDialogLite
import com.android.systemui.plugins.ActivityStarter import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.plugins.FalsingManager import com.android.systemui.plugins.FalsingManager
@@ -156,7 +157,7 @@ internal class FooterActionsController @Inject constructor(
startSettingsActivity() startSettingsActivity()
} else if (v === powerMenuLite) { } else if (v === powerMenuLite) {
uiEventLogger.log(GlobalActionsDialogLite.GlobalActionsEvent.GA_OPEN_QS) uiEventLogger.log(GlobalActionsDialogLite.GlobalActionsEvent.GA_OPEN_QS)
globalActionsDialog?.showOrHideDialog(false, true, v) globalActionsDialog?.showOrHideDialog(false, true, Expandable.fromView(powerMenuLite))
} }
} }

View File

@@ -29,6 +29,7 @@ import android.widget.TextView;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import com.android.systemui.R; import com.android.systemui.R;
import com.android.systemui.animation.Expandable;
import com.android.systemui.dagger.qualifiers.Background; import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.qs.dagger.QSScope; import com.android.systemui.qs.dagger.QSScope;
@@ -130,7 +131,7 @@ public class QSFgsManagerFooter implements View.OnClickListener,
@Override @Override
public void onClick(View view) { public void onClick(View view) {
mFgsManagerController.showDialog(mRootView); mFgsManagerController.showDialog(Expandable.fromView(view));
} }
public void refreshState() { public void refreshState() {

View File

@@ -39,6 +39,7 @@ import androidx.annotation.Nullable;
import com.android.internal.util.FrameworkStatsLog; import com.android.internal.util.FrameworkStatsLog;
import com.android.systemui.FontSizeUtils; import com.android.systemui.FontSizeUtils;
import com.android.systemui.R; import com.android.systemui.R;
import com.android.systemui.animation.Expandable;
import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.common.shared.model.Icon; import com.android.systemui.common.shared.model.Icon;
import com.android.systemui.dagger.qualifiers.Background; import com.android.systemui.dagger.qualifiers.Background;
@@ -169,7 +170,7 @@ public class QSSecurityFooter extends ViewController<View>
// TODO(b/242040009): Remove this. // TODO(b/242040009): Remove this.
public void showDeviceMonitoringDialog() { public void showDeviceMonitoringDialog() {
mQSSecurityFooterUtils.showDeviceMonitoringDialog(mContext, mView); mQSSecurityFooterUtils.showDeviceMonitoringDialog(mContext, Expandable.fromView(mView));
} }
public void refreshState() { public void refreshState() {

View File

@@ -75,6 +75,7 @@ import com.android.internal.jank.InteractionJankMonitor;
import com.android.systemui.R; import com.android.systemui.R;
import com.android.systemui.animation.DialogCuj; import com.android.systemui.animation.DialogCuj;
import com.android.systemui.animation.DialogLaunchAnimator; import com.android.systemui.animation.DialogLaunchAnimator;
import com.android.systemui.animation.Expandable;
import com.android.systemui.common.shared.model.ContentDescription; import com.android.systemui.common.shared.model.ContentDescription;
import com.android.systemui.common.shared.model.Icon; import com.android.systemui.common.shared.model.Icon;
import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.SysUISingleton;
@@ -190,8 +191,9 @@ public class QSSecurityFooterUtils implements DialogInterface.OnClickListener {
} }
/** Show the device monitoring dialog. */ /** Show the device monitoring dialog. */
public void showDeviceMonitoringDialog(Context quickSettingsContext, @Nullable View view) { public void showDeviceMonitoringDialog(Context quickSettingsContext,
createDialog(quickSettingsContext, view); @Nullable Expandable expandable) {
createDialog(quickSettingsContext, expandable);
} }
/** /**
@@ -440,7 +442,7 @@ public class QSSecurityFooterUtils implements DialogInterface.OnClickListener {
} }
} }
private void createDialog(Context quickSettingsContext, @Nullable View view) { private void createDialog(Context quickSettingsContext, @Nullable Expandable expandable) {
mShouldUseSettingsButton.set(false); mShouldUseSettingsButton.set(false);
mBgHandler.post(() -> { mBgHandler.post(() -> {
String settingsButtonText = getSettingsButton(); String settingsButtonText = getSettingsButton();
@@ -453,9 +455,12 @@ public class QSSecurityFooterUtils implements DialogInterface.OnClickListener {
? settingsButtonText : getNegativeButton(), this); ? settingsButtonText : getNegativeButton(), this);
mDialog.setView(dialogView); mDialog.setView(dialogView);
if (view != null && view.isAggregatedVisible()) { DialogLaunchAnimator.Controller controller =
mDialogLaunchAnimator.showFromView(mDialog, view, new DialogCuj( expandable != null ? expandable.dialogLaunchController(new DialogCuj(
InteractionJankMonitor.CUJ_SHADE_DIALOG_OPEN, INTERACTION_JANK_TAG)); InteractionJankMonitor.CUJ_SHADE_DIALOG_OPEN, INTERACTION_JANK_TAG))
: null;
if (controller != null) {
mDialogLaunchAnimator.show(mDialog, controller);
} else { } else {
mDialog.show(); mDialog.show();
} }

View File

@@ -23,13 +23,11 @@ import android.content.Intent
import android.content.IntentFilter import android.content.IntentFilter
import android.os.UserHandle import android.os.UserHandle
import android.provider.Settings import android.provider.Settings
import android.view.View
import com.android.internal.jank.InteractionJankMonitor import com.android.internal.jank.InteractionJankMonitor
import com.android.internal.logging.MetricsLogger import com.android.internal.logging.MetricsLogger
import com.android.internal.logging.UiEventLogger import com.android.internal.logging.UiEventLogger
import com.android.internal.logging.nano.MetricsProto import com.android.internal.logging.nano.MetricsProto
import com.android.internal.util.FrameworkStatsLog import com.android.internal.util.FrameworkStatsLog
import com.android.systemui.animation.ActivityLaunchAnimator
import com.android.systemui.animation.Expandable import com.android.systemui.animation.Expandable
import com.android.systemui.broadcast.BroadcastDispatcher import com.android.systemui.broadcast.BroadcastDispatcher
import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.SysUISingleton
@@ -74,37 +72,27 @@ interface FooterActionsInteractor {
val deviceMonitoringDialogRequests: Flow<Unit> val deviceMonitoringDialogRequests: Flow<Unit>
/** /**
* Show the device monitoring dialog, expanded from [view]. * Show the device monitoring dialog, expanded from [expandable] if it's not null.
*
* Important: [view] must be associated to the same [Context] as the [Quick Settings fragment]
* [com.android.systemui.qs.QSFragment].
*/
// TODO(b/230830644): Replace view by Expandable interface.
fun showDeviceMonitoringDialog(view: View)
/**
* Show the device monitoring dialog.
* *
* Important: [quickSettingsContext] *must* be the [Context] associated to the [Quick Settings * Important: [quickSettingsContext] *must* be the [Context] associated to the [Quick Settings
* fragment][com.android.systemui.qs.QSFragment]. * fragment][com.android.systemui.qs.QSFragment].
*/ */
// TODO(b/230830644): Replace view by Expandable interface. fun showDeviceMonitoringDialog(quickSettingsContext: Context, expandable: Expandable?)
fun showDeviceMonitoringDialog(quickSettingsContext: Context)
/** Show the foreground services dialog. */ /** Show the foreground services dialog. */
// TODO(b/230830644): Replace view by Expandable interface. fun showForegroundServicesDialog(expandable: Expandable)
fun showForegroundServicesDialog(view: View)
/** Show the power menu dialog. */ /** Show the power menu dialog. */
// TODO(b/230830644): Replace view by Expandable interface. fun showPowerMenuDialog(
fun showPowerMenuDialog(globalActionsDialogLite: GlobalActionsDialogLite, view: View) globalActionsDialogLite: GlobalActionsDialogLite,
expandable: Expandable,
)
/** Show the settings. */ /** Show the settings. */
fun showSettings(expandable: Expandable) fun showSettings(expandable: Expandable)
/** Show the user switcher. */ /** Show the user switcher. */
// TODO(b/230830644): Replace view by Expandable interface. fun showUserSwitcher(context: Context, expandable: Expandable)
fun showUserSwitcher(view: View)
} }
@SysUISingleton @SysUISingleton
@@ -147,28 +135,32 @@ constructor(
null, null,
) )
override fun showDeviceMonitoringDialog(view: View) { override fun showDeviceMonitoringDialog(
qsSecurityFooterUtils.showDeviceMonitoringDialog(view.context, view) quickSettingsContext: Context,
expandable: Expandable?,
) {
qsSecurityFooterUtils.showDeviceMonitoringDialog(quickSettingsContext, expandable)
if (expandable != null) {
DevicePolicyEventLogger.createEvent( DevicePolicyEventLogger.createEvent(
FrameworkStatsLog.DEVICE_POLICY_EVENT__EVENT_ID__DO_USER_INFO_CLICKED FrameworkStatsLog.DEVICE_POLICY_EVENT__EVENT_ID__DO_USER_INFO_CLICKED
) )
.write() .write()
} }
override fun showDeviceMonitoringDialog(quickSettingsContext: Context) {
qsSecurityFooterUtils.showDeviceMonitoringDialog(quickSettingsContext, /* view= */ null)
} }
override fun showForegroundServicesDialog(view: View) { override fun showForegroundServicesDialog(expandable: Expandable) {
fgsManagerController.showDialog(view) fgsManagerController.showDialog(expandable)
} }
override fun showPowerMenuDialog(globalActionsDialogLite: GlobalActionsDialogLite, view: View) { override fun showPowerMenuDialog(
globalActionsDialogLite: GlobalActionsDialogLite,
expandable: Expandable,
) {
uiEventLogger.log(GlobalActionsDialogLite.GlobalActionsEvent.GA_OPEN_QS) uiEventLogger.log(GlobalActionsDialogLite.GlobalActionsEvent.GA_OPEN_QS)
globalActionsDialogLite.showOrHideDialog( globalActionsDialogLite.showOrHideDialog(
/* keyguardShowing= */ false, /* keyguardShowing= */ false,
/* isDeviceProvisioned= */ true, /* isDeviceProvisioned= */ true,
view, expandable,
) )
} }
@@ -189,21 +181,21 @@ constructor(
) )
} }
override fun showUserSwitcher(view: View) { override fun showUserSwitcher(context: Context, expandable: Expandable) {
if (!featureFlags.isEnabled(Flags.FULL_SCREEN_USER_SWITCHER)) { if (!featureFlags.isEnabled(Flags.FULL_SCREEN_USER_SWITCHER)) {
userSwitchDialogController.showDialog(view) userSwitchDialogController.showDialog(context, expandable)
return return
} }
val intent = val intent =
Intent(view.context, UserSwitcherActivity::class.java).apply { Intent(context, UserSwitcherActivity::class.java).apply {
addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK) addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK)
} }
activityStarter.startActivity( activityStarter.startActivity(
intent, intent,
true /* dismissShade */, true /* dismissShade */,
ActivityLaunchAnimator.Controller.fromView(view, null), expandable.activityLaunchController(),
true /* showOverlockscreenwhenlocked */, true /* showOverlockscreenwhenlocked */,
UserHandle.SYSTEM, UserHandle.SYSTEM,
) )

View File

@@ -31,6 +31,7 @@ import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle import androidx.lifecycle.repeatOnLifecycle
import com.android.systemui.R import com.android.systemui.R
import com.android.systemui.animation.Expandable
import com.android.systemui.common.ui.binder.IconViewBinder import com.android.systemui.common.ui.binder.IconViewBinder
import com.android.systemui.lifecycle.repeatWhenAttached import com.android.systemui.lifecycle.repeatWhenAttached
import com.android.systemui.people.ui.view.PeopleViewBinder.bind import com.android.systemui.people.ui.view.PeopleViewBinder.bind
@@ -125,7 +126,7 @@ object FooterActionsViewBinder {
launch { launch {
viewModel.security.collect { security -> viewModel.security.collect { security ->
if (previousSecurity != security) { if (previousSecurity != security) {
bindSecurity(securityHolder, security) bindSecurity(view.context, securityHolder, security)
previousSecurity = security previousSecurity = security
} }
} }
@@ -159,6 +160,7 @@ object FooterActionsViewBinder {
} }
private fun bindSecurity( private fun bindSecurity(
quickSettingsContext: Context,
securityHolder: TextButtonViewHolder, securityHolder: TextButtonViewHolder,
security: FooterActionsSecurityButtonViewModel?, security: FooterActionsSecurityButtonViewModel?,
) { ) {
@@ -171,9 +173,12 @@ object FooterActionsViewBinder {
// Make sure that the chevron is visible and that the button is clickable if there is a // Make sure that the chevron is visible and that the button is clickable if there is a
// listener. // listener.
val chevron = securityHolder.chevron val chevron = securityHolder.chevron
if (security.onClick != null) { val onClick = security.onClick
if (onClick != null) {
securityView.isClickable = true securityView.isClickable = true
securityView.setOnClickListener(security.onClick) securityView.setOnClickListener {
onClick(quickSettingsContext, Expandable.fromView(securityView))
}
chevron.isVisible = true chevron.isVisible = true
} else { } else {
securityView.isClickable = false securityView.isClickable = false
@@ -205,7 +210,9 @@ object FooterActionsViewBinder {
foregroundServicesWithNumberView.isVisible = false foregroundServicesWithNumberView.isVisible = false
foregroundServicesWithTextView.isVisible = true foregroundServicesWithTextView.isVisible = true
foregroundServicesWithTextView.setOnClickListener(foregroundServices.onClick) foregroundServicesWithTextView.setOnClickListener {
foregroundServices.onClick(Expandable.fromView(foregroundServicesWithTextView))
}
foregroundServicesWithTextHolder.text.text = foregroundServices.text foregroundServicesWithTextHolder.text.text = foregroundServices.text
foregroundServicesWithTextHolder.newDot.isVisible = foregroundServices.hasNewChanges foregroundServicesWithTextHolder.newDot.isVisible = foregroundServices.hasNewChanges
} else { } else {
@@ -213,7 +220,9 @@ object FooterActionsViewBinder {
foregroundServicesWithTextView.isVisible = false foregroundServicesWithTextView.isVisible = false
foregroundServicesWithNumberView.visibility = View.VISIBLE foregroundServicesWithNumberView.visibility = View.VISIBLE
foregroundServicesWithNumberView.setOnClickListener(foregroundServices.onClick) foregroundServicesWithNumberView.setOnClickListener {
foregroundServices.onClick(Expandable.fromView(foregroundServicesWithTextView))
}
foregroundServicesWithNumberHolder.number.text = foregroundServicesCount.toString() foregroundServicesWithNumberHolder.number.text = foregroundServicesCount.toString()
foregroundServicesWithNumberHolder.number.contentDescription = foregroundServices.text foregroundServicesWithNumberHolder.number.contentDescription = foregroundServices.text
foregroundServicesWithNumberHolder.newDot.isVisible = foregroundServices.hasNewChanges foregroundServicesWithNumberHolder.newDot.isVisible = foregroundServices.hasNewChanges
@@ -229,7 +238,7 @@ object FooterActionsViewBinder {
} }
buttonView.setBackgroundResource(model.background) buttonView.setBackgroundResource(model.background)
buttonView.setOnClickListener(model.onClick) buttonView.setOnClickListener { model.onClick(Expandable.fromView(buttonView)) }
val icon = model.icon val icon = model.icon
val iconView = button.icon val iconView = button.icon

View File

@@ -17,7 +17,7 @@
package com.android.systemui.qs.footer.ui.viewmodel package com.android.systemui.qs.footer.ui.viewmodel
import android.annotation.DrawableRes import android.annotation.DrawableRes
import android.view.View import com.android.systemui.animation.Expandable
import com.android.systemui.common.shared.model.Icon import com.android.systemui.common.shared.model.Icon
/** /**
@@ -29,7 +29,5 @@ data class FooterActionsButtonViewModel(
val icon: Icon, val icon: Icon,
val iconTint: Int?, val iconTint: Int?,
@DrawableRes val background: Int, @DrawableRes val background: Int,
// TODO(b/230830644): Replace View by an Expandable interface that can expand in either dialog val onClick: (Expandable) -> Unit,
// or activity.
val onClick: (View) -> Unit,
) )

View File

@@ -16,7 +16,7 @@
package com.android.systemui.qs.footer.ui.viewmodel package com.android.systemui.qs.footer.ui.viewmodel
import android.view.View import com.android.systemui.animation.Expandable
/** A ViewModel for the foreground services button. */ /** A ViewModel for the foreground services button. */
data class FooterActionsForegroundServicesButtonViewModel( data class FooterActionsForegroundServicesButtonViewModel(
@@ -24,5 +24,5 @@ data class FooterActionsForegroundServicesButtonViewModel(
val text: String, val text: String,
val displayText: Boolean, val displayText: Boolean,
val hasNewChanges: Boolean, val hasNewChanges: Boolean,
val onClick: (View) -> Unit, val onClick: (Expandable) -> Unit,
) )

View File

@@ -16,12 +16,13 @@
package com.android.systemui.qs.footer.ui.viewmodel package com.android.systemui.qs.footer.ui.viewmodel
import android.view.View import android.content.Context
import com.android.systemui.animation.Expandable
import com.android.systemui.common.shared.model.Icon import com.android.systemui.common.shared.model.Icon
/** A ViewModel for the security button. */ /** A ViewModel for the security button. */
data class FooterActionsSecurityButtonViewModel( data class FooterActionsSecurityButtonViewModel(
val icon: Icon, val icon: Icon,
val text: String, val text: String,
val onClick: ((View) -> Unit)?, val onClick: ((quickSettingsContext: Context, Expandable) -> Unit)?,
) )

View File

@@ -18,7 +18,6 @@ package com.android.systemui.qs.footer.ui.viewmodel
import android.content.Context import android.content.Context
import android.util.Log import android.util.Log
import android.view.View
import androidx.lifecycle.DefaultLifecycleObserver import androidx.lifecycle.DefaultLifecycleObserver
import androidx.lifecycle.Lifecycle import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.LifecycleOwner
@@ -199,50 +198,51 @@ class FooterActionsViewModel(
*/ */
suspend fun observeDeviceMonitoringDialogRequests(quickSettingsContext: Context) { suspend fun observeDeviceMonitoringDialogRequests(quickSettingsContext: Context) {
footerActionsInteractor.deviceMonitoringDialogRequests.collect { footerActionsInteractor.deviceMonitoringDialogRequests.collect {
footerActionsInteractor.showDeviceMonitoringDialog(quickSettingsContext) footerActionsInteractor.showDeviceMonitoringDialog(
quickSettingsContext,
expandable = null,
)
} }
} }
private fun onSecurityButtonClicked(view: View) { private fun onSecurityButtonClicked(quickSettingsContext: Context, expandable: Expandable) {
if (falsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) { if (falsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
return return
} }
footerActionsInteractor.showDeviceMonitoringDialog(view) footerActionsInteractor.showDeviceMonitoringDialog(quickSettingsContext, expandable)
} }
private fun onForegroundServiceButtonClicked(view: View) { private fun onForegroundServiceButtonClicked(expandable: Expandable) {
if (falsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) { if (falsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
return return
} }
footerActionsInteractor.showForegroundServicesDialog(view) footerActionsInteractor.showForegroundServicesDialog(expandable)
} }
private fun onUserSwitcherClicked(view: View) { private fun onUserSwitcherClicked(expandable: Expandable) {
if (falsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) { if (falsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
return return
} }
footerActionsInteractor.showUserSwitcher(view) footerActionsInteractor.showUserSwitcher(context, expandable)
} }
// TODO(b/230830644): Replace View by an Expandable interface that can expand in either dialog private fun onSettingsButtonClicked(expandable: Expandable) {
// or activity.
private fun onSettingsButtonClicked(view: View) {
if (falsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) { if (falsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
return return
} }
footerActionsInteractor.showSettings(Expandable.fromView(view)) footerActionsInteractor.showSettings(expandable)
} }
private fun onPowerButtonClicked(view: View) { private fun onPowerButtonClicked(expandable: Expandable) {
if (falsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) { if (falsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
return return
} }
footerActionsInteractor.showPowerMenuDialog(globalActionsDialogLite, view) footerActionsInteractor.showPowerMenuDialog(globalActionsDialogLite, expandable)
} }
private fun userSwitcherButton( private fun userSwitcherButton(

View File

@@ -23,13 +23,13 @@ import android.content.DialogInterface.BUTTON_NEUTRAL
import android.content.Intent import android.content.Intent
import android.provider.Settings import android.provider.Settings
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View
import androidx.annotation.VisibleForTesting import androidx.annotation.VisibleForTesting
import com.android.internal.jank.InteractionJankMonitor import com.android.internal.jank.InteractionJankMonitor
import com.android.internal.logging.UiEventLogger import com.android.internal.logging.UiEventLogger
import com.android.systemui.R import com.android.systemui.R
import com.android.systemui.animation.DialogCuj import com.android.systemui.animation.DialogCuj
import com.android.systemui.animation.DialogLaunchAnimator import com.android.systemui.animation.DialogLaunchAnimator
import com.android.systemui.animation.Expandable
import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.plugins.ActivityStarter import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.plugins.FalsingManager import com.android.systemui.plugins.FalsingManager
@@ -77,10 +77,10 @@ class UserSwitchDialogController @VisibleForTesting constructor(
* Show a [UserDialog]. * Show a [UserDialog].
* *
* Populate the dialog with information from and adapter obtained from * Populate the dialog with information from and adapter obtained from
* [userDetailViewAdapterProvider] and show it as launched from [view]. * [userDetailViewAdapterProvider] and show it as launched from [expandable].
*/ */
fun showDialog(view: View) { fun showDialog(context: Context, expandable: Expandable) {
with(dialogFactory(view.context)) { with(dialogFactory(context)) {
setShowForAllUsers(true) setShowForAllUsers(true)
setCanceledOnTouchOutside(true) setCanceledOnTouchOutside(true)
@@ -112,13 +112,19 @@ class UserSwitchDialogController @VisibleForTesting constructor(
adapter.linkToViewGroup(gridFrame.findViewById(R.id.grid)) adapter.linkToViewGroup(gridFrame.findViewById(R.id.grid))
dialogLaunchAnimator.showFromView( val controller =
this, view, expandable.dialogLaunchController(
cuj = DialogCuj( DialogCuj(InteractionJankMonitor.CUJ_SHADE_DIALOG_OPEN, INTERACTION_JANK_TAG)
InteractionJankMonitor.CUJ_SHADE_DIALOG_OPEN,
INTERACTION_JANK_TAG
) )
if (controller != null) {
dialogLaunchAnimator.show(
this,
controller,
) )
} else {
show()
}
uiEventLogger.log(QSUserSwitcherEvent.QS_USER_DETAIL_OPEN) uiEventLogger.log(QSUserSwitcherEvent.QS_USER_DETAIL_OPEN)
adapter.injectDialogShower(DialogShowerImpl(this, dialogLaunchAnimator)) adapter.injectDialogShower(DialogShowerImpl(this, dialogLaunchAnimator))
} }

View File

@@ -26,6 +26,7 @@ import android.view.ViewGroup;
import com.android.systemui.R; import com.android.systemui.R;
import com.android.systemui.animation.ActivityLaunchAnimator; import com.android.systemui.animation.ActivityLaunchAnimator;
import com.android.systemui.animation.Expandable;
import com.android.systemui.flags.FeatureFlags; import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags; import com.android.systemui.flags.Flags;
import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.ActivityStarter;
@@ -67,7 +68,7 @@ public class MultiUserSwitchController extends ViewController<MultiUserSwitch> {
ActivityLaunchAnimator.Controller.fromView(v, null), ActivityLaunchAnimator.Controller.fromView(v, null),
true /* showOverlockscreenwhenlocked */, UserHandle.SYSTEM); true /* showOverlockscreenwhenlocked */, UserHandle.SYSTEM);
} else { } else {
mUserSwitchDialogController.showDialog(v); mUserSwitchDialogController.showDialog(v.getContext(), Expandable.fromView(v));
} }
} }
}; };

View File

@@ -19,6 +19,7 @@ package com.android.systemui.statusbar.phone.userswitcher
import android.content.Intent import android.content.Intent
import android.os.UserHandle import android.os.UserHandle
import android.view.View import android.view.View
import com.android.systemui.animation.Expandable
import com.android.systemui.flags.FeatureFlags import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags import com.android.systemui.flags.Flags
import com.android.systemui.plugins.ActivityStarter import com.android.systemui.plugins.ActivityStarter
@@ -75,7 +76,7 @@ class StatusBarUserSwitcherControllerImpl @Inject constructor(
null /* ActivityLaunchAnimator.Controller */, null /* ActivityLaunchAnimator.Controller */,
true /* showOverlockscreenwhenlocked */, UserHandle.SYSTEM) true /* showOverlockscreenwhenlocked */, UserHandle.SYSTEM)
} else { } else {
userSwitcherDialogController.showDialog(view) userSwitcherDialogController.showDialog(view.context, Expandable.fromView(view))
} }
} }

View File

@@ -36,6 +36,7 @@ import com.android.keyguard.KeyguardVisibilityHelper;
import com.android.keyguard.dagger.KeyguardUserSwitcherScope; import com.android.keyguard.dagger.KeyguardUserSwitcherScope;
import com.android.settingslib.drawable.CircleFramedDrawable; import com.android.settingslib.drawable.CircleFramedDrawable;
import com.android.systemui.R; import com.android.systemui.R;
import com.android.systemui.animation.Expandable;
import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.plugins.statusbar.StatusBarStateController;
@@ -190,7 +191,8 @@ public class KeyguardQsUserSwitchController extends ViewController<FrameLayout>
mUiEventLogger.log( mUiEventLogger.log(
LockscreenGestureLogger.LockscreenUiEvent.LOCKSCREEN_SWITCH_USER_TAP); LockscreenGestureLogger.LockscreenUiEvent.LOCKSCREEN_SWITCH_USER_TAP);
mUserSwitchDialogController.showDialog(mUserAvatarViewWithBackground); mUserSwitchDialogController.showDialog(mUserAvatarViewWithBackground.getContext(),
Expandable.fromView(mUserAvatarViewWithBackground));
}); });
mUserAvatarView.setAccessibilityDelegate(new View.AccessibilityDelegate() { mUserAvatarView.setAccessibilityDelegate(new View.AccessibilityDelegate() {

View File

@@ -22,7 +22,6 @@ import static junit.framework.Assert.assertNotNull;
import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Matchers.any; import static org.mockito.Matchers.any;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never; import static org.mockito.Mockito.never;
@@ -52,6 +51,7 @@ import android.text.SpannableStringBuilder;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.TextView; import android.widget.TextView;
import com.android.systemui.R; import com.android.systemui.R;
@@ -97,6 +97,7 @@ public class QSSecurityFooterTest extends SysuiTestCase {
private static final int DEFAULT_ICON_ID = R.drawable.ic_info_outline; private static final int DEFAULT_ICON_ID = R.drawable.ic_info_outline;
private ViewGroup mRootView; private ViewGroup mRootView;
private ViewGroup mSecurityFooterView;
private TextView mFooterText; private TextView mFooterText;
private TestableImageView mPrimaryFooterIcon; private TestableImageView mPrimaryFooterIcon;
private QSSecurityFooter mFooter; private QSSecurityFooter mFooter;
@@ -121,21 +122,26 @@ public class QSSecurityFooterTest extends SysuiTestCase {
Looper looper = mTestableLooper.getLooper(); Looper looper = mTestableLooper.getLooper();
Handler mainHandler = new Handler(looper); Handler mainHandler = new Handler(looper);
when(mUserTracker.getUserInfo()).thenReturn(mock(UserInfo.class)); when(mUserTracker.getUserInfo()).thenReturn(mock(UserInfo.class));
mRootView = (ViewGroup) new LayoutInflaterBuilder(mContext) mSecurityFooterView = (ViewGroup) new LayoutInflaterBuilder(mContext)
.replace("ImageView", TestableImageView.class) .replace("ImageView", TestableImageView.class)
.build().inflate(R.layout.quick_settings_security_footer, null, false); .build().inflate(R.layout.quick_settings_security_footer, null, false);
mFooterUtils = new QSSecurityFooterUtils(getContext(), mFooterUtils = new QSSecurityFooterUtils(getContext(),
getContext().getSystemService(DevicePolicyManager.class), mUserTracker, getContext().getSystemService(DevicePolicyManager.class), mUserTracker,
mainHandler, mActivityStarter, mSecurityController, looper, mDialogLaunchAnimator); mainHandler, mActivityStarter, mSecurityController, looper, mDialogLaunchAnimator);
mFooter = new QSSecurityFooter(mRootView, mainHandler, mSecurityController, looper, mFooter = new QSSecurityFooter(mSecurityFooterView, mainHandler, mSecurityController,
mBroadcastDispatcher, mFooterUtils); looper, mBroadcastDispatcher, mFooterUtils);
mFooterText = mRootView.findViewById(R.id.footer_text); mFooterText = mSecurityFooterView.findViewById(R.id.footer_text);
mPrimaryFooterIcon = mRootView.findViewById(R.id.primary_footer_icon); mPrimaryFooterIcon = mSecurityFooterView.findViewById(R.id.primary_footer_icon);
when(mSecurityController.getDeviceOwnerComponentOnAnyUser()) when(mSecurityController.getDeviceOwnerComponentOnAnyUser())
.thenReturn(DEVICE_OWNER_COMPONENT); .thenReturn(DEVICE_OWNER_COMPONENT);
when(mSecurityController.getDeviceOwnerType(DEVICE_OWNER_COMPONENT)) when(mSecurityController.getDeviceOwnerType(DEVICE_OWNER_COMPONENT))
.thenReturn(DEVICE_OWNER_TYPE_DEFAULT); .thenReturn(DEVICE_OWNER_TYPE_DEFAULT);
// mSecurityFooterView must have a ViewGroup parent so that
// DialogLaunchAnimator.Controller.fromView() does not return null.
mRootView = new FrameLayout(mContext);
mRootView.addView(mSecurityFooterView);
ViewUtils.attachView(mRootView); ViewUtils.attachView(mRootView);
mFooter.init(); mFooter.init();
@@ -153,7 +159,7 @@ public class QSSecurityFooterTest extends SysuiTestCase {
mFooter.refreshState(); mFooter.refreshState();
TestableLooper.get(this).processAllMessages(); TestableLooper.get(this).processAllMessages();
assertEquals(View.GONE, mRootView.getVisibility()); assertEquals(View.GONE, mSecurityFooterView.getVisibility());
} }
@Test @Test
@@ -165,7 +171,7 @@ public class QSSecurityFooterTest extends SysuiTestCase {
TestableLooper.get(this).processAllMessages(); TestableLooper.get(this).processAllMessages();
assertEquals(mContext.getString(R.string.quick_settings_disclosure_management), assertEquals(mContext.getString(R.string.quick_settings_disclosure_management),
mFooterText.getText()); mFooterText.getText());
assertEquals(View.VISIBLE, mRootView.getVisibility()); assertEquals(View.VISIBLE, mSecurityFooterView.getVisibility());
assertEquals(View.VISIBLE, mPrimaryFooterIcon.getVisibility()); assertEquals(View.VISIBLE, mPrimaryFooterIcon.getVisibility());
assertEquals(DEFAULT_ICON_ID, mPrimaryFooterIcon.getLastImageResource()); assertEquals(DEFAULT_ICON_ID, mPrimaryFooterIcon.getLastImageResource());
} }
@@ -181,7 +187,7 @@ public class QSSecurityFooterTest extends SysuiTestCase {
assertEquals(mContext.getString(R.string.quick_settings_disclosure_named_management, assertEquals(mContext.getString(R.string.quick_settings_disclosure_named_management,
MANAGING_ORGANIZATION), MANAGING_ORGANIZATION),
mFooterText.getText()); mFooterText.getText());
assertEquals(View.VISIBLE, mRootView.getVisibility()); assertEquals(View.VISIBLE, mSecurityFooterView.getVisibility());
assertEquals(View.VISIBLE, mPrimaryFooterIcon.getVisibility()); assertEquals(View.VISIBLE, mPrimaryFooterIcon.getVisibility());
assertEquals(DEFAULT_ICON_ID, mPrimaryFooterIcon.getLastImageResource()); assertEquals(DEFAULT_ICON_ID, mPrimaryFooterIcon.getLastImageResource());
} }
@@ -200,7 +206,7 @@ public class QSSecurityFooterTest extends SysuiTestCase {
assertEquals(mContext.getString( assertEquals(mContext.getString(
R.string.quick_settings_financed_disclosure_named_management, R.string.quick_settings_financed_disclosure_named_management,
MANAGING_ORGANIZATION), mFooterText.getText()); MANAGING_ORGANIZATION), mFooterText.getText());
assertEquals(View.VISIBLE, mRootView.getVisibility()); assertEquals(View.VISIBLE, mSecurityFooterView.getVisibility());
assertEquals(View.VISIBLE, mPrimaryFooterIcon.getVisibility()); assertEquals(View.VISIBLE, mPrimaryFooterIcon.getVisibility());
assertEquals(DEFAULT_ICON_ID, mPrimaryFooterIcon.getLastImageResource()); assertEquals(DEFAULT_ICON_ID, mPrimaryFooterIcon.getLastImageResource());
} }
@@ -217,7 +223,7 @@ public class QSSecurityFooterTest extends SysuiTestCase {
mFooter.refreshState(); mFooter.refreshState();
TestableLooper.get(this).processAllMessages(); TestableLooper.get(this).processAllMessages();
assertEquals(View.GONE, mRootView.getVisibility()); assertEquals(View.GONE, mSecurityFooterView.getVisibility());
} }
@Test @Test
@@ -227,8 +233,8 @@ public class QSSecurityFooterTest extends SysuiTestCase {
mFooter.refreshState(); mFooter.refreshState();
TestableLooper.get(this).processAllMessages(); TestableLooper.get(this).processAllMessages();
assertFalse(mRootView.isClickable()); assertFalse(mSecurityFooterView.isClickable());
assertEquals(View.GONE, mRootView.findViewById(R.id.footer_icon).getVisibility()); assertEquals(View.GONE, mSecurityFooterView.findViewById(R.id.footer_icon).getVisibility());
} }
@Test @Test
@@ -241,8 +247,9 @@ public class QSSecurityFooterTest extends SysuiTestCase {
mFooter.refreshState(); mFooter.refreshState();
TestableLooper.get(this).processAllMessages(); TestableLooper.get(this).processAllMessages();
assertTrue(mRootView.isClickable()); assertTrue(mSecurityFooterView.isClickable());
assertEquals(View.VISIBLE, mRootView.findViewById(R.id.footer_icon).getVisibility()); assertEquals(View.VISIBLE,
mSecurityFooterView.findViewById(R.id.footer_icon).getVisibility());
} }
@Test @Test
@@ -254,8 +261,8 @@ public class QSSecurityFooterTest extends SysuiTestCase {
mFooter.refreshState(); mFooter.refreshState();
TestableLooper.get(this).processAllMessages(); TestableLooper.get(this).processAllMessages();
assertFalse(mRootView.isClickable()); assertFalse(mSecurityFooterView.isClickable());
assertEquals(View.GONE, mRootView.findViewById(R.id.footer_icon).getVisibility()); assertEquals(View.GONE, mSecurityFooterView.findViewById(R.id.footer_icon).getVisibility());
} }
@Test @Test
@@ -734,11 +741,11 @@ public class QSSecurityFooterTest extends SysuiTestCase {
@Test @Test
public void testDialogUsesDialogLauncher() { public void testDialogUsesDialogLauncher() {
when(mSecurityController.isDeviceManaged()).thenReturn(true); when(mSecurityController.isDeviceManaged()).thenReturn(true);
mFooter.onClick(mRootView); mFooter.onClick(mSecurityFooterView);
mTestableLooper.processAllMessages(); mTestableLooper.processAllMessages();
verify(mDialogLaunchAnimator).showFromView(any(), eq(mRootView), any()); verify(mDialogLaunchAnimator).show(any(), any());
} }
@Test @Test
@@ -775,7 +782,7 @@ public class QSSecurityFooterTest extends SysuiTestCase {
ArgumentCaptor<AlertDialog> dialogCaptor = ArgumentCaptor.forClass(AlertDialog.class); ArgumentCaptor<AlertDialog> dialogCaptor = ArgumentCaptor.forClass(AlertDialog.class);
mTestableLooper.processAllMessages(); mTestableLooper.processAllMessages();
verify(mDialogLaunchAnimator).showFromView(dialogCaptor.capture(), any(), any()); verify(mDialogLaunchAnimator).show(dialogCaptor.capture(), any());
AlertDialog dialog = dialogCaptor.getValue(); AlertDialog dialog = dialogCaptor.getValue();
dialog.create(); dialog.create();
@@ -817,8 +824,8 @@ public class QSSecurityFooterTest extends SysuiTestCase {
verify(mBroadcastDispatcher).registerReceiverWithHandler(captor.capture(), any(), any(), verify(mBroadcastDispatcher).registerReceiverWithHandler(captor.capture(), any(), any(),
any()); any());
// Pretend view is not visible temporarily // Pretend view is not attached anymore.
mRootView.onVisibilityAggregated(false); mRootView.removeView(mSecurityFooterView);
captor.getValue().onReceive(mContext, captor.getValue().onReceive(mContext,
new Intent(DevicePolicyManager.ACTION_SHOW_DEVICE_MONITORING_DIALOG)); new Intent(DevicePolicyManager.ACTION_SHOW_DEVICE_MONITORING_DIALOG));
mTestableLooper.processAllMessages(); mTestableLooper.processAllMessages();

View File

@@ -23,13 +23,13 @@ import android.os.UserHandle
import android.provider.Settings import android.provider.Settings
import android.testing.AndroidTestingRunner import android.testing.AndroidTestingRunner
import android.testing.TestableLooper import android.testing.TestableLooper
import android.view.View
import androidx.test.filters.SmallTest import androidx.test.filters.SmallTest
import com.android.internal.logging.nano.MetricsProto import com.android.internal.logging.nano.MetricsProto
import com.android.internal.logging.testing.FakeMetricsLogger import com.android.internal.logging.testing.FakeMetricsLogger
import com.android.internal.logging.testing.UiEventLoggerFake import com.android.internal.logging.testing.UiEventLoggerFake
import com.android.systemui.SysuiTestCase import com.android.systemui.SysuiTestCase
import com.android.systemui.animation.ActivityLaunchAnimator import com.android.systemui.animation.ActivityLaunchAnimator
import com.android.systemui.animation.Expandable
import com.android.systemui.flags.FakeFeatureFlags import com.android.systemui.flags.FakeFeatureFlags
import com.android.systemui.flags.Flags import com.android.systemui.flags.Flags
import com.android.systemui.globalactions.GlobalActionsDialogLite import com.android.systemui.globalactions.GlobalActionsDialogLite
@@ -70,13 +70,13 @@ class FooterActionsInteractorTest : SysuiTestCase() {
val underTest = utils.footerActionsInteractor(qsSecurityFooterUtils = qsSecurityFooterUtils) val underTest = utils.footerActionsInteractor(qsSecurityFooterUtils = qsSecurityFooterUtils)
val quickSettingsContext = mock<Context>() val quickSettingsContext = mock<Context>()
underTest.showDeviceMonitoringDialog(quickSettingsContext)
underTest.showDeviceMonitoringDialog(quickSettingsContext, null)
verify(qsSecurityFooterUtils).showDeviceMonitoringDialog(quickSettingsContext, null) verify(qsSecurityFooterUtils).showDeviceMonitoringDialog(quickSettingsContext, null)
val view = mock<View>() val expandable = mock<Expandable>()
whenever(view.context).thenReturn(quickSettingsContext) underTest.showDeviceMonitoringDialog(quickSettingsContext, expandable)
underTest.showDeviceMonitoringDialog(view) verify(qsSecurityFooterUtils).showDeviceMonitoringDialog(quickSettingsContext, expandable)
verify(qsSecurityFooterUtils).showDeviceMonitoringDialog(quickSettingsContext, null)
} }
@Test @Test
@@ -85,8 +85,8 @@ class FooterActionsInteractorTest : SysuiTestCase() {
val underTest = utils.footerActionsInteractor(uiEventLogger = uiEventLogger) val underTest = utils.footerActionsInteractor(uiEventLogger = uiEventLogger)
val globalActionsDialogLite = mock<GlobalActionsDialogLite>() val globalActionsDialogLite = mock<GlobalActionsDialogLite>()
val view = mock<View>() val expandable = mock<Expandable>()
underTest.showPowerMenuDialog(globalActionsDialogLite, view) underTest.showPowerMenuDialog(globalActionsDialogLite, expandable)
// Event is logged. // Event is logged.
val logs = uiEventLogger.logs val logs = uiEventLogger.logs
@@ -99,7 +99,7 @@ class FooterActionsInteractorTest : SysuiTestCase() {
.showOrHideDialog( .showOrHideDialog(
/* keyguardShowing= */ false, /* keyguardShowing= */ false,
/* isDeviceProvisioned= */ true, /* isDeviceProvisioned= */ true,
view, expandable,
) )
} }
@@ -167,11 +167,11 @@ class FooterActionsInteractorTest : SysuiTestCase() {
userSwitchDialogController = userSwitchDialogController, userSwitchDialogController = userSwitchDialogController,
) )
val view = mock<View>() val expandable = mock<Expandable>()
underTest.showUserSwitcher(view) underTest.showUserSwitcher(context, expandable)
// Dialog is shown. // Dialog is shown.
verify(userSwitchDialogController).showDialog(view) verify(userSwitchDialogController).showDialog(context, expandable)
} }
@Test @Test
@@ -184,12 +184,9 @@ class FooterActionsInteractorTest : SysuiTestCase() {
activityStarter = activityStarter, activityStarter = activityStarter,
) )
// The clicked view. The context is necessary because it's used to build the intent, that // The clicked expandable.
// we check below. val expandable = mock<Expandable>()
val view = mock<View>() underTest.showUserSwitcher(context, expandable)
whenever(view.context).thenReturn(context)
underTest.showUserSwitcher(view)
// Dialog is shown. // Dialog is shown.
val intentCaptor = argumentCaptor<Intent>() val intentCaptor = argumentCaptor<Intent>()

View File

@@ -20,12 +20,12 @@ import android.content.DialogInterface
import android.content.Intent import android.content.Intent
import android.provider.Settings import android.provider.Settings
import android.testing.AndroidTestingRunner import android.testing.AndroidTestingRunner
import android.view.View
import android.widget.Button import android.widget.Button
import androidx.test.filters.SmallTest import androidx.test.filters.SmallTest
import com.android.internal.logging.UiEventLogger import com.android.internal.logging.UiEventLogger
import com.android.systemui.SysuiTestCase import com.android.systemui.SysuiTestCase
import com.android.systemui.animation.DialogLaunchAnimator import com.android.systemui.animation.DialogLaunchAnimator
import com.android.systemui.animation.Expandable
import com.android.systemui.plugins.ActivityStarter import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.plugins.FalsingManager import com.android.systemui.plugins.FalsingManager
import com.android.systemui.qs.PseudoGridView import com.android.systemui.qs.PseudoGridView
@@ -35,6 +35,7 @@ import com.android.systemui.statusbar.phone.SystemUIDialog
import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.capture import com.android.systemui.util.mockito.capture
import com.android.systemui.util.mockito.eq import com.android.systemui.util.mockito.eq
import com.android.systemui.util.mockito.mock
import org.junit.Before import org.junit.Before
import org.junit.Test import org.junit.Test
import org.junit.runner.RunWith import org.junit.runner.RunWith
@@ -63,7 +64,7 @@ class UserSwitchDialogControllerTest : SysuiTestCase() {
@Mock @Mock
private lateinit var userDetailViewAdapter: UserDetailView.Adapter private lateinit var userDetailViewAdapter: UserDetailView.Adapter
@Mock @Mock
private lateinit var launchView: View private lateinit var launchExpandable: Expandable
@Mock @Mock
private lateinit var neutralButton: Button private lateinit var neutralButton: Button
@Mock @Mock
@@ -79,7 +80,6 @@ class UserSwitchDialogControllerTest : SysuiTestCase() {
fun setUp() { fun setUp() {
MockitoAnnotations.initMocks(this) MockitoAnnotations.initMocks(this)
`when`(launchView.context).thenReturn(mContext)
`when`(dialog.context).thenReturn(mContext) `when`(dialog.context).thenReturn(mContext)
controller = UserSwitchDialogController( controller = UserSwitchDialogController(
@@ -94,32 +94,34 @@ class UserSwitchDialogControllerTest : SysuiTestCase() {
@Test @Test
fun showDialog_callsDialogShow() { fun showDialog_callsDialogShow() {
controller.showDialog(launchView) val launchController = mock<DialogLaunchAnimator.Controller>()
verify(dialogLaunchAnimator).showFromView(eq(dialog), eq(launchView), any(), anyBoolean()) `when`(launchExpandable.dialogLaunchController(any())).thenReturn(launchController)
controller.showDialog(context, launchExpandable)
verify(dialogLaunchAnimator).show(eq(dialog), eq(launchController), anyBoolean())
verify(uiEventLogger).log(QSUserSwitcherEvent.QS_USER_DETAIL_OPEN) verify(uiEventLogger).log(QSUserSwitcherEvent.QS_USER_DETAIL_OPEN)
} }
@Test @Test
fun dialog_showForAllUsers() { fun dialog_showForAllUsers() {
controller.showDialog(launchView) controller.showDialog(context, launchExpandable)
verify(dialog).setShowForAllUsers(true) verify(dialog).setShowForAllUsers(true)
} }
@Test @Test
fun dialog_cancelOnTouchOutside() { fun dialog_cancelOnTouchOutside() {
controller.showDialog(launchView) controller.showDialog(context, launchExpandable)
verify(dialog).setCanceledOnTouchOutside(true) verify(dialog).setCanceledOnTouchOutside(true)
} }
@Test @Test
fun adapterAndGridLinked() { fun adapterAndGridLinked() {
controller.showDialog(launchView) controller.showDialog(context, launchExpandable)
verify(userDetailViewAdapter).linkToViewGroup(any<PseudoGridView>()) verify(userDetailViewAdapter).linkToViewGroup(any<PseudoGridView>())
} }
@Test @Test
fun doneButtonLogsCorrectly() { fun doneButtonLogsCorrectly() {
controller.showDialog(launchView) controller.showDialog(context, launchExpandable)
verify(dialog).setPositiveButton(anyInt(), capture(clickCaptor)) verify(dialog).setPositiveButton(anyInt(), capture(clickCaptor))
@@ -132,7 +134,7 @@ class UserSwitchDialogControllerTest : SysuiTestCase() {
fun clickSettingsButton_noFalsing_opensSettings() { fun clickSettingsButton_noFalsing_opensSettings() {
`when`(falsingManager.isFalseTap(anyInt())).thenReturn(false) `when`(falsingManager.isFalseTap(anyInt())).thenReturn(false)
controller.showDialog(launchView) controller.showDialog(context, launchExpandable)
verify(dialog) verify(dialog)
.setNeutralButton(anyInt(), capture(clickCaptor), eq(false) /* dismissOnClick */) .setNeutralButton(anyInt(), capture(clickCaptor), eq(false) /* dismissOnClick */)
@@ -153,7 +155,7 @@ class UserSwitchDialogControllerTest : SysuiTestCase() {
fun clickSettingsButton_Falsing_notOpensSettings() { fun clickSettingsButton_Falsing_notOpensSettings() {
`when`(falsingManager.isFalseTap(anyInt())).thenReturn(true) `when`(falsingManager.isFalseTap(anyInt())).thenReturn(true)
controller.showDialog(launchView) controller.showDialog(context, launchExpandable)
verify(dialog) verify(dialog)
.setNeutralButton(anyInt(), capture(clickCaptor), eq(false) /* dismissOnClick */) .setNeutralButton(anyInt(), capture(clickCaptor), eq(false) /* dismissOnClick */)

View File

@@ -20,7 +20,6 @@ import android.content.Intent
import android.os.UserHandle import android.os.UserHandle
import android.testing.AndroidTestingRunner import android.testing.AndroidTestingRunner
import android.testing.TestableLooper import android.testing.TestableLooper
import android.view.View
import androidx.test.filters.SmallTest import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase import com.android.systemui.SysuiTestCase
import com.android.systemui.flags.FeatureFlags import com.android.systemui.flags.FeatureFlags
@@ -34,8 +33,8 @@ import org.junit.Before
import org.junit.Test import org.junit.Test
import org.junit.runner.RunWith import org.junit.runner.RunWith
import org.mockito.Mock import org.mockito.Mock
import org.mockito.Mockito.verify
import org.mockito.Mockito.`when` import org.mockito.Mockito.`when`
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations import org.mockito.MockitoAnnotations
@RunWith(AndroidTestingRunner::class) @RunWith(AndroidTestingRunner::class)
@@ -91,7 +90,7 @@ class StatusBarUserSwitcherControllerOldImplTest : SysuiTestCase() {
fun testStartActivity() { fun testStartActivity() {
`when`(featureFlags.isEnabled(Flags.FULL_SCREEN_USER_SWITCHER)).thenReturn(false) `when`(featureFlags.isEnabled(Flags.FULL_SCREEN_USER_SWITCHER)).thenReturn(false)
statusBarUserSwitcherContainer.callOnClick() statusBarUserSwitcherContainer.callOnClick()
verify(userSwitcherDialogController).showDialog(any(View::class.java)) verify(userSwitcherDialogController).showDialog(any(), any())
`when`(featureFlags.isEnabled(Flags.FULL_SCREEN_USER_SWITCHER)).thenReturn(true) `when`(featureFlags.isEnabled(Flags.FULL_SCREEN_USER_SWITCHER)).thenReturn(true)
statusBarUserSwitcherContainer.callOnClick() statusBarUserSwitcherContainer.callOnClick()
verify(activityStarter).startActivity(any(Intent::class.java), verify(activityStarter).startActivity(any(Intent::class.java),

View File

@@ -16,7 +16,7 @@
package com.android.systemui.qs package com.android.systemui.qs
import android.view.View import com.android.systemui.animation.Expandable
import com.android.systemui.qs.FgsManagerController.OnDialogDismissedListener import com.android.systemui.qs.FgsManagerController.OnDialogDismissedListener
import com.android.systemui.qs.FgsManagerController.OnNumberOfPackagesChangedListener import com.android.systemui.qs.FgsManagerController.OnNumberOfPackagesChangedListener
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
@@ -54,7 +54,7 @@ class FakeFgsManagerController(
override fun init() {} override fun init() {}
override fun showDialog(viewLaunchedFrom: View?) {} override fun showDialog(expandable: Expandable?) {}
override fun addOnNumberOfPackagesChangedListener(listener: OnNumberOfPackagesChangedListener) { override fun addOnNumberOfPackagesChangedListener(listener: OnNumberOfPackagesChangedListener) {
numRunningPackagesListeners.add(listener) numRunningPackagesListeners.add(listener)

View File

@@ -57,7 +57,6 @@ import com.android.systemui.statusbar.policy.UserSwitcherController
import com.android.systemui.util.mockito.mock import com.android.systemui.util.mockito.mock
import com.android.systemui.util.settings.FakeSettings import com.android.systemui.util.settings.FakeSettings
import com.android.systemui.util.settings.GlobalSettings import com.android.systemui.util.settings.GlobalSettings
import com.android.systemui.util.time.FakeSystemClock
import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.test.TestCoroutineDispatcher import kotlinx.coroutines.test.TestCoroutineDispatcher
@@ -68,7 +67,6 @@ import kotlinx.coroutines.test.TestCoroutineDispatcher
class FooterActionsTestUtils( class FooterActionsTestUtils(
private val context: Context, private val context: Context,
private val testableLooper: TestableLooper, private val testableLooper: TestableLooper,
private val fakeClock: FakeSystemClock = FakeSystemClock(),
) { ) {
/** Enable or disable the user switcher in the settings. */ /** Enable or disable the user switcher in the settings. */
fun setUserSwitcherEnabled(settings: GlobalSettings, enabled: Boolean, userId: Int) { fun setUserSwitcherEnabled(settings: GlobalSettings, enabled: Boolean, userId: Int) {