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

Commit 2632db84 authored by Aaron Liu's avatar Aaron Liu Committed by Android (Google) Code Review
Browse files

Merge "Bind preview keyguard rootview to blueprint data." into main

parents 3c0bdfaf 230fa7b6
Loading
Loading
Loading
Loading
+19 −16
Original line number Diff line number Diff line
@@ -25,28 +25,31 @@ interface KeyguardBlueprint {
    val sections: Set<KeyguardSection>

    /**
     * Add views to new blueprint.
     * Removes views of old blueprint and add views of new blueprint.
     *
     * Finds sections that did not exist in the previous blueprint and add the corresponding views.
     * Finds sections that no longer exists in the next blueprint and removes those views. Finds
     * sections that did not exist in the previous blueprint and add the corresponding views.
     *
     * @param previousBluePrint: KeyguardBlueprint the blueprint we are transitioning from.
     * @param previousBlueprint: KeyguardBlueprint the blueprint we are transitioning from.
     * @param constraintLayout: The parent view.
     * @param bindData: Whether to bind the data or not.
     */
    fun addViews(previousBlueprint: KeyguardBlueprint?, constraintLayout: ConstraintLayout) {
    fun replaceViews(
        previousBlueprint: KeyguardBlueprint?,
        constraintLayout: ConstraintLayout,
        bindData: Boolean = true
    ) {
        previousBlueprint?.let { previousBlueprint ->
            previousBlueprint.sections.subtract(sections).forEach {
                it.removeViews(constraintLayout)
            }
        }
        sections.subtract((previousBlueprint?.sections ?: setOf()).toSet()).forEach {
            it.addViews(constraintLayout)
            if (bindData) {
                it.bindData(constraintLayout)
            }
        }

    /**
     * Remove views of old blueprint.
     *
     * Finds sections that are no longer in the next blueprint and remove the corresponding views.
     *
     * @param nextBluePrint: KeyguardBlueprint the blueprint we will transition to.
     */
    fun removeViews(nextBlueprint: KeyguardBlueprint, constraintLayout: ConstraintLayout) {
        sections.subtract(nextBlueprint.sections).forEach { it.removeViews(constraintLayout) }
    }

    fun applyConstraints(constraintSet: ConstraintSet) {
+3 −3
Original line number Diff line number Diff line
@@ -39,15 +39,15 @@ class KeyguardBlueprintViewBinder {
                            val prevBluePrint = viewModel.currentBluePrint
                            Trace.beginSection("KeyguardBlueprint#applyBlueprint")
                            Log.d(TAG, "applying blueprint: $blueprint")
                            // Add and remove views of sections that are not contained by the other.
                            prevBluePrint?.removeViews(blueprint, constraintLayout)
                            blueprint.addViews(prevBluePrint, constraintLayout)

                            ConstraintSet().apply {
                                clone(constraintLayout)
                                val emptyLayout = ConstraintSet.Layout()
                                knownIds.forEach { getConstraint(it).layout.copyFrom(emptyLayout) }
                                blueprint.applyConstraints(this)
                                // Add and remove views of sections that are not contained by the
                                // other.
                                blueprint?.replaceViews(prevBluePrint, constraintLayout)
                                applyTo(constraintLayout)
                            }

+81 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2023 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.binder

import android.os.Trace
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.constraintlayout.widget.ConstraintSet
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.repeatOnLifecycle
import com.android.systemui.keyguard.ui.viewmodel.KeyguardBlueprintViewModel
import com.android.systemui.lifecycle.repeatWhenAttached
import kotlinx.coroutines.launch

/**
 * Binds the existing blueprint to the constraint layout that previews keyguard.
 *
 * This view binder should only inflate and add relevant views and apply the constraints. Actual
 * data binding should be done in {@link KeyguardPreviewRenderer}
 */
class PreviewKeyguardBlueprintViewBinder {
    companion object {

        /**
         * Binds the existing blueprint to the constraint layout that previews keyguard.
         *
         * @param constraintLayout The root view to bind to
         * @param viewModel The instance of the view model that contains flows we collect on.
         * @param finishedAddViewCallback Called when we have finished inflating the views.
         */
        fun bind(
            constraintLayout: ConstraintLayout,
            viewModel: KeyguardBlueprintViewModel,
            finishedAddViewCallback: () -> Unit
        ) {
            constraintLayout.repeatWhenAttached {
                repeatOnLifecycle(Lifecycle.State.CREATED) {
                    launch {
                        viewModel.blueprint.collect { blueprint ->
                            val prevBluePrint = viewModel.currentBluePrint
                            Trace.beginSection("PreviewKeyguardBlueprint#applyBlueprint")

                            ConstraintSet().apply {
                                clone(constraintLayout)
                                val emptyLayout = ConstraintSet.Layout()
                                knownIds.forEach { getConstraint(it).layout.copyFrom(emptyLayout) }
                                blueprint.applyConstraints(this)
                                // Add and remove views of sections that are not contained by the
                                // other.
                                blueprint.replaceViews(
                                    prevBluePrint,
                                    constraintLayout,
                                    bindData = false
                                )
                                applyTo(constraintLayout)
                            }

                            viewModel.currentBluePrint = blueprint
                            finishedAddViewCallback.invoke()
                            Trace.endSection()
                        }
                    }
                }
            }
        }
    }
}
+60 −52
Original line number Diff line number Diff line
@@ -39,19 +39,19 @@ import androidx.core.view.isInvisible
import com.android.keyguard.ClockEventController
import com.android.keyguard.KeyguardClockSwitch
import com.android.systemui.R
import com.android.systemui.animation.view.LaunchableImageView
import com.android.systemui.biometrics.domain.interactor.UdfpsOverlayInteractor
import com.android.systemui.broadcast.BroadcastDispatcher
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
import com.android.systemui.keyguard.domain.interactor.KeyguardBlueprintInteractor
import com.android.systemui.keyguard.ui.binder.KeyguardPreviewClockViewBinder
import com.android.systemui.keyguard.ui.binder.KeyguardPreviewSmartspaceViewBinder
import com.android.systemui.keyguard.ui.binder.KeyguardQuickAffordanceViewBinder
import com.android.systemui.keyguard.ui.binder.KeyguardRootViewBinder
import com.android.systemui.keyguard.ui.binder.PreviewKeyguardBlueprintViewBinder
import com.android.systemui.keyguard.ui.view.KeyguardRootView
import com.android.systemui.keyguard.ui.view.layout.sections.DefaultShortcutsSection
import com.android.systemui.keyguard.ui.viewmodel.KeyguardBlueprintViewModel
import com.android.systemui.keyguard.ui.viewmodel.KeyguardBottomAreaViewModel
import com.android.systemui.keyguard.ui.viewmodel.KeyguardPreviewClockViewModel
@@ -106,11 +106,9 @@ constructor(
    private val keyguardRootViewModel: KeyguardRootViewModel,
    @Assisted bundle: Bundle,
    private val keyguardBlueprintViewModel: KeyguardBlueprintViewModel,
    private val keyguardBlueprintInteractor: KeyguardBlueprintInteractor,
    private val occludingAppDeviceEntryMessageViewModel: OccludingAppDeviceEntryMessageViewModel,
    private val chipbarCoordinator: ChipbarCoordinator,
    private val keyguardStateController: KeyguardStateController,
    private val defaultShortcutsSection: DefaultShortcutsSection,
) {

    val hostToken: IBinder? = bundle.getBinder(KEY_HOST_TOKEN)
@@ -177,26 +175,10 @@ constructor(
        mainHandler.post {
            val rootView = FrameLayout(context)

            if (featureFlags.isEnabled(Flags.MIGRATE_SPLIT_KEYGUARD_BOTTOM_AREA)) {
            setupKeyguardRootView(rootView)
            } else {
                setUpBottomArea(rootView)
            }

            setUpSmartspace(rootView)
            smartSpaceView?.let {
                KeyguardPreviewSmartspaceViewBinder.bind(it, smartspaceViewModel)
            }

            setUpUdfps(rootView)

            if (!shouldHideClock) {
                setUpClock(rootView)
                KeyguardPreviewClockViewBinder.bind(
                    largeClockHostView,
                    smallClockHostView,
                    clockViewModel,
                )
            if (!featureFlags.isEnabled(Flags.MIGRATE_SPLIT_KEYGUARD_BOTTOM_AREA)) {
                setUpBottomArea(rootView)
            }

            rootView.measure(
@@ -332,7 +314,7 @@ constructor(

    @OptIn(ExperimentalCoroutinesApi::class)
    private fun setupKeyguardRootView(rootView: FrameLayout) {
        val keyguardRootView = KeyguardRootView(context, null)
        val keyguardRootView = KeyguardRootView(context, null).apply { removeAllViews() }
        disposables.add(
            KeyguardRootViewBinder.bind(
                keyguardRootView,
@@ -350,14 +332,33 @@ constructor(
                FrameLayout.LayoutParams.MATCH_PARENT,
            ),
        )
        PreviewKeyguardBlueprintViewBinder.bind(keyguardRootView, keyguardBlueprintViewModel) {
            if (featureFlags.isEnabled(Flags.MIGRATE_SPLIT_KEYGUARD_BOTTOM_AREA)) {
                setupShortcuts(keyguardRootView)
            }
            setUpUdfps(rootView)

            if (!shouldHideClock) {
                setUpClock(rootView)
                KeyguardPreviewClockViewBinder.bind(
                    largeClockHostView,
                    smallClockHostView,
                    clockViewModel,
                )
            }

            setUpSmartspace(rootView)
            smartSpaceView?.let {
                KeyguardPreviewSmartspaceViewBinder.bind(it, smartspaceViewModel)
            }
        }
    }

    private fun setupShortcuts(keyguardRootView: ConstraintLayout) {
        defaultShortcutsSection.addShortcutViews(keyguardRootView)
        keyguardRootView.findViewById<LaunchableImageView?>(R.id.start_button)?.let {
            shortcutsBindings.add(
                KeyguardQuickAffordanceViewBinder.bind(
                keyguardRootView.requireViewById(R.id.start_button),
                    it,
                    quickAffordancesCombinedViewModel.startButton,
                    keyguardRootViewModel.alpha,
                    falsingManager,
@@ -366,10 +367,12 @@ constructor(
                    indicationController.showTransientIndication(it)
                }
            )
        }

        keyguardRootView.findViewById<LaunchableImageView?>(R.id.end_button)?.let {
            shortcutsBindings.add(
                KeyguardQuickAffordanceViewBinder.bind(
                keyguardRootView.requireViewById(R.id.end_button),
                    it,
                    quickAffordancesCombinedViewModel.endButton,
                    keyguardRootViewModel.alpha,
                    falsingManager,
@@ -379,6 +382,7 @@ constructor(
                }
            )
        }
    }

    private fun setUpUdfps(parentView: ViewGroup) {
        val sensorBounds = udfpsOverlayInteractor.udfpsOverlayParams.value.sensorBounds
@@ -408,13 +412,17 @@ constructor(
    }

    private fun setUpClock(parentView: ViewGroup) {
        largeClockHostView = createLargeClockHostView()
        largeClockHostView =
            if (featureFlags.isEnabled(Flags.MIGRATE_KEYGUARD_STATUS_VIEW))
                parentView.requireViewById<FrameLayout>(R.id.lockscreen_clock_view_large)
            else createLargeClockHostView()
        largeClockHostView.isInvisible = true
        parentView.addView(largeClockHostView)

        smallClockHostView = createSmallClockHostView(parentView.resources)
        smallClockHostView =
            if (featureFlags.isEnabled(Flags.MIGRATE_KEYGUARD_STATUS_VIEW))
                parentView.requireViewById<FrameLayout>(R.id.lockscreen_clock_view)
            else createSmallClockHostView(parentView.resources)
        smallClockHostView.isInvisible = true
        parentView.addView(smallClockHostView)

        // TODO (b/283465254): Move the listeners to KeyguardClockRepository
        val clockChangeListener =
+4 −3
Original line number Diff line number Diff line
@@ -66,12 +66,13 @@ constructor(
            splitShadeGuidelines,
        )

    override fun addViews(
    override fun replaceViews(
        previousBlueprint: KeyguardBlueprint?,
        constraintLayout: ConstraintLayout
        constraintLayout: ConstraintLayout,
        bindData: Boolean
    ) {
        if (featureFlags.isEnabled(Flags.LAZY_INFLATE_KEYGUARD)) {
            super.addViews(previousBlueprint, constraintLayout)
            super.replaceViews(previousBlueprint, constraintLayout, bindData)
        }
    }

Loading