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

Commit a5037d84 authored by Chandru S's avatar Chandru S
Browse files

Remove bouncer root view whenever it is not needed.

1. Finishing a transition from * -> Gone removes the bouncer parent view
2. Starting a transition from Gone -> * adds the bouncer parent view

Removing the bouncer parent view cancels all the coroutines launched by the compose bouncer

Fixes: 364401028
Test: verified that compose bouncer works as expected, added logs to verify that bouncer is removed and re-added
Flag: com.android.systemui.compose_bouncer
Change-Id: I167a55284b13940d331c96f4a72defe2cc069aba
parent e18b5751
Loading
Loading
Loading
Loading
+0 −3
Original line number Diff line number Diff line
@@ -5,7 +5,6 @@ import androidx.activity.OnBackPressedDispatcher
import androidx.activity.OnBackPressedDispatcherOwner
import androidx.activity.setViewTreeOnBackPressedDispatcherOwner
import androidx.compose.ui.platform.ComposeView
import androidx.core.view.isGone
import androidx.lifecycle.Lifecycle
import com.android.systemui.bouncer.ui.BouncerDialogFactory
import com.android.systemui.bouncer.ui.composable.BouncerContainer
@@ -13,7 +12,6 @@ import com.android.systemui.bouncer.ui.viewmodel.BouncerContainerViewModel
import com.android.systemui.bouncer.ui.viewmodel.BouncerSceneContentViewModel
import com.android.systemui.lifecycle.WindowLifecycleState
import com.android.systemui.lifecycle.repeatWhenAttached
import com.android.systemui.lifecycle.setSnapshotBinding
import com.android.systemui.lifecycle.viewModel
import kotlinx.coroutines.awaitCancellation

