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

Commit 708ef5e7 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Check keyguard policy before launching note shortcut at lock screen" into udc-dev

parents e75fc3d9 c3238b51
Loading
Loading
Loading
Loading
+32 −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.devicepolicy

import android.app.admin.DevicePolicyManager
import android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_FEATURES_ALL
import android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_SHORTCUTS_ALL
import android.content.ComponentName

/** Returns true if the admin of [userId] disallows keyguard shortcuts. */
fun DevicePolicyManager.areKeyguardShortcutsDisabled(
    admin: ComponentName? = null,
    userId: Int
): Boolean {
    val flags = getKeyguardDisabledFeatures(admin, userId)
    return flags and KEYGUARD_DISABLE_SHORTCUTS_ALL == KEYGUARD_DISABLE_SHORTCUTS_ALL ||
        flags and KEYGUARD_DISABLE_FEATURES_ALL == KEYGUARD_DISABLE_FEATURES_ALL
}
+5 −10
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@ import com.android.systemui.animation.DialogLaunchAnimator
import com.android.systemui.animation.Expandable
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.devicepolicy.areKeyguardShortcutsDisabled
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceConfig
@@ -410,15 +411,9 @@ constructor(
        )
    }

    private suspend fun isFeatureDisabledByDevicePolicy(): Boolean {
        val flags =
    private suspend fun isFeatureDisabledByDevicePolicy(): Boolean =
        withContext(backgroundDispatcher) {
                devicePolicyManager.getKeyguardDisabledFeatures(null, userTracker.userId)
            }
        val flagsToCheck =
            DevicePolicyManager.KEYGUARD_DISABLE_FEATURES_ALL or
                DevicePolicyManager.KEYGUARD_DISABLE_SHORTCUTS_ALL
        return flagsToCheck and flags != 0
            devicePolicyManager.areKeyguardShortcutsDisabled(userId = userTracker.userId)
        }

    companion object {
+18 −1
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package com.android.systemui.notetask

import android.app.KeyguardManager
import android.app.admin.DevicePolicyManager
import android.content.ActivityNotFoundException
import android.content.ComponentName
import android.content.Context
@@ -27,7 +28,9 @@ import android.os.UserManager
import android.util.Log
import androidx.annotation.VisibleForTesting
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.devicepolicy.areKeyguardShortcutsDisabled
import com.android.systemui.notetask.shortcut.CreateNoteTaskShortcutActivity
import com.android.systemui.settings.UserTracker
import com.android.systemui.util.kotlin.getOrNull
import com.android.wm.shell.bubbles.Bubble
import com.android.wm.shell.bubbles.Bubbles
@@ -54,6 +57,8 @@ constructor(
    private val optionalUserManager: Optional<UserManager>,
    private val optionalKeyguardManager: Optional<KeyguardManager>,
    @NoteTaskEnabledKey private val isEnabled: Boolean,
    private val devicePolicyManager: DevicePolicyManager,
    private val userTracker: UserTracker,
) {

    @VisibleForTesting val infoReference = AtomicReference<NoteTaskInfo?>()
@@ -107,11 +112,23 @@ constructor(
        // TODO(b/249954038): We should handle direct boot (isUserUnlocked). For now, we do nothing.
        if (!userManager.isUserUnlocked) return

        val isKeyguardLocked = keyguardManager.isKeyguardLocked
        // KeyguardQuickAffordanceInteractor blocks the quick affordance from showing in the
        // keyguard if it is not allowed by the admin policy. Here we block any other way to show
        // note task when the screen is locked.
        if (
            isKeyguardLocked &&
                devicePolicyManager.areKeyguardShortcutsDisabled(userId = userTracker.userId)
        ) {
            logDebug { "Enterprise policy disallows launching note app when the screen is locked." }
            return
        }

        val info =
            resolver.resolveInfo(
                entryPoint = entryPoint,
                isInMultiWindowMode = isInMultiWindowMode,
                isKeyguardLocked = keyguardManager.isKeyguardLocked,
                isKeyguardLocked = isKeyguardLocked,
            )
                ?: return

+94 −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.devicepolicy

import android.app.admin.DevicePolicyManager
import android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_FACE
import android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_FEATURES_ALL
import android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_FEATURES_NONE
import android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_SECURE_CAMERA
import android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_SHORTCUTS_ALL
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.settings.UserTracker
import com.android.systemui.util.mockito.eq
import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
import org.mockito.ArgumentMatchers.anyInt
import org.mockito.Mock
import org.mockito.MockitoAnnotations

@SmallTest
@RunWith(JUnit4::class)
class DevicePolicyManagerExtTest : SysuiTestCase() {

    @Mock lateinit var devicePolicyManager: DevicePolicyManager
    @Mock private lateinit var userTracker: UserTracker

    @Before
    fun setUp() {
        MockitoAnnotations.initMocks(this)

        whenever(userTracker.userId).thenReturn(CURRENT_USER_ID)
    }

    // region areKeyguardShortcutsDisabled
    @Test
    fun areKeyguardShortcutsDisabled_noDisabledKeyguardFeature_shouldReturnFalse() {
        whenever(devicePolicyManager.getKeyguardDisabledFeatures(eq(null), anyInt()))
            .thenReturn(KEYGUARD_DISABLE_FEATURES_NONE)

        assertThat(devicePolicyManager.areKeyguardShortcutsDisabled(userId = CURRENT_USER_ID))
            .isFalse()
    }

    @Test
    fun areKeyguardShortcutsDisabled_otherDisabledKeyguardFeatures_shouldReturnFalse() {
        whenever(devicePolicyManager.getKeyguardDisabledFeatures(eq(null), anyInt()))
            .thenReturn(KEYGUARD_DISABLE_SECURE_CAMERA or KEYGUARD_DISABLE_FACE)

        assertThat(devicePolicyManager.areKeyguardShortcutsDisabled(userId = CURRENT_USER_ID))
            .isFalse()
    }

    @Test
    fun areKeyguardShortcutsDisabled_disabledShortcutsKeyguardFeature_shouldReturnTrue() {
        whenever(devicePolicyManager.getKeyguardDisabledFeatures(eq(null), anyInt()))
            .thenReturn(KEYGUARD_DISABLE_SHORTCUTS_ALL)

        assertThat(devicePolicyManager.areKeyguardShortcutsDisabled(userId = CURRENT_USER_ID))
            .isTrue()
    }

    @Test
    fun areKeyguardShortcutsDisabled_disabledAllKeyguardFeatures_shouldReturnTrue() {
        whenever(devicePolicyManager.getKeyguardDisabledFeatures(eq(null), anyInt()))
            .thenReturn(KEYGUARD_DISABLE_FEATURES_ALL)

        assertThat(devicePolicyManager.areKeyguardShortcutsDisabled(userId = CURRENT_USER_ID))
            .isTrue()
    }
    // endregion

    private companion object {
        const val CURRENT_USER_ID = 123
    }
}
+111 −1
Original line number Diff line number Diff line
@@ -16,16 +16,18 @@
package com.android.systemui.notetask

import android.app.KeyguardManager
import android.app.admin.DevicePolicyManager
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.os.UserManager
import android.test.suitebuilder.annotation.SmallTest
import androidx.test.filters.SmallTest
import androidx.test.runner.AndroidJUnit4
import com.android.systemui.SysuiTestCase
import com.android.systemui.notetask.NoteTaskController.Companion.INTENT_EXTRA_USE_STYLUS_MODE
import com.android.systemui.notetask.shortcut.CreateNoteTaskShortcutActivity
import com.android.systemui.settings.UserTracker
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.argumentCaptor
import com.android.systemui.util.mockito.capture
@@ -38,6 +40,7 @@ import java.util.Optional
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentMatchers.anyInt
import org.mockito.Mock
import org.mockito.Mockito.verify
import org.mockito.Mockito.verifyZeroInteractions
@@ -55,6 +58,8 @@ internal class NoteTaskControllerTest : SysuiTestCase() {
    @Mock lateinit var keyguardManager: KeyguardManager
    @Mock lateinit var userManager: UserManager
    @Mock lateinit var eventLogger: NoteTaskEventLogger
    @Mock private lateinit var userTracker: UserTracker
    @Mock private lateinit var devicePolicyManager: DevicePolicyManager

    private val noteTaskInfo = NoteTaskInfo(packageName = NOTES_PACKAGE_NAME, uid = NOTES_UID)

@@ -65,6 +70,13 @@ internal class NoteTaskControllerTest : SysuiTestCase() {
        whenever(context.packageManager).thenReturn(packageManager)
        whenever(resolver.resolveInfo(any(), any(), any())).thenReturn(noteTaskInfo)
        whenever(userManager.isUserUnlocked).thenReturn(true)
        whenever(
                devicePolicyManager.getKeyguardDisabledFeatures(
                    /* admin= */ eq(null),
                    /* userHandle= */ anyInt()
                )
            )
            .thenReturn(DevicePolicyManager.KEYGUARD_DISABLE_FEATURES_NONE)
    }

    private fun createNoteTaskController(
@@ -81,6 +93,8 @@ internal class NoteTaskControllerTest : SysuiTestCase() {
            optionalUserManager = Optional.ofNullable(userManager),
            optionalKeyguardManager = Optional.ofNullable(keyguardManager),
            isEnabled = isEnabled,
            devicePolicyManager = devicePolicyManager,
            userTracker = userTracker,
        )

    // region onBubbleExpandChanged
@@ -384,6 +398,102 @@ internal class NoteTaskControllerTest : SysuiTestCase() {
    }
    // endregion

    // region keyguard policy
    @Test
    fun showNoteTask_keyguardLocked_keyguardDisableShortcutsAll_shouldDoNothing() {
        whenever(keyguardManager.isKeyguardLocked).thenReturn(true)
        whenever(
                devicePolicyManager.getKeyguardDisabledFeatures(
                    /* admin= */ eq(null),
                    /* userHandle= */ anyInt()
                )
            )
            .thenReturn(DevicePolicyManager.KEYGUARD_DISABLE_SHORTCUTS_ALL)

        createNoteTaskController()
            .showNoteTask(
                isInMultiWindowMode = false,
                entryPoint = NoteTaskEntryPoint.QUICK_AFFORDANCE
            )

        verifyZeroInteractions(context, bubbles, eventLogger)
    }

    @Test
    fun showNoteTask_keyguardLocked_keyguardDisableFeaturesAll_shouldDoNothing() {
        whenever(keyguardManager.isKeyguardLocked).thenReturn(true)
        whenever(
                devicePolicyManager.getKeyguardDisabledFeatures(
                    /* admin= */ eq(null),
                    /* userHandle= */ anyInt()
                )
            )
            .thenReturn(DevicePolicyManager.KEYGUARD_DISABLE_FEATURES_ALL)

        createNoteTaskController()
            .showNoteTask(
                isInMultiWindowMode = false,
                entryPoint = NoteTaskEntryPoint.QUICK_AFFORDANCE
            )

        verifyZeroInteractions(context, bubbles, eventLogger)
    }

    @Test
    fun showNoteTask_keyguardUnlocked_keyguardDisableShortcutsAll_shouldStartBubble() {
        whenever(keyguardManager.isKeyguardLocked).thenReturn(false)
        whenever(
                devicePolicyManager.getKeyguardDisabledFeatures(
                    /* admin= */ eq(null),
                    /* userHandle= */ anyInt()
                )
            )
            .thenReturn(DevicePolicyManager.KEYGUARD_DISABLE_SHORTCUTS_ALL)

        createNoteTaskController()
            .showNoteTask(
                isInMultiWindowMode = false,
                entryPoint = NoteTaskEntryPoint.QUICK_AFFORDANCE
            )

        val intentCaptor = argumentCaptor<Intent>()
        verify(bubbles).showOrHideAppBubble(capture(intentCaptor))
        intentCaptor.value.let { intent ->
            assertThat(intent.action).isEqualTo(NoteTaskController.ACTION_CREATE_NOTE)
            assertThat(intent.`package`).isEqualTo(NOTES_PACKAGE_NAME)
            assertThat(intent.flags).isEqualTo(Intent.FLAG_ACTIVITY_NEW_TASK)
            assertThat(intent.getBooleanExtra(INTENT_EXTRA_USE_STYLUS_MODE, false)).isTrue()
        }
    }

    @Test
    fun showNoteTask_keyguardUnlocked_keyguardDisableFeaturesAll_shouldStartBubble() {
        whenever(keyguardManager.isKeyguardLocked).thenReturn(false)
        whenever(
                devicePolicyManager.getKeyguardDisabledFeatures(
                    /* admin= */ eq(null),
                    /* userHandle= */ anyInt()
                )
            )
            .thenReturn(DevicePolicyManager.KEYGUARD_DISABLE_FEATURES_ALL)

        createNoteTaskController()
            .showNoteTask(
                isInMultiWindowMode = false,
                entryPoint = NoteTaskEntryPoint.QUICK_AFFORDANCE
            )

        val intentCaptor = argumentCaptor<Intent>()
        verify(bubbles).showOrHideAppBubble(capture(intentCaptor))
        intentCaptor.value.let { intent ->
            assertThat(intent.action).isEqualTo(NoteTaskController.ACTION_CREATE_NOTE)
            assertThat(intent.`package`).isEqualTo(NOTES_PACKAGE_NAME)
            assertThat(intent.flags).isEqualTo(Intent.FLAG_ACTIVITY_NEW_TASK)
            assertThat(intent.getBooleanExtra(INTENT_EXTRA_USE_STYLUS_MODE, false)).isTrue()
        }
    }
    // endregion

    private companion object {
        const val NOTES_PACKAGE_NAME = "com.android.note.app"
        const val NOTES_UID = 123456