Hide notes app lock screen shortcut when there is no default notes app set
Test: atest SystemUITests:NoteTaskControllerTest atest SystemUITests:NoteTaskQuickAffordanceConfigTest atest SystemUITests:LaunchNotesRoleSettingsTrampolineActivityTest Bug: 266686199 Change-Id: I911f1f0283a4d3a3c136424df51efe473341ace4
This commit is contained in:
@@ -992,6 +992,18 @@
|
||||
android:excludeFromRecents="true"
|
||||
android:resizeableActivity="false"
|
||||
android:theme="@android:style/Theme.NoDisplay" />
|
||||
|
||||
<activity
|
||||
android:name=".notetask.LaunchNotesRoleSettingsTrampolineActivity"
|
||||
android:exported="true"
|
||||
android:excludeFromRecents="true"
|
||||
android:resizeableActivity="false"
|
||||
android:theme="@android:style/Theme.NoDisplay" >
|
||||
<intent-filter>
|
||||
<action android:name="com.android.systemui.action.MANAGE_NOTES_ROLE_FROM_QUICK_AFFORDANCE" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<!-- endregion -->
|
||||
|
||||
<!-- started from ControlsRequestReceiver -->
|
||||
|
||||
@@ -3035,6 +3035,19 @@
|
||||
-->
|
||||
<string name="keyguard_affordance_enablement_dialog_home_instruction_2">• At least one device is available</string>
|
||||
|
||||
<!---
|
||||
Requirement for the notes app to be available for the user to use. This is shown as part of a
|
||||
bulleted list of requirements. When all requirements are met, the app can be accessed through a
|
||||
shortcut button on the lock screen. [CHAR LIMIT=NONE] -->
|
||||
<string name="keyguard_affordance_enablement_dialog_notes_app_instruction">Select a default notes app to use notetaking shortcut</string>
|
||||
|
||||
<!---
|
||||
The action to make the lock screen shortcut for the notes app to be available for the user to
|
||||
use. This is shown as the action button in the dialog listing the requirements. When all
|
||||
requirements are met, the app can be accessed through a shortcut button on the lock screen.
|
||||
[CHAR LIMIT=NONE] -->
|
||||
<string name="keyguard_affordance_enablement_dialog_notes_app_action">Open settings</string>
|
||||
|
||||
<!--
|
||||
Error message shown when a shortcut must be pressed and held to activate it, usually shown when
|
||||
the user tried to tap the shortcut or held it for too short a time. [CHAR LIMIT=32].
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* 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.notetask
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.activity.ComponentActivity
|
||||
import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceConfig
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
* An internal proxy activity that starts the notes role setting.
|
||||
*
|
||||
* This activity is introduced mainly for the error handling of the notes app lock screen shortcut
|
||||
* picker, which only supports package + action but not extras. See
|
||||
* [KeyguardQuickAffordanceConfig.PickerScreenState.Disabled.actionComponentName].
|
||||
*/
|
||||
class LaunchNotesRoleSettingsTrampolineActivity
|
||||
@Inject
|
||||
constructor(
|
||||
private val controller: NoteTaskController,
|
||||
) : ComponentActivity() {
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
val entryPoint =
|
||||
if (intent?.action == ACTION_MANAGE_NOTES_ROLE_FROM_QUICK_AFFORDANCE) {
|
||||
NoteTaskEntryPoint.QUICK_AFFORDANCE
|
||||
} else {
|
||||
null
|
||||
}
|
||||
controller.startNotesRoleSetting(this, entryPoint)
|
||||
finish()
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val ACTION_MANAGE_NOTES_ROLE_FROM_QUICK_AFFORDANCE =
|
||||
"com.android.systemui.action.MANAGE_NOTES_ROLE_FROM_QUICK_AFFORDANCE"
|
||||
}
|
||||
}
|
||||
@@ -112,6 +112,43 @@ constructor(
|
||||
)
|
||||
}
|
||||
|
||||
/** Starts the notes role setting. */
|
||||
fun startNotesRoleSetting(activityContext: Context, entryPoint: NoteTaskEntryPoint?) {
|
||||
val user =
|
||||
if (entryPoint == null) {
|
||||
userTracker.userHandle
|
||||
} else {
|
||||
getUserForHandlingNotesTaking(entryPoint)
|
||||
}
|
||||
activityContext.startActivityAsUser(
|
||||
Intent(Intent.ACTION_MANAGE_DEFAULT_APP).apply {
|
||||
putExtra(Intent.EXTRA_ROLE_NAME, ROLE_NOTES)
|
||||
},
|
||||
user
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the [UserHandle] of an android user that should handle the notes taking [entryPoint].
|
||||
*
|
||||
* On company owned personally enabled (COPE) devices, if the given [entryPoint] is in the
|
||||
* [FORCE_WORK_NOTE_APPS_ENTRY_POINTS_ON_COPE_DEVICES] list, the default notes app in the work
|
||||
* profile user will always be launched.
|
||||
*
|
||||
* On non managed devices or devices with other management modes, the current [UserHandle] is
|
||||
* returned.
|
||||
*/
|
||||
fun getUserForHandlingNotesTaking(entryPoint: NoteTaskEntryPoint): UserHandle =
|
||||
if (
|
||||
entryPoint in FORCE_WORK_NOTE_APPS_ENTRY_POINTS_ON_COPE_DEVICES &&
|
||||
devicePolicyManager.isOrganizationOwnedDeviceWithManagedProfile
|
||||
) {
|
||||
userTracker.userProfiles.firstOrNull { userManager.isManagedProfile(it.id) }?.userHandle
|
||||
?: userTracker.userHandle
|
||||
} else {
|
||||
userTracker.userHandle
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows a note task. How the task is shown will depend on when the method is invoked.
|
||||
*
|
||||
@@ -122,30 +159,13 @@ constructor(
|
||||
* bubble is already opened.
|
||||
*
|
||||
* That will let users open other apps in full screen, and take contextual notes.
|
||||
*
|
||||
* On company owned personally enabled (COPE) devices, if the given [entryPoint] is in the
|
||||
* [FORCE_WORK_NOTE_APPS_ENTRY_POINTS_ON_COPE_DEVICES] list, the default notes app in the work
|
||||
* profile user will always be launched.
|
||||
*/
|
||||
fun showNoteTask(
|
||||
entryPoint: NoteTaskEntryPoint,
|
||||
) {
|
||||
if (!isEnabled) return
|
||||
|
||||
val user: UserHandle =
|
||||
if (
|
||||
entryPoint in FORCE_WORK_NOTE_APPS_ENTRY_POINTS_ON_COPE_DEVICES &&
|
||||
devicePolicyManager.isOrganizationOwnedDeviceWithManagedProfile
|
||||
) {
|
||||
userTracker.userProfiles
|
||||
.firstOrNull { userManager.isManagedProfile(it.id) }
|
||||
?.userHandle
|
||||
?: userTracker.userHandle
|
||||
} else {
|
||||
userTracker.userHandle
|
||||
}
|
||||
|
||||
showNoteTaskAsUser(entryPoint, user)
|
||||
showNoteTaskAsUser(entryPoint, getUserForHandlingNotesTaking(entryPoint))
|
||||
}
|
||||
|
||||
/** A variant of [showNoteTask] which launches note task in the given [user]. */
|
||||
|
||||
@@ -45,6 +45,10 @@ interface NoteTaskModule {
|
||||
@[Binds IntoMap ClassKey(LaunchNoteTaskManagedProfileProxyActivity::class)]
|
||||
fun LaunchNoteTaskManagedProfileProxyActivity.bindNoteTaskLauncherProxyActivity(): Activity
|
||||
|
||||
@[Binds IntoMap ClassKey(LaunchNotesRoleSettingsTrampolineActivity::class)]
|
||||
fun LaunchNotesRoleSettingsTrampolineActivity.bindLaunchNotesRoleSettingsTrampolineActivity():
|
||||
Activity
|
||||
|
||||
companion object {
|
||||
|
||||
@[Provides NoteTaskEnabledKey]
|
||||
|
||||
@@ -16,9 +16,12 @@
|
||||
|
||||
package com.android.systemui.notetask.quickaffordance
|
||||
|
||||
import android.app.role.OnRoleHoldersChangedListener
|
||||
import android.app.role.RoleManager
|
||||
import android.content.Context
|
||||
import android.hardware.input.InputSettings
|
||||
import android.os.Build
|
||||
import android.os.UserHandle
|
||||
import android.os.UserManager
|
||||
import android.util.Log
|
||||
import com.android.keyguard.KeyguardUpdateMonitor
|
||||
@@ -27,17 +30,22 @@ import com.android.systemui.R
|
||||
import com.android.systemui.animation.Expandable
|
||||
import com.android.systemui.common.shared.model.ContentDescription
|
||||
import com.android.systemui.common.shared.model.Icon
|
||||
import com.android.systemui.dagger.qualifiers.Background
|
||||
import com.android.systemui.keyguard.data.quickaffordance.BuiltInKeyguardQuickAffordanceKeys
|
||||
import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceConfig
|
||||
import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceConfig.LockScreenState
|
||||
import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceConfig.OnTriggeredResult
|
||||
import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceConfig.PickerScreenState
|
||||
import com.android.systemui.keyguard.data.repository.KeyguardQuickAffordanceRepository
|
||||
import com.android.systemui.notetask.LaunchNotesRoleSettingsTrampolineActivity.Companion.ACTION_MANAGE_NOTES_ROLE_FROM_QUICK_AFFORDANCE
|
||||
import com.android.systemui.notetask.NoteTaskController
|
||||
import com.android.systemui.notetask.NoteTaskEnabledKey
|
||||
import com.android.systemui.notetask.NoteTaskEntryPoint
|
||||
import com.android.systemui.notetask.NoteTaskEntryPoint.QUICK_AFFORDANCE
|
||||
import com.android.systemui.notetask.NoteTaskInfoResolver
|
||||
import com.android.systemui.shared.customization.data.content.CustomizationProviderContract.LockScreenQuickAffordances.AffordanceTable.COMPONENT_NAME_SEPARATOR
|
||||
import com.android.systemui.stylus.StylusManager
|
||||
import dagger.Lazy
|
||||
import java.util.concurrent.Executor
|
||||
import javax.inject.Inject
|
||||
import kotlinx.coroutines.channels.awaitClose
|
||||
import kotlinx.coroutines.channels.trySendBlocking
|
||||
@@ -49,13 +57,16 @@ import kotlinx.coroutines.flow.onEach
|
||||
class NoteTaskQuickAffordanceConfig
|
||||
@Inject
|
||||
constructor(
|
||||
context: Context,
|
||||
private val context: Context,
|
||||
private val controller: NoteTaskController,
|
||||
private val noteTaskInfoResolver: NoteTaskInfoResolver,
|
||||
private val stylusManager: StylusManager,
|
||||
private val roleManager: RoleManager,
|
||||
private val keyguardMonitor: KeyguardUpdateMonitor,
|
||||
private val userManager: UserManager,
|
||||
private val lazyRepository: Lazy<KeyguardQuickAffordanceRepository>,
|
||||
@NoteTaskEnabledKey private val isEnabled: Boolean,
|
||||
@Background private val backgroundExecutor: Executor,
|
||||
) : KeyguardQuickAffordanceConfig {
|
||||
|
||||
override val key = BuiltInKeyguardQuickAffordanceKeys.CREATE_NOTE
|
||||
@@ -73,15 +84,24 @@ constructor(
|
||||
val configSelectedFlow = repository.createConfigSelectedFlow(key)
|
||||
val stylusEverUsedFlow = stylusManager.createStylusEverUsedFlow(context)
|
||||
val userUnlockedFlow = userManager.createUserUnlockedFlow(keyguardMonitor)
|
||||
combine(userUnlockedFlow, stylusEverUsedFlow, configSelectedFlow) {
|
||||
val defaultNotesAppFlow =
|
||||
roleManager.createNotesRoleFlow(backgroundExecutor, controller, noteTaskInfoResolver)
|
||||
combine(userUnlockedFlow, stylusEverUsedFlow, configSelectedFlow, defaultNotesAppFlow) {
|
||||
isUserUnlocked,
|
||||
isStylusEverUsed,
|
||||
isConfigSelected ->
|
||||
isConfigSelected,
|
||||
isDefaultNotesAppSet ->
|
||||
logDebug { "lockScreenState:isUserUnlocked=$isUserUnlocked" }
|
||||
logDebug { "lockScreenState:isStylusEverUsed=$isStylusEverUsed" }
|
||||
logDebug { "lockScreenState:isConfigSelected=$isConfigSelected" }
|
||||
logDebug { "lockScreenState:isDefaultNotesAppSet=$isDefaultNotesAppSet" }
|
||||
|
||||
if (isEnabled && isUserUnlocked && (isConfigSelected || isStylusEverUsed)) {
|
||||
if (
|
||||
isEnabled &&
|
||||
isUserUnlocked &&
|
||||
isDefaultNotesAppSet &&
|
||||
(isConfigSelected || isStylusEverUsed)
|
||||
) {
|
||||
val contentDescription = ContentDescription.Resource(pickerNameResourceId)
|
||||
val icon = Icon.Resource(pickerIconResourceId, contentDescription)
|
||||
LockScreenState.Visible(icon)
|
||||
@@ -92,15 +112,34 @@ constructor(
|
||||
.onEach { state -> logDebug { "lockScreenState=$state" } }
|
||||
}
|
||||
|
||||
override suspend fun getPickerScreenState() =
|
||||
if (isEnabled) {
|
||||
PickerScreenState.Default()
|
||||
} else {
|
||||
PickerScreenState.UnavailableOnDevice
|
||||
override suspend fun getPickerScreenState(): PickerScreenState {
|
||||
val isDefaultNotesAppSet =
|
||||
noteTaskInfoResolver.resolveInfo(
|
||||
QUICK_AFFORDANCE,
|
||||
user = controller.getUserForHandlingNotesTaking(QUICK_AFFORDANCE)
|
||||
) != null
|
||||
return when {
|
||||
isEnabled && isDefaultNotesAppSet -> PickerScreenState.Default()
|
||||
isEnabled -> {
|
||||
PickerScreenState.Disabled(
|
||||
listOf(
|
||||
context.getString(
|
||||
R.string.keyguard_affordance_enablement_dialog_notes_app_instruction
|
||||
)
|
||||
),
|
||||
context.getString(
|
||||
R.string.keyguard_affordance_enablement_dialog_notes_app_action
|
||||
),
|
||||
"${context.packageName}$COMPONENT_NAME_SEPARATOR" +
|
||||
"$ACTION_MANAGE_NOTES_ROLE_FROM_QUICK_AFFORDANCE",
|
||||
)
|
||||
}
|
||||
else -> PickerScreenState.UnavailableOnDevice
|
||||
}
|
||||
}
|
||||
|
||||
override fun onTriggered(expandable: Expandable?): OnTriggeredResult {
|
||||
controller.showNoteTask(entryPoint = NoteTaskEntryPoint.QUICK_AFFORDANCE)
|
||||
controller.showNoteTask(entryPoint = QUICK_AFFORDANCE)
|
||||
return OnTriggeredResult.Handled
|
||||
}
|
||||
}
|
||||
@@ -129,6 +168,27 @@ private fun StylusManager.createStylusEverUsedFlow(context: Context) = callbackF
|
||||
awaitClose { unregisterCallback(callback) }
|
||||
}
|
||||
|
||||
private fun RoleManager.createNotesRoleFlow(
|
||||
executor: Executor,
|
||||
noteTaskController: NoteTaskController,
|
||||
noteTaskInfoResolver: NoteTaskInfoResolver,
|
||||
) = callbackFlow {
|
||||
fun isDefaultNotesAppSetForUser() =
|
||||
noteTaskInfoResolver.resolveInfo(
|
||||
QUICK_AFFORDANCE,
|
||||
user = noteTaskController.getUserForHandlingNotesTaking(QUICK_AFFORDANCE)
|
||||
) != null
|
||||
|
||||
trySendBlocking(isDefaultNotesAppSetForUser())
|
||||
val callback = OnRoleHoldersChangedListener { roleName, _ ->
|
||||
if (roleName == RoleManager.ROLE_NOTES) {
|
||||
trySendBlocking(isDefaultNotesAppSetForUser())
|
||||
}
|
||||
}
|
||||
addOnRoleHoldersChangedListenerAsUser(executor, callback, UserHandle.ALL)
|
||||
awaitClose { removeOnRoleHoldersChangedListenerAsUser(callback, UserHandle.ALL) }
|
||||
}
|
||||
|
||||
private fun KeyguardQuickAffordanceRepository.createConfigSelectedFlow(key: String) =
|
||||
selections.map { selected ->
|
||||
selected.values.flatten().any { selectedConfig -> selectedConfig.key == key }
|
||||
|
||||
@@ -196,6 +196,17 @@
|
||||
android:exported="false"
|
||||
android:permission="com.android.systemui.permission.SELF"
|
||||
android:excludeFromRecents="true" />
|
||||
|
||||
<activity
|
||||
android:name="com.android.systemui.notetask.LaunchNotesRoleSettingsTrampolineActivity"
|
||||
android:exported="false"
|
||||
android:permission="com.android.systemui.permission.SELF"
|
||||
android:excludeFromRecents="true" >
|
||||
<intent-filter>
|
||||
<action android:name="com.android.systemui.action.MANAGE_NOTES_ROLE_FROM_QUICK_AFFORDANCE" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
|
||||
<instrumentation android:name="android.testing.TestableInstrumentation"
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* 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.notetask
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.testing.AndroidTestingRunner
|
||||
import android.testing.TestableLooper
|
||||
import androidx.test.filters.SmallTest
|
||||
import androidx.test.rule.ActivityTestRule
|
||||
import androidx.test.runner.intercepting.SingleActivityFactory
|
||||
import com.android.dx.mockito.inline.extended.ExtendedMockito.verify
|
||||
import com.android.systemui.SysuiTestCase
|
||||
import com.android.systemui.notetask.LaunchNotesRoleSettingsTrampolineActivity.Companion.ACTION_MANAGE_NOTES_ROLE_FROM_QUICK_AFFORDANCE
|
||||
import com.android.systemui.notetask.NoteTaskEntryPoint.QUICK_AFFORDANCE
|
||||
import com.android.systemui.util.mockito.any
|
||||
import com.android.systemui.util.mockito.eq
|
||||
import org.junit.After
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mockito.Mock
|
||||
import org.mockito.MockitoAnnotations
|
||||
|
||||
@RunWith(AndroidTestingRunner::class)
|
||||
@SmallTest
|
||||
@TestableLooper.RunWithLooper
|
||||
class LaunchNotesRoleSettingsTrampolineActivityTest : SysuiTestCase() {
|
||||
|
||||
@Mock lateinit var noteTaskController: NoteTaskController
|
||||
|
||||
@Rule
|
||||
@JvmField
|
||||
val activityRule =
|
||||
ActivityTestRule<LaunchNotesRoleSettingsTrampolineActivity>(
|
||||
/* activityFactory= */ object :
|
||||
SingleActivityFactory<LaunchNotesRoleSettingsTrampolineActivity>(
|
||||
LaunchNotesRoleSettingsTrampolineActivity::class.java
|
||||
) {
|
||||
override fun create(intent: Intent?) =
|
||||
LaunchNotesRoleSettingsTrampolineActivity(noteTaskController)
|
||||
},
|
||||
/* initialTouchMode= */ false,
|
||||
/* launchActivity= */ false,
|
||||
)
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
MockitoAnnotations.initMocks(this)
|
||||
}
|
||||
|
||||
@After
|
||||
fun tearDown() {
|
||||
activityRule.finishActivity()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun startActivity_noAction_shouldLaunchNotesRoleSettingTaskWithNullEntryPoint() {
|
||||
activityRule.launchActivity(/* startIntent= */ null)
|
||||
|
||||
verify(noteTaskController).startNotesRoleSetting(any(Context::class.java), eq(null))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun startActivity_quickAffordanceAction_shouldLaunchNotesRoleSettingTaskWithQuickAffordanceEntryPoint() { // ktlint-disable max-line-length
|
||||
activityRule.launchActivity(Intent(ACTION_MANAGE_NOTES_ROLE_FROM_QUICK_AFFORDANCE))
|
||||
|
||||
verify(noteTaskController)
|
||||
.startNotesRoleSetting(any(Context::class.java), eq(QUICK_AFFORDANCE))
|
||||
}
|
||||
}
|
||||
@@ -47,6 +47,9 @@ import com.android.systemui.SysuiTestCase
|
||||
import com.android.systemui.notetask.NoteTaskController.Companion.EXTRA_SHORTCUT_BADGE_OVERRIDE_PACKAGE
|
||||
import com.android.systemui.notetask.NoteTaskController.Companion.SETTINGS_CREATE_NOTE_TASK_SHORTCUT_COMPONENT
|
||||
import com.android.systemui.notetask.NoteTaskController.Companion.SHORTCUT_ID
|
||||
import com.android.systemui.notetask.NoteTaskEntryPoint.APP_CLIPS
|
||||
import com.android.systemui.notetask.NoteTaskEntryPoint.QUICK_AFFORDANCE
|
||||
import com.android.systemui.notetask.NoteTaskEntryPoint.TAIL_BUTTON
|
||||
import com.android.systemui.notetask.shortcut.LaunchNoteTaskActivity
|
||||
import com.android.systemui.notetask.shortcut.LaunchNoteTaskManagedProfileProxyActivity
|
||||
import com.android.systemui.settings.FakeUserTracker
|
||||
@@ -493,7 +496,7 @@ internal class NoteTaskControllerTest : SysuiTestCase() {
|
||||
)
|
||||
.thenReturn(DevicePolicyManager.KEYGUARD_DISABLE_SHORTCUTS_ALL)
|
||||
|
||||
createNoteTaskController().showNoteTask(entryPoint = NoteTaskEntryPoint.QUICK_AFFORDANCE)
|
||||
createNoteTaskController().showNoteTask(entryPoint = QUICK_AFFORDANCE)
|
||||
|
||||
verifyZeroInteractions(context, bubbles, eventLogger)
|
||||
}
|
||||
@@ -509,7 +512,7 @@ internal class NoteTaskControllerTest : SysuiTestCase() {
|
||||
)
|
||||
.thenReturn(DevicePolicyManager.KEYGUARD_DISABLE_FEATURES_ALL)
|
||||
|
||||
createNoteTaskController().showNoteTask(entryPoint = NoteTaskEntryPoint.QUICK_AFFORDANCE)
|
||||
createNoteTaskController().showNoteTask(entryPoint = QUICK_AFFORDANCE)
|
||||
|
||||
verifyZeroInteractions(context, bubbles, eventLogger)
|
||||
}
|
||||
@@ -525,7 +528,7 @@ internal class NoteTaskControllerTest : SysuiTestCase() {
|
||||
)
|
||||
.thenReturn(DevicePolicyManager.KEYGUARD_DISABLE_SHORTCUTS_ALL)
|
||||
|
||||
createNoteTaskController().showNoteTask(entryPoint = NoteTaskEntryPoint.QUICK_AFFORDANCE)
|
||||
createNoteTaskController().showNoteTask(entryPoint = QUICK_AFFORDANCE)
|
||||
|
||||
verifyNoteTaskOpenInBubbleInUser(userTracker.userHandle)
|
||||
}
|
||||
@@ -541,7 +544,7 @@ internal class NoteTaskControllerTest : SysuiTestCase() {
|
||||
)
|
||||
.thenReturn(DevicePolicyManager.KEYGUARD_DISABLE_FEATURES_ALL)
|
||||
|
||||
createNoteTaskController().showNoteTask(entryPoint = NoteTaskEntryPoint.QUICK_AFFORDANCE)
|
||||
createNoteTaskController().showNoteTask(entryPoint = QUICK_AFFORDANCE)
|
||||
|
||||
verifyNoteTaskOpenInBubbleInUser(userTracker.userHandle)
|
||||
}
|
||||
@@ -553,7 +556,7 @@ internal class NoteTaskControllerTest : SysuiTestCase() {
|
||||
whenever(devicePolicyManager.isOrganizationOwnedDeviceWithManagedProfile).thenReturn(true)
|
||||
userTracker.set(listOf(mainUserInfo), mainAndWorkProfileUsers.indexOf(mainUserInfo))
|
||||
|
||||
createNoteTaskController().showNoteTask(entryPoint = NoteTaskEntryPoint.QUICK_AFFORDANCE)
|
||||
createNoteTaskController().showNoteTask(entryPoint = QUICK_AFFORDANCE)
|
||||
|
||||
verifyNoteTaskOpenInBubbleInUser(mainUserInfo.userHandle)
|
||||
}
|
||||
@@ -563,7 +566,7 @@ internal class NoteTaskControllerTest : SysuiTestCase() {
|
||||
whenever(devicePolicyManager.isOrganizationOwnedDeviceWithManagedProfile).thenReturn(true)
|
||||
userTracker.set(mainAndWorkProfileUsers, mainAndWorkProfileUsers.indexOf(mainUserInfo))
|
||||
|
||||
createNoteTaskController().showNoteTask(entryPoint = NoteTaskEntryPoint.QUICK_AFFORDANCE)
|
||||
createNoteTaskController().showNoteTask(entryPoint = QUICK_AFFORDANCE)
|
||||
|
||||
verifyNoteTaskOpenInBubbleInUser(workUserInfo.userHandle)
|
||||
}
|
||||
@@ -734,6 +737,129 @@ internal class NoteTaskControllerTest : SysuiTestCase() {
|
||||
}
|
||||
// endregion
|
||||
|
||||
// region getUserForHandlingNotesTaking
|
||||
@Test
|
||||
fun getUserForHandlingNotesTaking_cope_quickAffordance_shouldReturnWorkProfileUser() {
|
||||
whenever(devicePolicyManager.isOrganizationOwnedDeviceWithManagedProfile).thenReturn(true)
|
||||
userTracker.set(mainAndWorkProfileUsers, mainAndWorkProfileUsers.indexOf(mainUserInfo))
|
||||
|
||||
val user = createNoteTaskController().getUserForHandlingNotesTaking(QUICK_AFFORDANCE)
|
||||
|
||||
assertThat(user).isEqualTo(UserHandle.of(workUserInfo.id))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun getUserForHandlingNotesTaking_cope_tailButton_shouldReturnWorkProfileUser() {
|
||||
whenever(devicePolicyManager.isOrganizationOwnedDeviceWithManagedProfile).thenReturn(true)
|
||||
userTracker.set(mainAndWorkProfileUsers, mainAndWorkProfileUsers.indexOf(mainUserInfo))
|
||||
|
||||
val user = createNoteTaskController().getUserForHandlingNotesTaking(TAIL_BUTTON)
|
||||
|
||||
assertThat(user).isEqualTo(UserHandle.of(workUserInfo.id))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun getUserForHandlingNotesTaking_cope_appClip_shouldReturnCurrentUser() {
|
||||
whenever(devicePolicyManager.isOrganizationOwnedDeviceWithManagedProfile).thenReturn(true)
|
||||
userTracker.set(mainAndWorkProfileUsers, mainAndWorkProfileUsers.indexOf(mainUserInfo))
|
||||
|
||||
val user = createNoteTaskController().getUserForHandlingNotesTaking(APP_CLIPS)
|
||||
|
||||
assertThat(user).isEqualTo(UserHandle.of(mainUserInfo.id))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun getUserForHandlingNotesTaking_noManagement_quickAffordance_shouldReturnCurrentUser() {
|
||||
userTracker.set(mainAndWorkProfileUsers, mainAndWorkProfileUsers.indexOf(mainUserInfo))
|
||||
|
||||
val user = createNoteTaskController().getUserForHandlingNotesTaking(QUICK_AFFORDANCE)
|
||||
|
||||
assertThat(user).isEqualTo(UserHandle.of(mainUserInfo.id))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun getUserForHandlingNotesTaking_noManagement_tailButton_shouldReturnCurrentUser() {
|
||||
userTracker.set(mainAndWorkProfileUsers, mainAndWorkProfileUsers.indexOf(mainUserInfo))
|
||||
|
||||
val user = createNoteTaskController().getUserForHandlingNotesTaking(TAIL_BUTTON)
|
||||
|
||||
assertThat(user).isEqualTo(UserHandle.of(mainUserInfo.id))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun getUserForHandlingNotesTaking_noManagement_appClip_shouldReturnCurrentUser() {
|
||||
userTracker.set(mainAndWorkProfileUsers, mainAndWorkProfileUsers.indexOf(mainUserInfo))
|
||||
|
||||
val user = createNoteTaskController().getUserForHandlingNotesTaking(APP_CLIPS)
|
||||
|
||||
assertThat(user).isEqualTo(UserHandle.of(mainUserInfo.id))
|
||||
}
|
||||
// endregion
|
||||
|
||||
// startregion startNotesRoleSetting
|
||||
@Test
|
||||
fun startNotesRoleSetting_cope_quickAffordance_shouldStartNoteRoleIntentWithWorkProfileUser() {
|
||||
whenever(devicePolicyManager.isOrganizationOwnedDeviceWithManagedProfile).thenReturn(true)
|
||||
userTracker.set(mainAndWorkProfileUsers, mainAndWorkProfileUsers.indexOf(mainUserInfo))
|
||||
|
||||
createNoteTaskController().startNotesRoleSetting(context, QUICK_AFFORDANCE)
|
||||
|
||||
val intentCaptor = argumentCaptor<Intent>()
|
||||
val userCaptor = argumentCaptor<UserHandle>()
|
||||
verify(context).startActivityAsUser(capture(intentCaptor), capture(userCaptor))
|
||||
intentCaptor.value.let { intent ->
|
||||
assertThat(intent).hasAction(Intent.ACTION_MANAGE_DEFAULT_APP)
|
||||
}
|
||||
assertThat(userCaptor.value).isEqualTo(UserHandle.of(workUserInfo.id))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun startNotesRoleSetting_cope_nullEntryPoint_shouldStartNoteRoleIntentWithCurrentUser() {
|
||||
whenever(devicePolicyManager.isOrganizationOwnedDeviceWithManagedProfile).thenReturn(true)
|
||||
userTracker.set(mainAndWorkProfileUsers, mainAndWorkProfileUsers.indexOf(mainUserInfo))
|
||||
|
||||
createNoteTaskController().startNotesRoleSetting(context, entryPoint = null)
|
||||
|
||||
val intentCaptor = argumentCaptor<Intent>()
|
||||
val userCaptor = argumentCaptor<UserHandle>()
|
||||
verify(context).startActivityAsUser(capture(intentCaptor), capture(userCaptor))
|
||||
intentCaptor.value.let { intent ->
|
||||
assertThat(intent).hasAction(Intent.ACTION_MANAGE_DEFAULT_APP)
|
||||
}
|
||||
assertThat(userCaptor.value).isEqualTo(UserHandle.of(mainUserInfo.id))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun startNotesRoleSetting_noManagement_quickAffordance_shouldStartNoteRoleIntentWithCurrentUser() { // ktlint-disable max-line-length
|
||||
userTracker.set(mainAndWorkProfileUsers, mainAndWorkProfileUsers.indexOf(mainUserInfo))
|
||||
|
||||
createNoteTaskController().startNotesRoleSetting(context, QUICK_AFFORDANCE)
|
||||
|
||||
val intentCaptor = argumentCaptor<Intent>()
|
||||
val userCaptor = argumentCaptor<UserHandle>()
|
||||
verify(context).startActivityAsUser(capture(intentCaptor), capture(userCaptor))
|
||||
intentCaptor.value.let { intent ->
|
||||
assertThat(intent).hasAction(Intent.ACTION_MANAGE_DEFAULT_APP)
|
||||
}
|
||||
assertThat(userCaptor.value).isEqualTo(UserHandle.of(mainUserInfo.id))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun startNotesRoleSetting_noManagement_nullEntryPoint_shouldStartNoteRoleIntentWithCurrentUser() { // ktlint-disable max-line-length
|
||||
userTracker.set(mainAndWorkProfileUsers, mainAndWorkProfileUsers.indexOf(mainUserInfo))
|
||||
|
||||
createNoteTaskController().startNotesRoleSetting(context, entryPoint = null)
|
||||
|
||||
val intentCaptor = argumentCaptor<Intent>()
|
||||
val userCaptor = argumentCaptor<UserHandle>()
|
||||
verify(context).startActivityAsUser(capture(intentCaptor), capture(userCaptor))
|
||||
intentCaptor.value.let { intent ->
|
||||
assertThat(intent).hasAction(Intent.ACTION_MANAGE_DEFAULT_APP)
|
||||
}
|
||||
assertThat(userCaptor.value).isEqualTo(UserHandle.of(mainUserInfo.id))
|
||||
}
|
||||
// endregion
|
||||
|
||||
private companion object {
|
||||
const val NOTE_TASK_SHORT_LABEL = "Notetaking"
|
||||
const val NOTE_TASK_ACTIVITY_NAME = "NoteTaskActivity"
|
||||
|
||||
@@ -18,7 +18,12 @@
|
||||
|
||||
package com.android.systemui.notetask.quickaffordance
|
||||
|
||||
import android.app.role.RoleManager
|
||||
import android.content.pm.ApplicationInfo
|
||||
import android.content.pm.PackageManager
|
||||
import android.content.pm.PackageManager.ApplicationInfoFlags
|
||||
import android.hardware.input.InputSettings
|
||||
import android.os.UserHandle
|
||||
import android.os.UserManager
|
||||
import android.test.suitebuilder.annotation.SmallTest
|
||||
import android.testing.AndroidTestingRunner
|
||||
@@ -31,11 +36,18 @@ import com.android.systemui.coroutines.collectLastValue
|
||||
import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceConfig
|
||||
import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceConfig.LockScreenState
|
||||
import com.android.systemui.keyguard.data.repository.KeyguardQuickAffordanceRepository
|
||||
import com.android.systemui.notetask.LaunchNotesRoleSettingsTrampolineActivity.Companion.ACTION_MANAGE_NOTES_ROLE_FROM_QUICK_AFFORDANCE
|
||||
import com.android.systemui.notetask.NoteTaskController
|
||||
import com.android.systemui.notetask.NoteTaskEntryPoint
|
||||
import com.android.systemui.notetask.NoteTaskInfoResolver
|
||||
import com.android.systemui.shared.customization.data.content.CustomizationProviderContract.LockScreenQuickAffordances.AffordanceTable.COMPONENT_NAME_SEPARATOR
|
||||
import com.android.systemui.stylus.StylusManager
|
||||
import com.android.systemui.util.concurrency.FakeExecutor
|
||||
import com.android.systemui.util.mockito.any
|
||||
import com.android.systemui.util.mockito.eq
|
||||
import com.android.systemui.util.mockito.mock
|
||||
import com.android.systemui.util.mockito.whenever
|
||||
import com.android.systemui.util.time.FakeSystemClock
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
@@ -45,6 +57,7 @@ import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mockito.Mock
|
||||
import org.mockito.Mockito.anyString
|
||||
import org.mockito.Mockito.verify
|
||||
import org.mockito.MockitoSession
|
||||
import org.mockito.quality.Strictness
|
||||
@@ -58,6 +71,8 @@ internal class NoteTaskQuickAffordanceConfigTest : SysuiTestCase() {
|
||||
@Mock lateinit var stylusManager: StylusManager
|
||||
@Mock lateinit var repository: KeyguardQuickAffordanceRepository
|
||||
@Mock lateinit var userManager: UserManager
|
||||
@Mock lateinit var roleManager: RoleManager
|
||||
@Mock lateinit var packageManager: PackageManager
|
||||
|
||||
private lateinit var mockitoSession: MockitoSession
|
||||
|
||||
@@ -69,6 +84,23 @@ internal class NoteTaskQuickAffordanceConfigTest : SysuiTestCase() {
|
||||
.mockStatic(InputSettings::class.java)
|
||||
.strictness(Strictness.LENIENT)
|
||||
.startMocking()
|
||||
|
||||
whenever(
|
||||
packageManager.getApplicationInfoAsUser(
|
||||
anyString(),
|
||||
any(ApplicationInfoFlags::class.java),
|
||||
any(UserHandle::class.java)
|
||||
)
|
||||
)
|
||||
.thenReturn(ApplicationInfo())
|
||||
whenever(controller.getUserForHandlingNotesTaking(any())).thenReturn(UserHandle.SYSTEM)
|
||||
whenever(
|
||||
roleManager.getRoleHoldersAsUser(
|
||||
eq(RoleManager.ROLE_NOTES),
|
||||
any(UserHandle::class.java)
|
||||
)
|
||||
)
|
||||
.thenReturn(listOf("com.google.test.notes"))
|
||||
}
|
||||
|
||||
@After
|
||||
@@ -85,6 +117,9 @@ internal class NoteTaskQuickAffordanceConfigTest : SysuiTestCase() {
|
||||
keyguardMonitor = mock(),
|
||||
lazyRepository = { repository },
|
||||
isEnabled = isEnabled,
|
||||
backgroundExecutor = FakeExecutor(FakeSystemClock()),
|
||||
roleManager = roleManager,
|
||||
noteTaskInfoResolver = NoteTaskInfoResolver(roleManager, packageManager)
|
||||
)
|
||||
|
||||
private fun createLockScreenStateVisible(): LockScreenState =
|
||||
@@ -111,6 +146,27 @@ internal class NoteTaskQuickAffordanceConfigTest : SysuiTestCase() {
|
||||
assertThat(actual).isEqualTo(createLockScreenStateVisible())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun lockScreenState_stylusUsed_userUnlocked_isSelected_noDefaultNotesAppSet_shouldEmitHidden() =
|
||||
runTest {
|
||||
TestConfig()
|
||||
.setStylusEverUsed(true)
|
||||
.setUserUnlocked(true)
|
||||
.setConfigSelections(mock<NoteTaskQuickAffordanceConfig>())
|
||||
whenever(
|
||||
roleManager.getRoleHoldersAsUser(
|
||||
eq(RoleManager.ROLE_NOTES),
|
||||
any(UserHandle::class.java)
|
||||
)
|
||||
)
|
||||
.thenReturn(emptyList())
|
||||
|
||||
val underTest = createUnderTest()
|
||||
val actual by collectLastValue(underTest.lockScreenState)
|
||||
|
||||
assertThat(actual).isEqualTo(LockScreenState.Hidden)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun lockScreenState_stylusUnused_userUnlocked_isSelected_shouldEmitHidden() = runTest {
|
||||
TestConfig()
|
||||
@@ -217,6 +273,39 @@ internal class NoteTaskQuickAffordanceConfigTest : SysuiTestCase() {
|
||||
verify(controller).showNoteTask(entryPoint = NoteTaskEntryPoint.QUICK_AFFORDANCE)
|
||||
}
|
||||
|
||||
// region getPickerScreenState
|
||||
@Test
|
||||
fun getPickerScreenState_defaultNoteAppSet_shouldReturnDefault() = runTest {
|
||||
val underTest = createUnderTest(isEnabled = true)
|
||||
|
||||
assertThat(underTest.getPickerScreenState())
|
||||
.isEqualTo(KeyguardQuickAffordanceConfig.PickerScreenState.Default())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun getPickerScreenState_nodefaultNoteAppSet_shouldReturnDisable() = runTest {
|
||||
val underTest = createUnderTest(isEnabled = true)
|
||||
whenever(
|
||||
roleManager.getRoleHoldersAsUser(
|
||||
eq(RoleManager.ROLE_NOTES),
|
||||
any(UserHandle::class.java)
|
||||
)
|
||||
)
|
||||
.thenReturn(emptyList())
|
||||
|
||||
assertThat(underTest.getPickerScreenState())
|
||||
.isEqualTo(
|
||||
KeyguardQuickAffordanceConfig.PickerScreenState.Disabled(
|
||||
listOf("Select a default notes app to use notetaking shortcut"),
|
||||
actionText = "Open settings",
|
||||
actionComponentName =
|
||||
"${context.packageName}$COMPONENT_NAME_SEPARATOR" +
|
||||
"$ACTION_MANAGE_NOTES_ROLE_FROM_QUICK_AFFORDANCE"
|
||||
)
|
||||
)
|
||||
}
|
||||
// endregion
|
||||
|
||||
private inner class TestConfig {
|
||||
|
||||
fun setStylusEverUsed(value: Boolean) = also {
|
||||
|
||||
Reference in New Issue
Block a user