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

Commit ad20f378 authored by Bill Lin's avatar Bill Lin Committed by Automerger Merge Worker
Browse files

Merge "4-1/ KeyguardBypassController listen for device posture change" into...

Merge "4-1/ KeyguardBypassController listen for device posture change" into tm-qpr-dev am: 89713888

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



Change-Id: I9dc7f97ce158781ef0fea73e037b0666a16db394
Signed-off-by: default avatarAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
parents cfcc692a 89713888
Loading
Loading
Loading
Loading
+36 −3
Original line number Diff line number Diff line
@@ -30,6 +30,9 @@ import com.android.systemui.shade.ShadeExpansionStateManager
import com.android.systemui.statusbar.NotificationLockscreenUserManager
import com.android.systemui.statusbar.StatusBarState
import com.android.systemui.statusbar.notification.stack.StackScrollAlgorithm
import com.android.systemui.statusbar.policy.DevicePostureController
import com.android.systemui.statusbar.policy.DevicePostureController.DEVICE_POSTURE_UNKNOWN
import com.android.systemui.statusbar.policy.DevicePostureController.DevicePostureInt
import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.tuner.TunerService
import java.io.PrintWriter
@@ -40,11 +43,19 @@ open class KeyguardBypassController : Dumpable, StackScrollAlgorithm.BypassContr

    private val mKeyguardStateController: KeyguardStateController
    private val statusBarStateController: StatusBarStateController
    private val devicePostureController: DevicePostureController
    @BypassOverride private val bypassOverride: Int
    private var hasFaceFeature: Boolean
    @DevicePostureInt private val configFaceAuthSupportedPosture: Int
    @DevicePostureInt private var postureState: Int = DEVICE_POSTURE_UNKNOWN
    private var pendingUnlock: PendingUnlock? = null
    private val listeners = mutableListOf<OnBypassStateChangedListener>()

    private val postureCallback = DevicePostureController.Callback { posture ->
        if (postureState != posture) {
            postureState = posture
            notifyListeners()
        }
    }
    private val faceAuthEnabledChangedCallback = object : KeyguardStateController.Callback {
        override fun onFaceAuthEnabledChanged() = notifyListeners()
    }
