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

Commit 82f38e6a authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "[flexiglass] Moves alternate bouncer (back) to its own window." into main

parents 2e5cf644 eca402eb
Loading
Loading
Loading
Loading
+19 −4
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package com.android.systemui.keyguard.ui.composable

import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.Crossfade
import androidx.compose.animation.core.MutableTransitionState
import androidx.compose.animation.core.tween
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
@@ -29,7 +30,9 @@ import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
@@ -60,13 +63,25 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi
@Composable
fun AlternateBouncer(
    alternateBouncerDependencies: AlternateBouncerDependencies,
    onHideAnimationFinished: () -> Unit,
    modifier: Modifier = Modifier,
) {

    val isVisible by
        alternateBouncerDependencies.viewModel.isVisible.collectAsStateWithLifecycle(
            initialValue = false
        )
        alternateBouncerDependencies.viewModel.isVisible.collectAsStateWithLifecycle(true)
    val visibleState = remember { MutableTransitionState(isVisible) }

    // Feeds the isVisible value to the MutableTransitionState used by AnimatedVisibility below.
    LaunchedEffect(isVisible) { visibleState.targetState = isVisible }

    // Watches the MutableTransitionState and calls onHideAnimationFinished when the fade out
    // animation is finished. This way the window view is removed from the view hierarchy only after
    // the fade out animation is complete.
    LaunchedEffect(visibleState.currentState, visibleState.isIdle) {
        if (!visibleState.currentState && visibleState.isIdle) {
            onHideAnimationFinished()
        }
    }

    val udfpsIconLocation by
        alternateBouncerDependencies.udfpsIconViewModel.iconLocation.collectAsStateWithLifecycle(
@@ -74,7 +89,7 @@ fun AlternateBouncer(
        )

    AnimatedVisibility(
        visible = isVisible,
        visibleState = visibleState,
        enter = fadeIn(),
        exit = fadeOut(),
        modifier = modifier,
+7 −0
Original line number Diff line number Diff line
@@ -62,6 +62,7 @@ import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor;
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionBootInteractor;
import com.android.systemui.keyguard.domain.interactor.StartKeyguardTransitionModule;
import com.android.systemui.keyguard.ui.transitions.DeviceEntryIconTransitionModule;
import com.android.systemui.keyguard.ui.view.AlternateBouncerWindowViewBinder;
import com.android.systemui.keyguard.ui.viewmodel.KeyguardQuickAffordancesCombinedViewModelModule;
import com.android.systemui.log.SessionTracker;
import com.android.systemui.navigationbar.NavigationModeController;
@@ -248,4 +249,10 @@ public interface KeyguardModule {
    @IntoMap
    @ClassKey(KeyguardUpdateMonitor.class)
    CoreStartable bindsKeyguardUpdateMonitor(KeyguardUpdateMonitor keyguardUpdateMonitor);

    /***/
    @Binds
    @IntoMap
    @ClassKey(AlternateBouncerWindowViewBinder.class)
    CoreStartable bindsAlternateBouncerWindowViewBinder(AlternateBouncerWindowViewBinder binder);
}
+4 −25
Original line number Diff line number Diff line
@@ -16,9 +16,7 @@

package com.android.systemui.keyguard.ui.binder

import android.graphics.PixelFormat
import android.util.Log
import android.view.Gravity
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
@@ -36,6 +34,7 @@ import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.deviceentry.ui.binder.UdfpsAccessibilityOverlayBinder
import com.android.systemui.deviceentry.ui.view.UdfpsAccessibilityOverlay
import com.android.systemui.deviceentry.ui.viewmodel.AlternateBouncerUdfpsAccessibilityOverlayViewModel
import com.android.systemui.keyguard.ui.view.AlternateBouncerWindowViewLayoutParams
import com.android.systemui.keyguard.ui.view.DeviceEntryIconView
import com.android.systemui.keyguard.ui.viewmodel.AlternateBouncerDependencies
import com.android.systemui.keyguard.ui.viewmodel.AlternateBouncerUdfpsIconViewModel
@@ -68,28 +67,6 @@ constructor(
    private val windowManager: Lazy<WindowManager>,
    private val layoutInflater: Lazy<LayoutInflater>,
) : CoreStartable {
    private val layoutParams: WindowManager.LayoutParams
        get() =
            WindowManager.LayoutParams(
                    WindowManager.LayoutParams.MATCH_PARENT,
                    WindowManager.LayoutParams.MATCH_PARENT,
                    WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG,
                    WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN or
                        WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED,
                    PixelFormat.TRANSLUCENT,
                )
                .apply {
                    title = "AlternateBouncerView"
                    fitInsetsTypes = 0 // overrides default, avoiding status bars during layout
                    gravity = Gravity.TOP or Gravity.LEFT
                    layoutInDisplayCutoutMode =
                        WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS
                    privateFlags =
                        WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY or
                            WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION
                    // Avoid announcing window title.
                    accessibilityTitle = " "
                }

    private var alternateBouncerView: ConstraintLayout? = null

@@ -176,7 +153,9 @@ constructor(
                as ConstraintLayout

        Log.d(TAG, "Adding alternate bouncer view")
        windowManager.get().addView(alternateBouncerView, layoutParams)
        windowManager
            .get()
            .addView(alternateBouncerView, AlternateBouncerWindowViewLayoutParams.layoutParams)
        alternateBouncerView!!.addOnAttachStateChangeListener(onAttachAddBackGestureHandler)
    }

+102 −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.keyguard.ui.view

import android.content.Context
import android.view.View
import android.view.WindowManager
import android.widget.FrameLayout
import androidx.compose.ui.platform.ComposeView
import com.android.systemui.CoreStartable
import com.android.systemui.compose.ComposeInitializer
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.keyguard.ui.composable.AlternateBouncer
import com.android.systemui.keyguard.ui.viewmodel.AlternateBouncerDependencies
import com.android.systemui.keyguard.ui.viewmodel.AlternateBouncerViewModel
import com.android.systemui.lifecycle.repeatWhenAttached
import com.android.systemui.lifecycle.repeatWhenAttachedToWindow
import com.android.systemui.scene.shared.flag.SceneContainerFlag
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.awaitCancellation
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.launch

/** Drives the showing and hiding of the alternate bouncer window. */
@SysUISingleton
class AlternateBouncerWindowViewBinder
@Inject
constructor(
    @Application private val applicationScope: CoroutineScope,
    @Application private val context: Context,
    private val viewModel: AlternateBouncerViewModel,
    private val dependencies: AlternateBouncerDependencies,
    private val windowManager: WindowManager,
) : CoreStartable {

    override fun start() {
        if (!SceneContainerFlag.isEnabled) {
            return
        }

        applicationScope.launch {
            viewModel.isVisible
                .distinctUntilChanged()
                .filter { it }
                .collect {
                    windowManager.addView(
                        createView(),
                        AlternateBouncerWindowViewLayoutParams.layoutParams,
                    )
                }
        }
    }

    private fun createView(): View {
        val root = FrameLayout(context)
        val composeView =
            ComposeView(context).apply {
                setContent {
                    AlternateBouncer(
                        alternateBouncerDependencies = dependencies,
                        onHideAnimationFinished = {
                            if (root.isAttachedToWindow) {
                                windowManager.removeView(root)
                            }
                        },
                    )
                }
            }

        root.repeatWhenAttached {
            root.repeatWhenAttachedToWindow {
                try {
                    ComposeInitializer.onAttachedToWindow(root)
                    root.addView(composeView)
                    awaitCancellation()
                } finally {
                    root.removeView(composeView)
                    ComposeInitializer.onDetachedFromWindow(root)
                }
            }
        }

        return root
    }
}
+46 −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.keyguard.ui.view

import android.graphics.PixelFormat
import android.view.Gravity
import android.view.WindowManager

object AlternateBouncerWindowViewLayoutParams {
    val layoutParams: WindowManager.LayoutParams
        get() =
            WindowManager.LayoutParams(
                    WindowManager.LayoutParams.MATCH_PARENT,
                    WindowManager.LayoutParams.MATCH_PARENT,
                    WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG,
                    WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN or
                        WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED,
                    PixelFormat.TRANSLUCENT,
                )
                .apply {
                    title = "AlternateBouncerView"
                    fitInsetsTypes = 0 // overrides default, avoiding status bars during layout
                    gravity = Gravity.TOP or Gravity.LEFT
                    layoutInDisplayCutoutMode =
                        WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS
                    privateFlags =
                        WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY or
                            WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION
                    // Avoid announcing window title.
                    accessibilityTitle = " "
                }
}
Loading