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

Commit 1de7f584 authored by Chandru S's avatar Chandru S Committed by Automerger Merge Worker
Browse files

Merge "Provide API for accessing the current state of secure camera." into...

Merge "Provide API for accessing the current state of secure camera." into tm-qpr-dev am: d4768d6e

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/21008158



Change-Id: I7b2820f31890fc8d8c6fac1849e4411aeb543215
Signed-off-by: default avatarAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
parents 1d606903 d4768d6e
Loading
Loading
Loading
Loading
+175 −155
Original line number Diff line number Diff line
@@ -24,8 +24,8 @@ import android.content.res.Resources
import android.text.format.DateFormat
import android.util.TypedValue
import android.view.View
import android.widget.FrameLayout
import android.view.ViewTreeObserver
import android.widget.FrameLayout
import androidx.annotation.VisibleForTesting
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.repeatOnLifecycle
@@ -40,8 +40,8 @@ import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.lifecycle.repeatWhenAttached
import com.android.systemui.log.dagger.KeyguardSmallClockLog
import com.android.systemui.log.dagger.KeyguardLargeClockLog
import com.android.systemui.log.dagger.KeyguardSmallClockLog
import com.android.systemui.plugins.ClockController
import com.android.systemui.plugins.ClockFaceController
import com.android.systemui.plugins.ClockTickRate
@@ -53,22 +53,24 @@ import com.android.systemui.statusbar.policy.BatteryController
import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback
import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.util.concurrency.DelayableExecutor
import java.util.Locale
import java.util.TimeZone
import java.util.concurrent.Executor
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.DisposableHandle
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.launch
import java.util.Locale
import java.util.TimeZone
import java.util.concurrent.Executor
import javax.inject.Inject

/**
 * Controller for a Clock provided by the registry and used on the keyguard. Instantiated by
 * [KeyguardClockSwitchController]. Functionality is forked from [AnimatableClockController].
 */
