Loading packages/SystemUI/src/com/android/systemui/qs/FooterActionsController.kt +49 −8 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package com.android.systemui.qs import android.content.Intent import android.content.res.Configuration import android.os.Handler import android.os.UserManager import android.provider.Settings Loading @@ -38,9 +39,11 @@ import com.android.systemui.qs.dagger.QSFlagsModule.PM_LITE_ENABLED import com.android.systemui.qs.dagger.QSScope import com.android.systemui.settings.UserTracker import com.android.systemui.statusbar.phone.MultiUserSwitchController import com.android.systemui.statusbar.policy.ConfigurationController import com.android.systemui.statusbar.policy.DeviceProvisionedController import com.android.systemui.statusbar.policy.UserInfoController import com.android.systemui.statusbar.policy.UserInfoController.OnUserInfoChangedListener import com.android.systemui.util.LargeScreenUtils import com.android.systemui.util.ViewController import com.android.systemui.util.settings.GlobalSettings import javax.inject.Inject Loading Loading @@ -69,18 +72,43 @@ internal class FooterActionsController @Inject constructor( private val uiEventLogger: UiEventLogger, @Named(PM_LITE_ENABLED) private val showPMLiteButton: Boolean, private val globalSetting: GlobalSettings, private val handler: Handler private val handler: Handler, private val configurationController: ConfigurationController, ) : ViewController<FooterActionsView>(view) { private var globalActionsDialog: GlobalActionsDialogLite? = null private var lastExpansion = -1f private var listening: Boolean = false private var inSplitShade = false private val alphaAnimator = TouchAnimator.Builder() .addFloat(mView, "alpha", 0f, 1f) private val singleShadeAnimator by lazy { // In single shade, the actions footer should only appear at the end of the expansion, // so that it doesn't overlap with the notifications panel. TouchAnimator.Builder().addFloat(mView, "alpha", 0f, 1f).setStartDelay(0.9f).build() } private val splitShadeAnimator by lazy { // The Actions footer view has its own background which is the same color as the qs panel's // background. // We don't want it to fade in at the same time as the rest of the panel, otherwise it is // more opaque than the rest of the panel's background. Only applies to split shade. val alphaAnimator = TouchAnimator.Builder().addFloat(mView, "alpha", 0f, 1f).build() val bgAlphaAnimator = TouchAnimator.Builder() .addFloat(mView, "backgroundAlpha", 0f, 1f) .setStartDelay(0.9f) .build() // In split shade, we want the actions footer to fade in exactly at the same time as the // rest of the shade, as there is no overlap. TouchAnimator.Builder() .addFloat(alphaAnimator, "position", 0f, 1f) .addFloat(bgAlphaAnimator, "position", 0f, 1f) .build() } private val animators: TouchAnimator get() = if (inSplitShade) splitShadeAnimator else singleShadeAnimator var visible = true set(value) { Loading @@ -95,9 +123,7 @@ internal class FooterActionsController @Inject constructor( private val multiUserSwitchController = multiUserSwitchControllerFactory.create(view) @VisibleForTesting internal val securityFootersSeparator = View(context).apply { visibility = View.GONE } internal val securityFootersSeparator = View(context).apply { visibility = View.GONE } private val onUserInfoChangedListener = OnUserInfoChangedListener { _, picture, _ -> val isGuestUser: Boolean = userManager.isGuestUser(KeyguardUpdateMonitor.getCurrentUser()) Loading Loading @@ -133,6 +159,17 @@ internal class FooterActionsController @Inject constructor( } } private val configurationListener = object : ConfigurationController.ConfigurationListener { override fun onConfigChanged(newConfig: Configuration?) { updateResources() } } private fun updateResources() { inSplitShade = LargeScreenUtils.shouldUseSplitNotificationShade(resources) } override fun onInit() { multiUserSwitchController.init() securityFooterController.init() Loading Loading @@ -189,6 +226,9 @@ internal class FooterActionsController @Inject constructor( securityFooterController.setOnVisibilityChangedListener(visibilityListener) fgsManagerFooterController.setOnVisibilityChangedListener(visibilityListener) configurationController.addCallback(configurationListener) updateResources() updateView() } Loading @@ -201,6 +241,7 @@ internal class FooterActionsController @Inject constructor( globalActionsDialog = null setListening(false) multiUserSetting.isListening = false configurationController.removeCallback(configurationListener) } fun setListening(listening: Boolean) { Loading @@ -224,7 +265,7 @@ internal class FooterActionsController @Inject constructor( } fun setExpansion(headerExpansionFraction: Float) { alphaAnimator.setPosition(headerExpansionFraction) animators.setPosition(headerExpansionFraction) } fun setKeyguardShowing(showing: Boolean) { Loading packages/SystemUI/src/com/android/systemui/qs/FooterActionsView.kt +15 −1 Original line number Diff line number Diff line Loading @@ -27,6 +27,7 @@ import android.view.MotionEvent import android.view.View import android.widget.ImageView import android.widget.LinearLayout import androidx.annotation.Keep import com.android.settingslib.Utils import com.android.settingslib.drawable.UserIconDrawable import com.android.systemui.R Loading @@ -45,6 +46,19 @@ class FooterActionsView(context: Context?, attrs: AttributeSet?) : LinearLayout( private var qsDisabled = false private var expansionAmount = 0f /** * Sets the alpha of the background of this view. * * Used from a [TouchAnimator] in the controller. */ var backgroundAlpha: Float = 1f @Keep set(value) { field = value background?.alpha = (value * 255).toInt() } @Keep get override fun onFinishInflate() { super.onFinishInflate() settingsContainer = findViewById(R.id.settings_button_container) Loading packages/SystemUI/src/com/android/systemui/qs/QSFragment.java +5 −3 Original line number Diff line number Diff line Loading @@ -557,9 +557,9 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca public void setQsExpansion(float expansion, float panelExpansionFraction, float proposedTranslation, float squishinessFraction) { float headerTranslation = mTransitioningToFullShade ? 0 : proposedTranslation; float progress = mTransitioningToFullShade || mState == StatusBarState.KEYGUARD float alphaProgress = mTransitioningToFullShade || mState == StatusBarState.KEYGUARD ? mFullShadeProgress : panelExpansionFraction; setAlphaAnimationProgress(mInSplitShade ? progress : 1); setAlphaAnimationProgress(mInSplitShade ? alphaProgress : 1); mContainer.setExpansion(expansion); final float translationScaleY = (mInSplitShade ? 1 : QSAnimator.SHORT_PARALLAX_AMOUNT) * (expansion - 1); Loading Loading @@ -600,7 +600,9 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca } mQSPanelController.setIsOnKeyguard(onKeyguard); mFooter.setExpansion(onKeyguardAndExpanded ? 1 : expansion); mQSFooterActionController.setExpansion(onKeyguardAndExpanded ? 1 : expansion); float footerActionsExpansion = onKeyguardAndExpanded ? 1 : mInSplitShade ? alphaProgress : expansion; mQSFooterActionController.setExpansion(footerActionsExpansion); mQSPanelController.setRevealExpansion(expansion); mQSPanelController.getTileLayout().setExpansion(expansion, proposedTranslation); mQuickQSPanelController.getTileLayout().setExpansion(expansion, proposedTranslation); Loading packages/SystemUI/tests/src/com/android/systemui/qs/FooterActionsControllerTest.kt +152 −37 Original line number Diff line number Diff line Loading @@ -22,13 +22,17 @@ import com.android.systemui.plugins.ActivityStarter import com.android.systemui.settings.UserTracker import com.android.systemui.statusbar.phone.MultiUserSwitchController import com.android.systemui.statusbar.policy.DeviceProvisionedController import com.android.systemui.statusbar.policy.FakeConfigurationController import com.android.systemui.statusbar.policy.UserInfoController import com.android.systemui.util.mockito.capture import com.android.systemui.util.settings.FakeSettings import com.android.systemui.utils.leaks.LeakCheckedTest import com.google.common.truth.Expect import com.google.common.truth.Truth.assertThat import javax.inject.Provider import org.junit.After import org.junit.Before import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import org.mockito.ArgumentCaptor Loading @@ -42,47 +46,38 @@ import org.mockito.Mockito.clearInvocations import org.mockito.Mockito.never import org.mockito.Mockito.reset import org.mockito.Mockito.verify import org.mockito.MockitoAnnotations import javax.inject.Provider import org.mockito.Mockito.`when` as whenever import org.mockito.MockitoAnnotations @SmallTest @TestableLooper.RunWithLooper(setAsMainLooper = true) @RunWith(AndroidTestingRunner::class) class FooterActionsControllerTest : LeakCheckedTest() { @Mock private lateinit var userManager: UserManager @Mock private lateinit var userTracker: UserTracker @Mock private lateinit var activityStarter: ActivityStarter @Mock private lateinit var deviceProvisionedController: DeviceProvisionedController @Mock private lateinit var userInfoController: UserInfoController @Mock private lateinit var multiUserSwitchControllerFactory: MultiUserSwitchController.Factory @Mock private lateinit var multiUserSwitchController: MultiUserSwitchController @Mock private lateinit var globalActionsDialogProvider: Provider<GlobalActionsDialogLite> @Mock private lateinit var globalActionsDialog: GlobalActionsDialogLite @Mock private lateinit var uiEventLogger: UiEventLogger @Mock private lateinit var securityFooterController: QSSecurityFooter @Mock private lateinit var fgsManagerController: QSFgsManagerFooter @get:Rule var expect: Expect = Expect.create() @Mock private lateinit var userManager: UserManager @Mock private lateinit var userTracker: UserTracker @Mock private lateinit var activityStarter: ActivityStarter @Mock private lateinit var deviceProvisionedController: DeviceProvisionedController @Mock private lateinit var userInfoController: UserInfoController @Mock private lateinit var multiUserSwitchControllerFactory: MultiUserSwitchController.Factory @Mock private lateinit var multiUserSwitchController: MultiUserSwitchController @Mock private lateinit var globalActionsDialogProvider: Provider<GlobalActionsDialogLite> @Mock private lateinit var globalActionsDialog: GlobalActionsDialogLite @Mock private lateinit var uiEventLogger: UiEventLogger @Mock private lateinit var securityFooterController: QSSecurityFooter @Mock private lateinit var fgsManagerController: QSFgsManagerFooter @Captor private lateinit var visibilityChangedCaptor: ArgumentCaptor<VisibilityChangedDispatcher.OnVisibilityChangedListener> private lateinit var controller: FooterActionsController private val configurationController = FakeConfigurationController() private val metricsLogger: MetricsLogger = FakeMetricsLogger() private lateinit var view: FooterActionsView private val falsingManager: FalsingManagerFake = FalsingManagerFake() private lateinit var view: FooterActionsView private lateinit var testableLooper: TestableLooper private lateinit var fakeSettings: FakeSettings private lateinit var securityFooter: View Loading @@ -90,6 +85,9 @@ class FooterActionsControllerTest : LeakCheckedTest() { @Before fun setUp() { // We want to make sure testable resources are always used context.ensureTestableResources() MockitoAnnotations.initMocks(this) testableLooper = TestableLooper.get(this) fakeSettings = FakeSettings() Loading Loading @@ -299,6 +297,86 @@ class FooterActionsControllerTest : LeakCheckedTest() { assertThat(booleanCaptor.allValues.last()).isTrue() } @Test fun setExpansion_inSplitShade_alphaFollowsExpansion() { enableSplitShade() controller.setExpansion(0f) expect.that(view.alpha).isEqualTo(0f) controller.setExpansion(0.25f) expect.that(view.alpha).isEqualTo(0.25f) controller.setExpansion(0.5f) expect.that(view.alpha).isEqualTo(0.5f) controller.setExpansion(0.75f) expect.that(view.alpha).isEqualTo(0.75f) controller.setExpansion(1f) expect.that(view.alpha).isEqualTo(1f) } @Test fun setExpansion_inSplitShade_backgroundAlphaFollowsExpansion_with_0_9_delay() { enableSplitShade() controller.setExpansion(0f) expect.that(view.backgroundAlphaFraction).isEqualTo(0f) controller.setExpansion(0.5f) expect.that(view.backgroundAlphaFraction).isEqualTo(0f) controller.setExpansion(0.9f) expect.that(view.backgroundAlphaFraction).isEqualTo(0f) controller.setExpansion(0.91f) expect.that(view.backgroundAlphaFraction).isWithin(FLOAT_TOLERANCE).of(0.1f) controller.setExpansion(0.95f) expect.that(view.backgroundAlphaFraction).isWithin(FLOAT_TOLERANCE).of(0.5f) controller.setExpansion(1f) expect.that(view.backgroundAlphaFraction).isEqualTo(1f) } @Test fun setExpansion_inSingleShade_alphaFollowsExpansion_with_0_9_delay() { disableSplitShade() controller.setExpansion(0f) expect.that(view.alpha).isEqualTo(0f) controller.setExpansion(0.5f) expect.that(view.alpha).isEqualTo(0f) controller.setExpansion(0.9f) expect.that(view.alpha).isEqualTo(0f) controller.setExpansion(0.91f) expect.that(view.alpha).isWithin(FLOAT_TOLERANCE).of(0.1f) controller.setExpansion(0.95f) expect.that(view.alpha).isWithin(FLOAT_TOLERANCE).of(0.5f) controller.setExpansion(1f) expect.that(view.alpha).isEqualTo(1f) } @Test fun setExpansion_inSingleShade_backgroundAlphaAlways1() { disableSplitShade() controller.setExpansion(0f) expect.that(view.backgroundAlphaFraction).isEqualTo(1f) controller.setExpansion(0.5f) expect.that(view.backgroundAlphaFraction).isEqualTo(1f) controller.setExpansion(1f) expect.that(view.backgroundAlphaFraction).isEqualTo(1f) } private fun setVisibilities( securityFooterVisible: Boolean, fgsFooterVisible: Boolean, Loading @@ -311,15 +389,52 @@ class FooterActionsControllerTest : LeakCheckedTest() { } private fun inflateView(): FooterActionsView { return LayoutInflater.from(context) .inflate(R.layout.footer_actions, null) as FooterActionsView return LayoutInflater.from(context).inflate(R.layout.footer_actions, null) as FooterActionsView } private fun constructFooterActionsController(view: FooterActionsView): FooterActionsController { return FooterActionsController(view, multiUserSwitchControllerFactory, activityStarter, userManager, userTracker, userInfoController, deviceProvisionedController, securityFooterController, fgsManagerController, falsingManager, metricsLogger, globalActionsDialogProvider, uiEventLogger, showPMLiteButton = true, fakeSettings, Handler(testableLooper.looper)) return FooterActionsController( view, multiUserSwitchControllerFactory, activityStarter, userManager, userTracker, userInfoController, deviceProvisionedController, securityFooterController, fgsManagerController, falsingManager, metricsLogger, globalActionsDialogProvider, uiEventLogger, showPMLiteButton = true, fakeSettings, Handler(testableLooper.looper), configurationController) } private fun enableSplitShade() { setSplitShadeEnabled(true) } private fun disableSplitShade() { setSplitShadeEnabled(false) } private fun setSplitShadeEnabled(enabled: Boolean) { overrideResource(R.bool.config_use_split_notification_shade, enabled) configurationController.notifyConfigurationChanged() } } private const val FLOAT_TOLERANCE = 0.01f private val View.backgroundAlphaFraction: Float? get() { return if (background != null) { background.alpha / 255f } else { null } } packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java +34 −0 Original line number Diff line number Diff line Loading @@ -204,6 +204,40 @@ public class QSFragmentTest extends SysuiBaseFragmentTest { assertThat(mQsFragmentView.getAlpha()).isEqualTo(1); } @Test public void setQsExpansion_inSplitShade_setsFooterActionsExpansion_basedOnPanelExpFraction() { // Random test values without any meaning. They just have to be different from each other. float expansion = 0.123f; float panelExpansionFraction = 0.321f; float proposedTranslation = 456f; float squishinessFraction = 0.987f; QSFragment fragment = resumeAndGetFragment(); enableSplitShade(); fragment.setQsExpansion(expansion, panelExpansionFraction, proposedTranslation, squishinessFraction); verify(mQSFooterActionController).setExpansion(panelExpansionFraction); } @Test public void setQsExpansion_notInSplitShade_setsFooterActionsExpansion_basedOnExpansion() { // Random test values without any meaning. They just have to be different from each other. float expansion = 0.123f; float panelExpansionFraction = 0.321f; float proposedTranslation = 456f; float squishinessFraction = 0.987f; QSFragment fragment = resumeAndGetFragment(); disableSplitShade(); fragment.setQsExpansion(expansion, panelExpansionFraction, proposedTranslation, squishinessFraction); verify(mQSFooterActionController).setExpansion(expansion); } @Test public void getQsMinExpansionHeight_notInSplitShade_returnsHeaderHeight() { QSFragment fragment = resumeAndGetFragment(); Loading Loading
packages/SystemUI/src/com/android/systemui/qs/FooterActionsController.kt +49 −8 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package com.android.systemui.qs import android.content.Intent import android.content.res.Configuration import android.os.Handler import android.os.UserManager import android.provider.Settings Loading @@ -38,9 +39,11 @@ import com.android.systemui.qs.dagger.QSFlagsModule.PM_LITE_ENABLED import com.android.systemui.qs.dagger.QSScope import com.android.systemui.settings.UserTracker import com.android.systemui.statusbar.phone.MultiUserSwitchController import com.android.systemui.statusbar.policy.ConfigurationController import com.android.systemui.statusbar.policy.DeviceProvisionedController import com.android.systemui.statusbar.policy.UserInfoController import com.android.systemui.statusbar.policy.UserInfoController.OnUserInfoChangedListener import com.android.systemui.util.LargeScreenUtils import com.android.systemui.util.ViewController import com.android.systemui.util.settings.GlobalSettings import javax.inject.Inject Loading Loading @@ -69,18 +72,43 @@ internal class FooterActionsController @Inject constructor( private val uiEventLogger: UiEventLogger, @Named(PM_LITE_ENABLED) private val showPMLiteButton: Boolean, private val globalSetting: GlobalSettings, private val handler: Handler private val handler: Handler, private val configurationController: ConfigurationController, ) : ViewController<FooterActionsView>(view) { private var globalActionsDialog: GlobalActionsDialogLite? = null private var lastExpansion = -1f private var listening: Boolean = false private var inSplitShade = false private val alphaAnimator = TouchAnimator.Builder() .addFloat(mView, "alpha", 0f, 1f) private val singleShadeAnimator by lazy { // In single shade, the actions footer should only appear at the end of the expansion, // so that it doesn't overlap with the notifications panel. TouchAnimator.Builder().addFloat(mView, "alpha", 0f, 1f).setStartDelay(0.9f).build() } private val splitShadeAnimator by lazy { // The Actions footer view has its own background which is the same color as the qs panel's // background. // We don't want it to fade in at the same time as the rest of the panel, otherwise it is // more opaque than the rest of the panel's background. Only applies to split shade. val alphaAnimator = TouchAnimator.Builder().addFloat(mView, "alpha", 0f, 1f).build() val bgAlphaAnimator = TouchAnimator.Builder() .addFloat(mView, "backgroundAlpha", 0f, 1f) .setStartDelay(0.9f) .build() // In split shade, we want the actions footer to fade in exactly at the same time as the // rest of the shade, as there is no overlap. TouchAnimator.Builder() .addFloat(alphaAnimator, "position", 0f, 1f) .addFloat(bgAlphaAnimator, "position", 0f, 1f) .build() } private val animators: TouchAnimator get() = if (inSplitShade) splitShadeAnimator else singleShadeAnimator var visible = true set(value) { Loading @@ -95,9 +123,7 @@ internal class FooterActionsController @Inject constructor( private val multiUserSwitchController = multiUserSwitchControllerFactory.create(view) @VisibleForTesting internal val securityFootersSeparator = View(context).apply { visibility = View.GONE } internal val securityFootersSeparator = View(context).apply { visibility = View.GONE } private val onUserInfoChangedListener = OnUserInfoChangedListener { _, picture, _ -> val isGuestUser: Boolean = userManager.isGuestUser(KeyguardUpdateMonitor.getCurrentUser()) Loading Loading @@ -133,6 +159,17 @@ internal class FooterActionsController @Inject constructor( } } private val configurationListener = object : ConfigurationController.ConfigurationListener { override fun onConfigChanged(newConfig: Configuration?) { updateResources() } } private fun updateResources() { inSplitShade = LargeScreenUtils.shouldUseSplitNotificationShade(resources) } override fun onInit() { multiUserSwitchController.init() securityFooterController.init() Loading Loading @@ -189,6 +226,9 @@ internal class FooterActionsController @Inject constructor( securityFooterController.setOnVisibilityChangedListener(visibilityListener) fgsManagerFooterController.setOnVisibilityChangedListener(visibilityListener) configurationController.addCallback(configurationListener) updateResources() updateView() } Loading @@ -201,6 +241,7 @@ internal class FooterActionsController @Inject constructor( globalActionsDialog = null setListening(false) multiUserSetting.isListening = false configurationController.removeCallback(configurationListener) } fun setListening(listening: Boolean) { Loading @@ -224,7 +265,7 @@ internal class FooterActionsController @Inject constructor( } fun setExpansion(headerExpansionFraction: Float) { alphaAnimator.setPosition(headerExpansionFraction) animators.setPosition(headerExpansionFraction) } fun setKeyguardShowing(showing: Boolean) { Loading
packages/SystemUI/src/com/android/systemui/qs/FooterActionsView.kt +15 −1 Original line number Diff line number Diff line Loading @@ -27,6 +27,7 @@ import android.view.MotionEvent import android.view.View import android.widget.ImageView import android.widget.LinearLayout import androidx.annotation.Keep import com.android.settingslib.Utils import com.android.settingslib.drawable.UserIconDrawable import com.android.systemui.R Loading @@ -45,6 +46,19 @@ class FooterActionsView(context: Context?, attrs: AttributeSet?) : LinearLayout( private var qsDisabled = false private var expansionAmount = 0f /** * Sets the alpha of the background of this view. * * Used from a [TouchAnimator] in the controller. */ var backgroundAlpha: Float = 1f @Keep set(value) { field = value background?.alpha = (value * 255).toInt() } @Keep get override fun onFinishInflate() { super.onFinishInflate() settingsContainer = findViewById(R.id.settings_button_container) Loading
packages/SystemUI/src/com/android/systemui/qs/QSFragment.java +5 −3 Original line number Diff line number Diff line Loading @@ -557,9 +557,9 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca public void setQsExpansion(float expansion, float panelExpansionFraction, float proposedTranslation, float squishinessFraction) { float headerTranslation = mTransitioningToFullShade ? 0 : proposedTranslation; float progress = mTransitioningToFullShade || mState == StatusBarState.KEYGUARD float alphaProgress = mTransitioningToFullShade || mState == StatusBarState.KEYGUARD ? mFullShadeProgress : panelExpansionFraction; setAlphaAnimationProgress(mInSplitShade ? progress : 1); setAlphaAnimationProgress(mInSplitShade ? alphaProgress : 1); mContainer.setExpansion(expansion); final float translationScaleY = (mInSplitShade ? 1 : QSAnimator.SHORT_PARALLAX_AMOUNT) * (expansion - 1); Loading Loading @@ -600,7 +600,9 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca } mQSPanelController.setIsOnKeyguard(onKeyguard); mFooter.setExpansion(onKeyguardAndExpanded ? 1 : expansion); mQSFooterActionController.setExpansion(onKeyguardAndExpanded ? 1 : expansion); float footerActionsExpansion = onKeyguardAndExpanded ? 1 : mInSplitShade ? alphaProgress : expansion; mQSFooterActionController.setExpansion(footerActionsExpansion); mQSPanelController.setRevealExpansion(expansion); mQSPanelController.getTileLayout().setExpansion(expansion, proposedTranslation); mQuickQSPanelController.getTileLayout().setExpansion(expansion, proposedTranslation); Loading
packages/SystemUI/tests/src/com/android/systemui/qs/FooterActionsControllerTest.kt +152 −37 Original line number Diff line number Diff line Loading @@ -22,13 +22,17 @@ import com.android.systemui.plugins.ActivityStarter import com.android.systemui.settings.UserTracker import com.android.systemui.statusbar.phone.MultiUserSwitchController import com.android.systemui.statusbar.policy.DeviceProvisionedController import com.android.systemui.statusbar.policy.FakeConfigurationController import com.android.systemui.statusbar.policy.UserInfoController import com.android.systemui.util.mockito.capture import com.android.systemui.util.settings.FakeSettings import com.android.systemui.utils.leaks.LeakCheckedTest import com.google.common.truth.Expect import com.google.common.truth.Truth.assertThat import javax.inject.Provider import org.junit.After import org.junit.Before import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import org.mockito.ArgumentCaptor Loading @@ -42,47 +46,38 @@ import org.mockito.Mockito.clearInvocations import org.mockito.Mockito.never import org.mockito.Mockito.reset import org.mockito.Mockito.verify import org.mockito.MockitoAnnotations import javax.inject.Provider import org.mockito.Mockito.`when` as whenever import org.mockito.MockitoAnnotations @SmallTest @TestableLooper.RunWithLooper(setAsMainLooper = true) @RunWith(AndroidTestingRunner::class) class FooterActionsControllerTest : LeakCheckedTest() { @Mock private lateinit var userManager: UserManager @Mock private lateinit var userTracker: UserTracker @Mock private lateinit var activityStarter: ActivityStarter @Mock private lateinit var deviceProvisionedController: DeviceProvisionedController @Mock private lateinit var userInfoController: UserInfoController @Mock private lateinit var multiUserSwitchControllerFactory: MultiUserSwitchController.Factory @Mock private lateinit var multiUserSwitchController: MultiUserSwitchController @Mock private lateinit var globalActionsDialogProvider: Provider<GlobalActionsDialogLite> @Mock private lateinit var globalActionsDialog: GlobalActionsDialogLite @Mock private lateinit var uiEventLogger: UiEventLogger @Mock private lateinit var securityFooterController: QSSecurityFooter @Mock private lateinit var fgsManagerController: QSFgsManagerFooter @get:Rule var expect: Expect = Expect.create() @Mock private lateinit var userManager: UserManager @Mock private lateinit var userTracker: UserTracker @Mock private lateinit var activityStarter: ActivityStarter @Mock private lateinit var deviceProvisionedController: DeviceProvisionedController @Mock private lateinit var userInfoController: UserInfoController @Mock private lateinit var multiUserSwitchControllerFactory: MultiUserSwitchController.Factory @Mock private lateinit var multiUserSwitchController: MultiUserSwitchController @Mock private lateinit var globalActionsDialogProvider: Provider<GlobalActionsDialogLite> @Mock private lateinit var globalActionsDialog: GlobalActionsDialogLite @Mock private lateinit var uiEventLogger: UiEventLogger @Mock private lateinit var securityFooterController: QSSecurityFooter @Mock private lateinit var fgsManagerController: QSFgsManagerFooter @Captor private lateinit var visibilityChangedCaptor: ArgumentCaptor<VisibilityChangedDispatcher.OnVisibilityChangedListener> private lateinit var controller: FooterActionsController private val configurationController = FakeConfigurationController() private val metricsLogger: MetricsLogger = FakeMetricsLogger() private lateinit var view: FooterActionsView private val falsingManager: FalsingManagerFake = FalsingManagerFake() private lateinit var view: FooterActionsView private lateinit var testableLooper: TestableLooper private lateinit var fakeSettings: FakeSettings private lateinit var securityFooter: View Loading @@ -90,6 +85,9 @@ class FooterActionsControllerTest : LeakCheckedTest() { @Before fun setUp() { // We want to make sure testable resources are always used context.ensureTestableResources() MockitoAnnotations.initMocks(this) testableLooper = TestableLooper.get(this) fakeSettings = FakeSettings() Loading Loading @@ -299,6 +297,86 @@ class FooterActionsControllerTest : LeakCheckedTest() { assertThat(booleanCaptor.allValues.last()).isTrue() } @Test fun setExpansion_inSplitShade_alphaFollowsExpansion() { enableSplitShade() controller.setExpansion(0f) expect.that(view.alpha).isEqualTo(0f) controller.setExpansion(0.25f) expect.that(view.alpha).isEqualTo(0.25f) controller.setExpansion(0.5f) expect.that(view.alpha).isEqualTo(0.5f) controller.setExpansion(0.75f) expect.that(view.alpha).isEqualTo(0.75f) controller.setExpansion(1f) expect.that(view.alpha).isEqualTo(1f) } @Test fun setExpansion_inSplitShade_backgroundAlphaFollowsExpansion_with_0_9_delay() { enableSplitShade() controller.setExpansion(0f) expect.that(view.backgroundAlphaFraction).isEqualTo(0f) controller.setExpansion(0.5f) expect.that(view.backgroundAlphaFraction).isEqualTo(0f) controller.setExpansion(0.9f) expect.that(view.backgroundAlphaFraction).isEqualTo(0f) controller.setExpansion(0.91f) expect.that(view.backgroundAlphaFraction).isWithin(FLOAT_TOLERANCE).of(0.1f) controller.setExpansion(0.95f) expect.that(view.backgroundAlphaFraction).isWithin(FLOAT_TOLERANCE).of(0.5f) controller.setExpansion(1f) expect.that(view.backgroundAlphaFraction).isEqualTo(1f) } @Test fun setExpansion_inSingleShade_alphaFollowsExpansion_with_0_9_delay() { disableSplitShade() controller.setExpansion(0f) expect.that(view.alpha).isEqualTo(0f) controller.setExpansion(0.5f) expect.that(view.alpha).isEqualTo(0f) controller.setExpansion(0.9f) expect.that(view.alpha).isEqualTo(0f) controller.setExpansion(0.91f) expect.that(view.alpha).isWithin(FLOAT_TOLERANCE).of(0.1f) controller.setExpansion(0.95f) expect.that(view.alpha).isWithin(FLOAT_TOLERANCE).of(0.5f) controller.setExpansion(1f) expect.that(view.alpha).isEqualTo(1f) } @Test fun setExpansion_inSingleShade_backgroundAlphaAlways1() { disableSplitShade() controller.setExpansion(0f) expect.that(view.backgroundAlphaFraction).isEqualTo(1f) controller.setExpansion(0.5f) expect.that(view.backgroundAlphaFraction).isEqualTo(1f) controller.setExpansion(1f) expect.that(view.backgroundAlphaFraction).isEqualTo(1f) } private fun setVisibilities( securityFooterVisible: Boolean, fgsFooterVisible: Boolean, Loading @@ -311,15 +389,52 @@ class FooterActionsControllerTest : LeakCheckedTest() { } private fun inflateView(): FooterActionsView { return LayoutInflater.from(context) .inflate(R.layout.footer_actions, null) as FooterActionsView return LayoutInflater.from(context).inflate(R.layout.footer_actions, null) as FooterActionsView } private fun constructFooterActionsController(view: FooterActionsView): FooterActionsController { return FooterActionsController(view, multiUserSwitchControllerFactory, activityStarter, userManager, userTracker, userInfoController, deviceProvisionedController, securityFooterController, fgsManagerController, falsingManager, metricsLogger, globalActionsDialogProvider, uiEventLogger, showPMLiteButton = true, fakeSettings, Handler(testableLooper.looper)) return FooterActionsController( view, multiUserSwitchControllerFactory, activityStarter, userManager, userTracker, userInfoController, deviceProvisionedController, securityFooterController, fgsManagerController, falsingManager, metricsLogger, globalActionsDialogProvider, uiEventLogger, showPMLiteButton = true, fakeSettings, Handler(testableLooper.looper), configurationController) } private fun enableSplitShade() { setSplitShadeEnabled(true) } private fun disableSplitShade() { setSplitShadeEnabled(false) } private fun setSplitShadeEnabled(enabled: Boolean) { overrideResource(R.bool.config_use_split_notification_shade, enabled) configurationController.notifyConfigurationChanged() } } private const val FLOAT_TOLERANCE = 0.01f private val View.backgroundAlphaFraction: Float? get() { return if (background != null) { background.alpha / 255f } else { null } }
packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java +34 −0 Original line number Diff line number Diff line Loading @@ -204,6 +204,40 @@ public class QSFragmentTest extends SysuiBaseFragmentTest { assertThat(mQsFragmentView.getAlpha()).isEqualTo(1); } @Test public void setQsExpansion_inSplitShade_setsFooterActionsExpansion_basedOnPanelExpFraction() { // Random test values without any meaning. They just have to be different from each other. float expansion = 0.123f; float panelExpansionFraction = 0.321f; float proposedTranslation = 456f; float squishinessFraction = 0.987f; QSFragment fragment = resumeAndGetFragment(); enableSplitShade(); fragment.setQsExpansion(expansion, panelExpansionFraction, proposedTranslation, squishinessFraction); verify(mQSFooterActionController).setExpansion(panelExpansionFraction); } @Test public void setQsExpansion_notInSplitShade_setsFooterActionsExpansion_basedOnExpansion() { // Random test values without any meaning. They just have to be different from each other. float expansion = 0.123f; float panelExpansionFraction = 0.321f; float proposedTranslation = 456f; float squishinessFraction = 0.987f; QSFragment fragment = resumeAndGetFragment(); disableSplitShade(); fragment.setQsExpansion(expansion, panelExpansionFraction, proposedTranslation, squishinessFraction); verify(mQSFooterActionController).setExpansion(expansion); } @Test public void getQsMinExpansionHeight_notInSplitShade_returnsHeaderHeight() { QSFragment fragment = resumeAndGetFragment(); Loading