@@ -50,7 +48,6 @@ object ComposeBouncerViewBinder {
                            setContent { BouncerContainer(viewModelFactory, dialogFactory) }
                        }
                    )
                    view.setSnapshotBinding { view.isGone = !viewModel.isVisible }
                    awaitCancellation()
                } finally {
                    view.removeAllViews()
+2 −10
Original line number Diff line number Diff line
@@ -16,17 +16,15 @@

package com.android.systemui.bouncer.ui.viewmodel

import androidx.compose.runtime.getValue
import com.android.systemui.authentication.domain.interactor.AuthenticationInteractor
import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor
import com.android.systemui.deviceentry.domain.interactor.DeviceUnlockedInteractor
import com.android.systemui.lifecycle.ExclusiveActivatable
import com.android.systemui.lifecycle.Hydrator
import com.android.systemui.user.domain.interactor.SelectedUserInteractor
import com.android.systemui.util.kotlin.Utils.Companion.sample
import com.android.systemui.util.kotlin.sample
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import kotlinx.coroutines.awaitCancellation
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.launch

@@ -39,11 +37,6 @@ constructor(
    private val deviceUnlockedInteractor: DeviceUnlockedInteractor,
) : ExclusiveActivatable() {

    private val hydrator = Hydrator("BouncerContainerViewModel")

    val isVisible: Boolean by
        hydrator.hydratedStateOf(traceName = "isVisible", source = legacyInteractor.isShowing)

    override suspend fun onActivated(): Nothing {
        coroutineScope {
            launch {
@@ -74,8 +67,7 @@ constructor(
                    legacyInteractor.hide()
                }
            }

            hydrator.activate()
            awaitCancellation()
        }
    }

+38 −1
Original line number Diff line number Diff line
@@ -30,6 +30,8 @@ import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;

import androidx.core.view.ViewKt;

import com.android.internal.annotations.VisibleForTesting;
import com.android.keyguard.AuthKeyguardMessageArea;
import com.android.keyguard.KeyguardUnfoldTransition;
@@ -38,6 +40,7 @@ import com.android.systemui.Dumpable;
import com.android.systemui.animation.ActivityTransitionAnimator;
import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor;
import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor;
import com.android.systemui.bouncer.shared.flag.ComposeBouncerFlags;
import com.android.systemui.bouncer.ui.binder.BouncerViewBinder;
import com.android.systemui.classifier.FalsingCollector;
import com.android.systemui.dagger.SysUISingleton;
@@ -51,10 +54,12 @@ import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
import com.android.systemui.keyguard.MigrateClocksToBlueprint;
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
import com.android.systemui.keyguard.shared.model.Edge;
import com.android.systemui.keyguard.shared.model.KeyguardState;
import com.android.systemui.keyguard.shared.model.TransitionState;
import com.android.systemui.keyguard.shared.model.TransitionStep;
import com.android.systemui.res.R;
import com.android.systemui.scene.shared.flag.SceneContainerFlag;
import com.android.systemui.scene.shared.model.Scenes;
import com.android.systemui.shade.domain.interactor.PanelExpansionInteractor;
import com.android.systemui.shared.animation.DisableSubpixelTextTransitionListener;
import com.android.systemui.statusbar.DragDownHelper;
@@ -111,6 +116,7 @@ public class NotificationShadeWindowViewController implements Dumpable {
    private final PrimaryBouncerInteractor mPrimaryBouncerInteractor;
    private final AlternateBouncerInteractor mAlternateBouncerInteractor;
    private final QuickSettingsController mQuickSettingsController;
    private final KeyguardTransitionInteractor mKeyguardTransitionInteractor;
    private final GlanceableHubContainerController
            mGlanceableHubContainerController;
    private GestureDetector mPulsingWakeupGestureHandler;
@@ -140,6 +146,7 @@ public class NotificationShadeWindowViewController implements Dumpable {
    private final PanelExpansionInteractor mPanelExpansionInteractor;
    private final ShadeExpansionStateManager mShadeExpansionStateManager;

    private ViewGroup mBouncerParentView;
    /**
     * If {@code true}, an external touch sent in {@link #handleExternalTouch(MotionEvent)} has been
     * intercepted and all future touch events for the gesture should be processed by this view.
@@ -217,6 +224,7 @@ public class NotificationShadeWindowViewController implements Dumpable {
        mPulsingGestureListener = pulsingGestureListener;
        mLockscreenHostedDreamGestureListener = lockscreenHostedDreamGestureListener;
        mNotificationInsetsController = notificationInsetsController;
        mKeyguardTransitionInteractor = keyguardTransitionInteractor;
        mGlanceableHubContainerController = glanceableHubContainerController;
        mFeatureFlagsClassic = featureFlagsClassic;
        mSysUIKeyEventHandler = sysUIKeyEventHandler;
@@ -227,7 +235,7 @@ public class NotificationShadeWindowViewController implements Dumpable {
        // This view is not part of the newly inflated expanded status bar.
        mBrightnessMirror = mView.findViewById(R.id.brightness_mirror_container);
        mDisableSubpixelTextTransitionListener = new DisableSubpixelTextTransitionListener(mView);
        bouncerViewBinder.bind(mView.findViewById(R.id.keyguard_bouncer_container));
        bindBouncer(bouncerViewBinder);

        collectFlow(mView, keyguardTransitionInteractor.transition(
                Edge.create(LOCKSCREEN, DREAMING)),
@@ -256,6 +264,35 @@ public class NotificationShadeWindowViewController implements Dumpable {
        dumpManager.registerDumpable(this);
    }

    private void bindBouncer(BouncerViewBinder bouncerViewBinder) {
        if (ComposeBouncerFlags.INSTANCE.isOnlyComposeBouncerEnabled()) {
            collectFlow(mView, mKeyguardTransitionInteractor.isFinishedIn(Scenes.Gone,
                    KeyguardState.GONE), this::removeBouncerParentView);
            collectFlow(mView, mKeyguardTransitionInteractor.transition(
                            new Edge.StateToState(KeyguardState.GONE, null)),
                    this::handleGoneToAnyOtherStateTransition);
            collectFlow(mView, mPrimaryBouncerInteractor.isShowing(),
                    (showing) -> ViewKt.setVisible(mBouncerParentView, showing));
        }
        mBouncerParentView = mView.findViewById(R.id.keyguard_bouncer_container);
        bouncerViewBinder.bind(mBouncerParentView);
    }

    private void handleGoneToAnyOtherStateTransition(TransitionStep transitionStep) {
        if (transitionStep.getTransitionState() == TransitionState.STARTED) {
            if (mView.indexOfChild(mBouncerParentView) != -1) {
                mView.removeView(mBouncerParentView);
            }
            mView.addView(mBouncerParentView);
        }
    }

    private void removeBouncerParentView(boolean isFinishedInGoneState) {
        if (isFinishedInGoneState) {
            mView.removeView(mBouncerParentView);
        }
    }

    /**
     * @return Location where to place the KeyguardMessageArea
     */