@@ -86,7 +97,8 @@ open class KeyguardBypassController : Dumpable, StackScrollAlgorithm.BypassContr
                FACE_UNLOCK_BYPASS_NEVER -> false
                else -> field
            }
            return enabled && mKeyguardStateController.isFaceAuthEnabled
            return enabled && mKeyguardStateController.isFaceAuthEnabled &&
                    isPostureAllowedForFaceAuth()
        }
        private set(value) {
            field = value
@@ -106,18 +118,31 @@ open class KeyguardBypassController : Dumpable, StackScrollAlgorithm.BypassContr
        lockscreenUserManager: NotificationLockscreenUserManager,
        keyguardStateController: KeyguardStateController,
        shadeExpansionStateManager: ShadeExpansionStateManager,
        devicePostureController: DevicePostureController,
        dumpManager: DumpManager
    ) {
        this.mKeyguardStateController = keyguardStateController
        this.statusBarStateController = statusBarStateController
        this.devicePostureController = devicePostureController

        bypassOverride = context.resources.getInteger(R.integer.config_face_unlock_bypass_override)
        configFaceAuthSupportedPosture =
            context.resources.getInteger(R.integer.config_face_auth_supported_posture)

        hasFaceFeature = context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_FACE)
        hasFaceFeature = context.packageManager.hasSystemFeature(PackageManager.FEATURE_FACE)
        if (!hasFaceFeature) {
            return
        }

        if (configFaceAuthSupportedPosture != DEVICE_POSTURE_UNKNOWN) {
            devicePostureController.addCallback { posture ->
                if (postureState != posture) {
                    postureState = posture
                    notifyListeners()
                }
            }
        }

        dumpManager.registerDumpable("KeyguardBypassController", this)
        statusBarStateController.addCallback(object : StatusBarStateController.StateListener {
            override fun onStateChanged(newState: Int) {
@@ -203,6 +228,13 @@ open class KeyguardBypassController : Dumpable, StackScrollAlgorithm.BypassContr
        pendingUnlock = null
    }

    fun isPostureAllowedForFaceAuth(): Boolean {
        return when (configFaceAuthSupportedPosture) {
            DEVICE_POSTURE_UNKNOWN -> true
            else -> (postureState == configFaceAuthSupportedPosture)
        }
    }

    override fun dump(pw: PrintWriter, args: Array<out String>) {
        pw.println("KeyguardBypassController:")
        if (pendingUnlock != null) {
@@ -219,6 +251,7 @@ open class KeyguardBypassController : Dumpable, StackScrollAlgorithm.BypassContr
        pw.println("  launchingAffordance: $launchingAffordance")
        pw.println("  qSExpanded: $qsExpanded")
        pw.println("  hasFaceFeature: $hasFaceFeature")
        pw.println("  postureState: $postureState")
    }

    /** Registers a listener for bypass state changes. */
+255 −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.statusbar.phone

import android.content.pm.PackageManager
import android.test.suitebuilder.annotation.SmallTest
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
import com.android.systemui.dump.DumpManager
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.shade.ShadeExpansionStateManager
import com.android.systemui.statusbar.NotificationLockscreenUserManager
import com.android.systemui.statusbar.policy.DevicePostureController
import com.android.systemui.statusbar.policy.DevicePostureController.DEVICE_POSTURE_CLOSED
import com.android.systemui.statusbar.policy.DevicePostureController.DEVICE_POSTURE_FLIPPED
import com.android.systemui.statusbar.policy.DevicePostureController.DEVICE_POSTURE_OPENED
import com.android.systemui.statusbar.policy.DevicePostureController.DEVICE_POSTURE_UNKNOWN
import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.tuner.TunerService
import com.google.common.truth.Truth.assertThat
import org.junit.After
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
import org.mockito.Captor
import org.mockito.Mock
import org.mockito.Mockito.never
import org.mockito.Mockito.reset
import org.mockito.Mockito.verify
import org.mockito.Mockito.`when` as whenever
import org.mockito.junit.MockitoJUnit

@SmallTest
@RunWith(AndroidTestingRunner::class)
@TestableLooper.RunWithLooper
class KeyguardBypassControllerTest : SysuiTestCase() {

    private lateinit var keyguardBypassController: KeyguardBypassController
    private lateinit var postureControllerCallback: DevicePostureController.Callback
    @Mock private lateinit var tunerService: TunerService
    @Mock private lateinit var statusBarStateController: StatusBarStateController
    @Mock private lateinit var lockscreenUserManager: NotificationLockscreenUserManager
    @Mock private lateinit var keyguardStateController: KeyguardStateController
    @Mock private lateinit var shadeExpansionStateManager: ShadeExpansionStateManager
    @Mock private lateinit var devicePostureController: DevicePostureController
    @Mock private lateinit var dumpManager: DumpManager
    @Mock private lateinit var packageManager: PackageManager
    @Captor
    private val postureCallbackCaptor =
        ArgumentCaptor.forClass(DevicePostureController.Callback::class.java)
    @JvmField @Rule val mockito = MockitoJUnit.rule()

    @Before
    fun setUp() {
        context.setMockPackageManager(packageManager)
        whenever(packageManager.hasSystemFeature(PackageManager.FEATURE_FACE)).thenReturn(true)
        whenever(keyguardStateController.isFaceAuthEnabled).thenReturn(true)
    }

    @After
    fun tearDown() {
        reset(devicePostureController)
        reset(keyguardStateController)
    }

    private fun defaultConfigPostureClosed() {
        context.orCreateTestableResources.addOverride(
            R.integer.config_face_auth_supported_posture,
            DEVICE_POSTURE_CLOSED
        )
        initKeyguardBypassController()
        verify(devicePostureController).addCallback(postureCallbackCaptor.capture())
        postureControllerCallback = postureCallbackCaptor.value
    }

    private fun defaultConfigPostureOpened() {
        context.orCreateTestableResources.addOverride(
            R.integer.config_face_auth_supported_posture,
            DEVICE_POSTURE_OPENED
        )
        initKeyguardBypassController()
        verify(devicePostureController).addCallback(postureCallbackCaptor.capture())
        postureControllerCallback = postureCallbackCaptor.value
    }

    private fun defaultConfigPostureFlipped() {
        context.orCreateTestableResources.addOverride(
            R.integer.config_face_auth_supported_posture,
            DEVICE_POSTURE_FLIPPED
        )
        initKeyguardBypassController()
        verify(devicePostureController).addCallback(postureCallbackCaptor.capture())
        postureControllerCallback = postureCallbackCaptor.value
    }

    private fun defaultConfigPostureUnknown() {
        context.orCreateTestableResources.addOverride(
            R.integer.config_face_auth_supported_posture,
            DEVICE_POSTURE_UNKNOWN
        )
        initKeyguardBypassController()
        verify(devicePostureController, never()).addCallback(postureCallbackCaptor.capture())
    }

    private fun initKeyguardBypassController() {
        keyguardBypassController =
            KeyguardBypassController(
                context,
                tunerService,
                statusBarStateController,
                lockscreenUserManager,
                keyguardStateController,
                shadeExpansionStateManager,
                devicePostureController,
                dumpManager
            )
    }

    @Test
    fun configDevicePostureClosed_matchState_isPostureAllowedForFaceAuth_returnTrue() {
        defaultConfigPostureClosed()

        postureControllerCallback.onPostureChanged(DEVICE_POSTURE_CLOSED)

        assertThat(keyguardBypassController.isPostureAllowedForFaceAuth()).isTrue()
    }

    @Test
    fun configDevicePostureOpen_matchState_isPostureAllowedForFaceAuth_returnTrue() {
        defaultConfigPostureOpened()

        postureControllerCallback.onPostureChanged(DEVICE_POSTURE_OPENED)

        assertThat(keyguardBypassController.isPostureAllowedForFaceAuth()).isTrue()
    }

    @Test
    fun configDevicePostureFlipped_matchState_isPostureAllowedForFaceAuth_returnTrue() {
        defaultConfigPostureFlipped()

        postureControllerCallback.onPostureChanged(DEVICE_POSTURE_FLIPPED)

        assertThat(keyguardBypassController.isPostureAllowedForFaceAuth()).isTrue()
    }

    @Test
    fun configDevicePostureClosed_changeOpened_isPostureAllowedForFaceAuth_returnFalse() {
        defaultConfigPostureClosed()

        postureControllerCallback.onPostureChanged(DEVICE_POSTURE_OPENED)

        assertThat(keyguardBypassController.isPostureAllowedForFaceAuth()).isFalse()
    }

    @Test
    fun configDevicePostureClosed_changeFlipped_isPostureAllowedForFaceAuth_returnFalse() {
        defaultConfigPostureClosed()

        postureControllerCallback.onPostureChanged(DEVICE_POSTURE_FLIPPED)

        assertThat(keyguardBypassController.isPostureAllowedForFaceAuth()).isFalse()
    }

    @Test
    fun configDevicePostureOpened_changeClosed_isPostureAllowedForFaceAuth_returnFalse() {
        defaultConfigPostureOpened()

        postureControllerCallback.onPostureChanged(DEVICE_POSTURE_CLOSED)

        assertThat(keyguardBypassController.isPostureAllowedForFaceAuth()).isFalse()
    }

    @Test
    fun configDevicePostureOpened_changeFlipped_isPostureAllowedForFaceAuth_returnFalse() {
        defaultConfigPostureOpened()

        postureControllerCallback.onPostureChanged(DEVICE_POSTURE_FLIPPED)

        assertThat(keyguardBypassController.isPostureAllowedForFaceAuth()).isFalse()
    }

    @Test
    fun configDevicePostureFlipped_changeClosed_isPostureAllowedForFaceAuth_returnFalse() {
        defaultConfigPostureFlipped()

        postureControllerCallback.onPostureChanged(DEVICE_POSTURE_CLOSED)

        assertThat(keyguardBypassController.isPostureAllowedForFaceAuth()).isFalse()
    }

    @Test
    fun configDevicePostureFlipped_changeOpened_isPostureAllowedForFaceAuth_returnFalse() {
        defaultConfigPostureFlipped()

        postureControllerCallback.onPostureChanged(DEVICE_POSTURE_OPENED)

        assertThat(keyguardBypassController.isPostureAllowedForFaceAuth()).isFalse()
    }

    @Test
    fun defaultConfigPostureClosed_canOverrideByPassAlways_shouldReturnFalse() {
        context.orCreateTestableResources.addOverride(
            R.integer.config_face_unlock_bypass_override,
            1 /* FACE_UNLOCK_BYPASS_ALWAYS */
        )

        defaultConfigPostureClosed()

        postureControllerCallback.onPostureChanged(DEVICE_POSTURE_OPENED)

        assertThat(keyguardBypassController.bypassEnabled).isFalse()
    }

    @Test
    fun defaultConfigPostureUnknown_canNotOverrideByPassAlways_shouldReturnTrue() {
        context.orCreateTestableResources.addOverride(
            R.integer.config_face_unlock_bypass_override,
            1 /* FACE_UNLOCK_BYPASS_ALWAYS */
        )

        defaultConfigPostureUnknown()

        assertThat(keyguardBypassController.bypassEnabled).isTrue()
    }

    @Test
    fun defaultConfigPostureUnknown_canNotOverrideByPassNever_shouldReturnFalse() {
        context.orCreateTestableResources.addOverride(
            R.integer.config_face_unlock_bypass_override,
            2 /* FACE_UNLOCK_BYPASS_NEVER */
        )

        defaultConfigPostureUnknown()

        assertThat(keyguardBypassController.bypassEnabled).isFalse()
    }
}