Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c5caa005 authored by Matt Pietal's avatar Matt Pietal
Browse files

Use transitions for shade window occluded state

There is a timing issue that shows up with activity
launch animations. If keyguard occluded state is
changed in the middle of a launch animation, a flicker
can occur, sometimes pretty bad like currently
lauching the emergency call UI over SIM bouncer. Use
transition FINISHED state as a more reliable method
to send state over to the shade window.

Fixes: 344716537
Test: atest NotificationShadeWindowModelTest
Test: manual repeatedly launch emergency call UI
over SIM bouncer
Flag: com.android.systemui.use_transitions_for_keyguard_occluded

Change-Id: I14e1c3478fb76c3a9459c3a8fd0d8e4587962089
parent 24ceab6c
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -1262,6 +1262,16 @@ flag {
   }
}

flag {
   name: "use_transitions_for_keyguard_occluded"
   namespace: "systemui"
   description: "Use Keyguard Transitions to set Notification Shade occlusion state"
   bug: "344716537"
   metadata {
        purpose: PURPOSE_BUGFIX
   }
}

flag {
   name: "lockscreen_preview_renderer_create_on_main_thread"
   namespace: "systemui"
+3 −0
Original line number Diff line number Diff line
@@ -60,6 +60,7 @@ import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.res.R;
import com.android.systemui.scene.FakeWindowRootViewComponent;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.shade.ui.viewmodel.NotificationShadeWindowModel;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.phone.DozeParameters;
@@ -106,6 +107,7 @@ public class NotificationShadeWindowControllerImplTest extends SysuiTestCase {
    @Mock private ShadeWindowLogger mShadeWindowLogger;
    @Mock private SelectedUserInteractor mSelectedUserInteractor;
    @Mock private UserTracker mUserTracker;
    @Mock private NotificationShadeWindowModel mNotificationShadeWindowModel;
    @Captor private ArgumentCaptor<WindowManager.LayoutParams> mLayoutParameters;
    @Captor private ArgumentCaptor<StatusBarStateController.StateListener> mStateListener;

@@ -161,6 +163,7 @@ public class NotificationShadeWindowControllerImplTest extends SysuiTestCase {
                mShadeWindowLogger,
                () -> mSelectedUserInteractor,
                mUserTracker,
                mNotificationShadeWindowModel,
                mKosmos::getCommunalInteractor) {
                    @Override
                    protected boolean isDebuggable() {
+65 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 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.shade.ui.viewmodel

import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.kosmos.testScope
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.runTest
import org.junit.Test
import org.junit.runner.RunWith

@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
@RunWith(AndroidJUnit4::class)
class NotificationShadeWindowModelTest : SysuiTestCase() {

    private val kosmos = testKosmos()
    private val testScope = kosmos.testScope
    private val keyguardTransitionRepository by lazy { kosmos.fakeKeyguardTransitionRepository }
    private val underTest: NotificationShadeWindowModel by lazy {
        kosmos.notificationShadeWindowModel
    }

    @Test
    fun transitionToOccluded() =
        testScope.runTest {
            val isKeyguardOccluded by collectLastValue(underTest.isKeyguardOccluded)
            assertThat(isKeyguardOccluded).isFalse()

            keyguardTransitionRepository.sendTransitionSteps(
                from = KeyguardState.LOCKSCREEN,
                to = KeyguardState.OCCLUDED,
                testScope,
            )
            assertThat(isKeyguardOccluded).isTrue()

            keyguardTransitionRepository.sendTransitionSteps(
                from = KeyguardState.OCCLUDED,
                to = KeyguardState.GONE,
                testScope,
            )
            assertThat(isKeyguardOccluded).isFalse()
        }
}
+5 −2
Original line number Diff line number Diff line
@@ -220,7 +220,10 @@ constructor(
            interpolator = Interpolators.LINEAR
            duration =
                when (toState) {
                    KeyguardState.GONE -> TO_GONE_DURATION
                    KeyguardState.LOCKSCREEN -> TO_LOCKSCREEN_DURATION
                    KeyguardState.OCCLUDED -> TO_OCCLUDED_DURATION
                    KeyguardState.PRIMARY_BOUNCER -> TO_PRIMARY_BOUNCER_DURATION
                    else -> DEFAULT_DURATION
                }.inWholeMilliseconds
        }
@@ -229,9 +232,9 @@ constructor(
    companion object {
        private const val TAG = "FromAodTransitionInteractor"
        private val DEFAULT_DURATION = 500.milliseconds
        val TO_LOCKSCREEN_DURATION = 500.milliseconds
        val TO_GONE_DURATION = DEFAULT_DURATION
        val TO_OCCLUDED_DURATION = DEFAULT_DURATION
        val TO_LOCKSCREEN_DURATION = 500.milliseconds
        val TO_OCCLUDED_DURATION = 550.milliseconds
        val TO_PRIMARY_BOUNCER_DURATION = DEFAULT_DURATION
    }
}
+12 −3
Original line number Diff line number Diff line
@@ -302,16 +302,25 @@ constructor(
    override fun getDefaultAnimatorForTransitionsToState(toState: KeyguardState): ValueAnimator {
        return ValueAnimator().apply {
            interpolator = Interpolators.LINEAR
            duration = DEFAULT_DURATION.inWholeMilliseconds
            duration =
                when (toState) {
                    KeyguardState.GONE -> TO_GONE_DURATION
                    KeyguardState.GLANCEABLE_HUB -> TO_GLANCEABLE_HUB_DURATION
                    KeyguardState.LOCKSCREEN -> TO_LOCKSCREEN_DURATION
                    KeyguardState.OCCLUDED -> TO_OCCLUDED_DURATION
                    KeyguardState.PRIMARY_BOUNCER -> TO_PRIMARY_BOUNCER_DURATION
                    else -> DEFAULT_DURATION
                }.inWholeMilliseconds
        }
    }

    companion object {
        const val TAG = "FromDozingTransitionInteractor"
        private val DEFAULT_DURATION = 500.milliseconds
        val TO_LOCKSCREEN_DURATION = DEFAULT_DURATION
        val TO_GLANCEABLE_HUB_DURATION = DEFAULT_DURATION
        val TO_GONE_DURATION = DEFAULT_DURATION
        val TO_LOCKSCREEN_DURATION = DEFAULT_DURATION
        val TO_OCCLUDED_DURATION = 550.milliseconds
        val TO_PRIMARY_BOUNCER_DURATION = DEFAULT_DURATION
        val TO_GLANCEABLE_HUB_DURATION = DEFAULT_DURATION
    }
}
Loading