open class ClockEventController @Inject constructor(
open class ClockEventController
@Inject
constructor(
    private val keyguardInteractor: KeyguardInteractor,
    private val keyguardTransitionInteractor: KeyguardTransitionInteractor,
    private val broadcastDispatcher: BroadcastDispatcher,
@@ -115,7 +117,8 @@ open class ClockEventController @Inject constructor(
    private var disposableHandle: DisposableHandle? = null
    private val regionSamplingEnabled = featureFlags.isEnabled(REGION_SAMPLING)

    private val mLayoutChangedListener = object : View.OnLayoutChangeListener {
    private val mLayoutChangedListener =
        object : View.OnLayoutChangeListener {
            private var currentSmallClockView: View? = null
            private var currentLargeClockView: View? = null
            private var currentSmallClockLocation = IntArray(2)
@@ -141,10 +144,14 @@ open class ClockEventController @Inject constructor(

                // SMALL CLOCK
                if (parent.id == R.id.lockscreen_clock_view) {
            // view bounds have changed due to clock size changing (i.e. different character widths)
            // AND/OR the view has been translated when transitioning between small and large clock
            if (view != currentSmallClockView ||
                !view.locationOnScreen.contentEquals(currentSmallClockLocation)) {
                    // view bounds have changed due to clock size changing (i.e. different character
                    // widths)
                    // AND/OR the view has been translated when transitioning between small and
                    // large clock
                    if (
                        view != currentSmallClockView ||
                            !view.locationOnScreen.contentEquals(currentSmallClockLocation)
                    ) {
                        currentSmallClockView = view
                        currentSmallClockLocation = view.locationOnScreen
                        updateRegionSampler(view)
@@ -152,8 +159,10 @@ open class ClockEventController @Inject constructor(
                }
                // LARGE CLOCK
                else if (parent.id == R.id.lockscreen_clock_view_large) {
            if (view != currentLargeClockView ||
                !view.locationOnScreen.contentEquals(currentLargeClockLocation)) {
                    if (
                        view != currentLargeClockView ||
                            !view.locationOnScreen.contentEquals(currentLargeClockLocation)
                    ) {
                        currentLargeClockView = view
                        currentLargeClockLocation = view.locationOnScreen
                        updateRegionSampler(view)
@@ -189,13 +198,15 @@ open class ClockEventController @Inject constructor(

    private fun updateRegionSampler(sampledRegion: View) {
        regionSampler?.stopRegionSampler()
        regionSampler = createRegionSampler(
        regionSampler =
            createRegionSampler(
                    sampledRegion,
                    mainExecutor,
                    bgExecutor,
                    regionSamplingEnabled,
                    ::updateColors
        )?.apply { startRegionSampler() }
                )
                ?.apply { startRegionSampler() }

        updateColors()
    }
@@ -212,7 +223,8 @@ open class ClockEventController @Inject constructor(
            mainExecutor,
            bgExecutor,
            regionSamplingEnabled,
            updateColors)
            updateColors
        )
    }

    var regionSampler: RegionSampler? = null
@@ -224,7 +236,8 @@ open class ClockEventController @Inject constructor(
    private var smallClockIsDark = true
    private var largeClockIsDark = true

    private val configListener = object : ConfigurationController.ConfigurationListener {
    private val configListener =
        object : ConfigurationController.ConfigurationListener {
            override fun onThemeChanged() {
                clock?.events?.onColorPaletteChanged(resources)
                updateColors()
@@ -235,7 +248,8 @@ open class ClockEventController @Inject constructor(
            }
        }

    private val batteryCallback = object : BatteryStateChangeCallback {
    private val batteryCallback =
        object : BatteryStateChangeCallback {
            override fun onBatteryLevelChanged(level: Int, pluggedIn: Boolean, charging: Boolean) {
                if (isKeyguardVisible && !isCharging && charging) {
                    clock?.animations?.charge()
@@ -244,13 +258,15 @@ open class ClockEventController @Inject constructor(
            }
        }

    private val localeBroadcastReceiver = object : BroadcastReceiver() {
    private val localeBroadcastReceiver =
        object : BroadcastReceiver() {
            override fun onReceive(context: Context, intent: Intent) {
                clock?.events?.onLocaleChanged(Locale.getDefault())
            }
        }

    private val keyguardUpdateMonitorCallback = object : KeyguardUpdateMonitorCallback() {
    private val keyguardUpdateMonitorCallback =
        object : KeyguardUpdateMonitorCallback() {
            override fun onKeyguardVisibilityChanged(visible: Boolean) {
                isKeyguardVisible = visible
                if (!featureFlags.isEnabled(DOZING_MIGRATION_1)) {
@@ -295,7 +311,8 @@ open class ClockEventController @Inject constructor(
        configurationController.addCallback(configListener)
        batteryController.addCallback(batteryCallback)
        keyguardUpdateMonitor.registerCallback(keyguardUpdateMonitorCallback)
        disposableHandle = parent.repeatWhenAttached {
        disposableHandle =
            parent.repeatWhenAttached {
                repeatOnLifecycle(Lifecycle.State.STARTED) {
                    listenForDozing(this)
                    if (featureFlags.isEnabled(DOZING_MIGRATION_1)) {
@@ -344,10 +361,18 @@ open class ClockEventController @Inject constructor(
    }

    private fun updateFontSizes() {
        clock?.smallClock?.events?.onFontSettingChanged(
            resources.getDimensionPixelSize(R.dimen.small_clock_text_size).toFloat())
        clock?.largeClock?.events?.onFontSettingChanged(
            resources.getDimensionPixelSize(R.dimen.large_clock_text_size).toFloat())
        clock
            ?.smallClock
            ?.events
            ?.onFontSettingChanged(
                resources.getDimensionPixelSize(R.dimen.small_clock_text_size).toFloat()
            )
        clock
            ?.largeClock
            ?.events
            ?.onFontSettingChanged(
                resources.getDimensionPixelSize(R.dimen.large_clock_text_size).toFloat()
            )
    }

    private fun handleDoze(doze: Float) {
@@ -359,34 +384,25 @@ open class ClockEventController @Inject constructor(

    @VisibleForTesting
    internal fun listenForDozeAmount(scope: CoroutineScope): Job {
        return scope.launch {
            keyguardInteractor.dozeAmount.collect {
                handleDoze(it)
            }
        }
        return scope.launch { keyguardInteractor.dozeAmount.collect { handleDoze(it) } }
    }

    @VisibleForTesting
    internal fun listenForDozeAmountTransition(scope: CoroutineScope): Job {
        return scope.launch {
            keyguardTransitionInteractor.dozeAmountTransition.collect {
                handleDoze(it.value)
            }
            keyguardTransitionInteractor.dozeAmountTransition.collect { handleDoze(it.value) }
        }
    }

    /**
     * When keyguard is displayed again after being gone, the clock must be reset to full
     * dozing.
     * When keyguard is displayed again after being gone, the clock must be reset to full dozing.
     */
    @VisibleForTesting
    internal fun listenForAnyStateToAodTransition(scope: CoroutineScope): Job {
        return scope.launch {
            keyguardTransitionInteractor.anyStateToAodTransition.filter {
                it.transitionState == TransitionState.FINISHED
            }.collect {
                handleDoze(1f)
            }
            keyguardTransitionInteractor.anyStateToAodTransition
                .filter { it.transitionState == TransitionState.FINISHED }
                .collect { handleDoze(1f) }
        }
    }

@@ -399,19 +415,19 @@ open class ClockEventController @Inject constructor(
                ) { localDozeAmount, localIsDozing ->
                    localDozeAmount > dozeAmount || localIsDozing
                }
            .collect { localIsDozing ->
                isDozing = localIsDozing
            }
                .collect { localIsDozing -> isDozing = localIsDozing }
        }
    }

    class TimeListener(val clockFace: ClockFaceController, val executor: DelayableExecutor) {
        val predrawListener = ViewTreeObserver.OnPreDrawListener {
        val predrawListener =
            ViewTreeObserver.OnPreDrawListener {
                clockFace.events.onTimeTick()
                true
            }

        val secondsRunnable = object : Runnable {
        val secondsRunnable =
            object : Runnable {
                override fun run() {
                    if (!isRunning) {
                        return
@@ -432,7 +448,9 @@ open class ClockEventController @Inject constructor(

            isRunning = true
            when (clockFace.events.tickRate) {
                ClockTickRate.PER_MINUTE -> {/* Handled by KeyguardClockSwitchController */}
                ClockTickRate.PER_MINUTE -> {
                    /* Handled by KeyguardClockSwitchController */
                }
                ClockTickRate.PER_SECOND -> executor.execute(secondsRunnable)
                ClockTickRate.PER_FRAME -> {
                    clockFace.view.viewTreeObserver.addOnPreDrawListener(predrawListener)
@@ -442,7 +460,9 @@ open class ClockEventController @Inject constructor(
        }

        fun stop() {
            if (!isRunning) { return }
            if (!isRunning) {
                return
            }

            isRunning = false
            clockFace.view.viewTreeObserver.removeOnPreDrawListener(predrawListener)
+28 −1
Original line number Diff line number Diff line
@@ -22,6 +22,8 @@ import android.graphics.Point
import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
import com.android.systemui.keyguard.data.repository.KeyguardRepository
import com.android.systemui.keyguard.shared.model.BiometricUnlockModel
import com.android.systemui.keyguard.shared.model.CameraLaunchSourceModel
@@ -31,7 +33,6 @@ import com.android.systemui.keyguard.shared.model.DozeTransitionModel
import com.android.systemui.keyguard.shared.model.StatusBarState
import com.android.systemui.keyguard.shared.model.WakefulnessModel
import com.android.systemui.statusbar.CommandQueue
import com.android.systemui.statusbar.CommandQueue.Callbacks
import javax.inject.Inject
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.delay
@@ -41,7 +42,9 @@ import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.merge
import kotlinx.coroutines.flow.onStart

/**
 * Encapsulates business-logic related to the keyguard but not to a more specific part within it.
@@ -52,6 +55,7 @@ class KeyguardInteractor
constructor(
    private val repository: KeyguardRepository,
    private val commandQueue: CommandQueue,
    featureFlags: FeatureFlags,
) {
    /**
     * The amount of doze the system is in, where `1.0` is fully dozing and `0.0` is not dozing at
@@ -129,6 +133,29 @@ constructor(
     */
    val biometricUnlockState: Flow<BiometricUnlockModel> = repository.biometricUnlockState

    /** Keyguard is present and is not occluded. */
    val isKeyguardVisible: Flow<Boolean> =
        combine(isKeyguardShowing, isKeyguardOccluded) { showing, occluded -> showing && !occluded }

    /** Whether camera is launched over keyguard. */
    var isSecureCameraActive =
        if (featureFlags.isEnabled(Flags.FACE_AUTH_REFACTOR)) {
            combine(
                    isKeyguardVisible,
                    repository.isBouncerShowing,
                    onCameraLaunchDetected,
                ) { isKeyguardVisible, isBouncerShowing, cameraLaunchEvent ->
                    when {
                        isKeyguardVisible -> false
                        isBouncerShowing -> false
                        else -> cameraLaunchEvent == CameraLaunchSourceModel.POWER_DOUBLE_TAP
                    }
                }
                .onStart { emit(false) }
        } else {
            flowOf(false)
        }

    /** The approximate location on the screen of the fingerprint sensor, if one is available. */
    val fingerprintSensorLocation: Flow<Point?> = repository.fingerprintSensorLocation

+4 −2
Original line number Diff line number Diff line
@@ -58,7 +58,7 @@ import org.mockito.Mockito.never
import org.mockito.Mockito.times
import org.mockito.Mockito.verify
import org.mockito.junit.MockitoJUnit
import java.util.*
import java.util.TimeZone
import java.util.concurrent.Executor
import org.mockito.Mockito.`when` as whenever

@@ -105,7 +105,9 @@ class ClockEventControllerTest : SysuiTestCase() {
        repository = FakeKeyguardRepository()

        underTest = ClockEventController(
            KeyguardInteractor(repository = repository, commandQueue = commandQueue),
            KeyguardInteractor(repository = repository,
                    commandQueue = commandQueue,
                    featureFlags = featureFlags),
            KeyguardTransitionInteractor(repository = transitionRepository),
            broadcastDispatcher,
            batteryController,
+3 −1
Original line number Diff line number Diff line
@@ -159,7 +159,9 @@ public class LockIconViewControllerBaseTest extends SysuiTestCase {
                mAuthRippleController,
                mResources,
                new KeyguardTransitionInteractor(mTransitionRepository),
                new KeyguardInteractor(new FakeKeyguardRepository(), mCommandQueue),
                new KeyguardInteractor(new FakeKeyguardRepository(),
                        mCommandQueue,
                        mFeatureFlags),
                mFeatureFlags
        );
    }
+10 −7
Original line number Diff line number Diff line
@@ -157,25 +157,28 @@ class CustomizationProviderTest : SysuiTestCase() {
                dumpManager = mock(),
                userHandle = UserHandle.SYSTEM,
            )
        val featureFlags =
            FakeFeatureFlags().apply {
                set(Flags.CUSTOMIZABLE_LOCK_SCREEN_QUICK_AFFORDANCES, true)
                set(Flags.LOCKSCREEN_CUSTOM_CLOCKS, true)
                set(Flags.REVAMPED_WALLPAPER_UI, true)
                set(Flags.WALLPAPER_FULLSCREEN_PREVIEW, true)
                set(Flags.FACE_AUTH_REFACTOR, true)
            }
        underTest.interactor =
            KeyguardQuickAffordanceInteractor(
                keyguardInteractor =
                    KeyguardInteractor(
                        repository = FakeKeyguardRepository(),
                        commandQueue = commandQueue,
                        featureFlags = featureFlags,
                    ),
                registry = mock(),
                lockPatternUtils = lockPatternUtils,
                keyguardStateController = keyguardStateController,
                userTracker = userTracker,
                activityStarter = activityStarter,
                featureFlags =
                    FakeFeatureFlags().apply {
                        set(Flags.CUSTOMIZABLE_LOCK_SCREEN_QUICK_AFFORDANCES, true)
                        set(Flags.LOCKSCREEN_CUSTOM_CLOCKS, true)
                        set(Flags.REVAMPED_WALLPAPER_UI, true)
                        set(Flags.WALLPAPER_FULLSCREEN_PREVIEW, true)
                    },
                featureFlags = featureFlags,
                repository = { quickAffordanceRepository },
                launchAnimator = launchAnimator,
            )
Loading