Merge "Log UI events for all note-taking entry points" into tm-qpr-dev
This commit is contained in:
@@ -20,9 +20,12 @@ import android.app.KeyguardManager
|
|||||||
import android.content.ActivityNotFoundException
|
import android.content.ActivityNotFoundException
|
||||||
import android.content.ComponentName
|
import android.content.ComponentName
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
import android.content.pm.PackageManager
|
import android.content.pm.PackageManager
|
||||||
import android.os.UserManager
|
import android.os.UserManager
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
|
import com.android.internal.logging.UiEvent
|
||||||
|
import com.android.internal.logging.UiEventLogger
|
||||||
import com.android.systemui.dagger.SysUISingleton
|
import com.android.systemui.dagger.SysUISingleton
|
||||||
import com.android.systemui.notetask.shortcut.CreateNoteTaskShortcutActivity
|
import com.android.systemui.notetask.shortcut.CreateNoteTaskShortcutActivity
|
||||||
import com.android.systemui.util.kotlin.getOrNull
|
import com.android.systemui.util.kotlin.getOrNull
|
||||||
@@ -42,11 +45,12 @@ internal class NoteTaskController
|
|||||||
@Inject
|
@Inject
|
||||||
constructor(
|
constructor(
|
||||||
private val context: Context,
|
private val context: Context,
|
||||||
private val intentResolver: NoteTaskIntentResolver,
|
private val resolver: NoteTaskInfoResolver,
|
||||||
private val optionalBubbles: Optional<Bubbles>,
|
private val optionalBubbles: Optional<Bubbles>,
|
||||||
private val optionalKeyguardManager: Optional<KeyguardManager>,
|
private val optionalKeyguardManager: Optional<KeyguardManager>,
|
||||||
private val optionalUserManager: Optional<UserManager>,
|
private val optionalUserManager: Optional<UserManager>,
|
||||||
@NoteTaskEnabledKey private val isEnabled: Boolean,
|
@NoteTaskEnabledKey private val isEnabled: Boolean,
|
||||||
|
private val uiEventLogger: UiEventLogger,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -64,7 +68,9 @@ constructor(
|
|||||||
*
|
*
|
||||||
* That will let users open other apps in full screen, and take contextual notes.
|
* That will let users open other apps in full screen, and take contextual notes.
|
||||||
*/
|
*/
|
||||||
fun showNoteTask(isInMultiWindowMode: Boolean = false) {
|
@JvmOverloads
|
||||||
|
fun showNoteTask(isInMultiWindowMode: Boolean = false, uiEvent: ShowNoteTaskUiEvent? = null) {
|
||||||
|
|
||||||
if (!isEnabled) return
|
if (!isEnabled) return
|
||||||
|
|
||||||
val bubbles = optionalBubbles.getOrNull() ?: return
|
val bubbles = optionalBubbles.getOrNull() ?: return
|
||||||
@@ -74,9 +80,12 @@ constructor(
|
|||||||
// TODO(b/249954038): We should handle direct boot (isUserUnlocked). For now, we do nothing.
|
// TODO(b/249954038): We should handle direct boot (isUserUnlocked). For now, we do nothing.
|
||||||
if (!userManager.isUserUnlocked) return
|
if (!userManager.isUserUnlocked) return
|
||||||
|
|
||||||
val intent = intentResolver.resolveIntent() ?: return
|
val noteTaskInfo = resolver.resolveInfo() ?: return
|
||||||
|
|
||||||
|
uiEvent?.let { uiEventLogger.log(it, noteTaskInfo.uid, noteTaskInfo.packageName) }
|
||||||
|
|
||||||
// TODO(b/266686199): We should handle when app not available. For now, we log.
|
// TODO(b/266686199): We should handle when app not available. For now, we log.
|
||||||
|
val intent = noteTaskInfo.toCreateNoteIntent()
|
||||||
try {
|
try {
|
||||||
if (isInMultiWindowMode || keyguardManager.isKeyguardLocked) {
|
if (isInMultiWindowMode || keyguardManager.isKeyguardLocked) {
|
||||||
context.startActivity(intent)
|
context.startActivity(intent)
|
||||||
@@ -84,9 +93,7 @@ constructor(
|
|||||||
bubbles.showOrHideAppBubble(intent)
|
bubbles.showOrHideAppBubble(intent)
|
||||||
}
|
}
|
||||||
} catch (e: ActivityNotFoundException) {
|
} catch (e: ActivityNotFoundException) {
|
||||||
val message =
|
Log.e(TAG, "Activity not found for action: $ACTION_CREATE_NOTE.", e)
|
||||||
"Activity not found for action: ${NoteTaskIntentResolver.ACTION_CREATE_NOTE}."
|
|
||||||
Log.e(TAG, message, e)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -114,10 +121,47 @@ constructor(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** IDs of UI events accepted by [showNoteTask]. */
|
||||||
|
enum class ShowNoteTaskUiEvent(private val _id: Int) : UiEventLogger.UiEventEnum {
|
||||||
|
@UiEvent(doc = "User opened a note by tapping on the lockscreen shortcut.")
|
||||||
|
NOTE_OPENED_VIA_KEYGUARD_QUICK_AFFORDANCE(1294),
|
||||||
|
|
||||||
|
/* ktlint-disable max-line-length */
|
||||||
|
@UiEvent(
|
||||||
|
doc =
|
||||||
|
"User opened a note by pressing the stylus tail button while the screen was unlocked."
|
||||||
|
)
|
||||||
|
NOTE_OPENED_VIA_STYLUS_TAIL_BUTTON(1295),
|
||||||
|
@UiEvent(
|
||||||
|
doc =
|
||||||
|
"User opened a note by pressing the stylus tail button while the screen was locked."
|
||||||
|
)
|
||||||
|
NOTE_OPENED_VIA_STYLUS_TAIL_BUTTON_LOCKED(1296),
|
||||||
|
@UiEvent(doc = "User opened a note by tapping on an app shortcut.")
|
||||||
|
NOTE_OPENED_VIA_SHORTCUT(1297);
|
||||||
|
|
||||||
|
override fun getId() = _id
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val TAG = NoteTaskController::class.simpleName.orEmpty()
|
private val TAG = NoteTaskController::class.simpleName.orEmpty()
|
||||||
|
|
||||||
|
private fun NoteTaskInfoResolver.NoteTaskInfo.toCreateNoteIntent(): Intent {
|
||||||
|
return Intent(ACTION_CREATE_NOTE)
|
||||||
|
.setPackage(packageName)
|
||||||
|
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||||
|
// EXTRA_USE_STYLUS_MODE does not mean a stylus is in-use, but a stylus entrypoint
|
||||||
|
// was used to start it.
|
||||||
|
.putExtra(INTENT_EXTRA_USE_STYLUS_MODE, true)
|
||||||
|
}
|
||||||
|
|
||||||
// TODO(b/254604589): Use final KeyEvent.KEYCODE_* instead.
|
// TODO(b/254604589): Use final KeyEvent.KEYCODE_* instead.
|
||||||
const val NOTE_TASK_KEY_EVENT = 311
|
const val NOTE_TASK_KEY_EVENT = 311
|
||||||
|
|
||||||
|
// TODO(b/265912743): Use Intent.ACTION_CREATE_NOTE instead.
|
||||||
|
const val ACTION_CREATE_NOTE = "android.intent.action.CREATE_NOTE"
|
||||||
|
|
||||||
|
// TODO(b/265912743): Use Intent.INTENT_EXTRA_USE_STYLUS_MODE instead.
|
||||||
|
const val INTENT_EXTRA_USE_STYLUS_MODE = "android.intent.extra.USE_STYLUS_MODE"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,69 @@
|
|||||||
|
/*
|
||||||
|
* 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.app.role.RoleManager
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.pm.PackageManager
|
||||||
|
import android.os.UserHandle
|
||||||
|
import android.util.Log
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
internal class NoteTaskInfoResolver
|
||||||
|
@Inject
|
||||||
|
constructor(
|
||||||
|
private val context: Context,
|
||||||
|
private val roleManager: RoleManager,
|
||||||
|
private val packageManager: PackageManager,
|
||||||
|
) {
|
||||||
|
fun resolveInfo(): NoteTaskInfo? {
|
||||||
|
// TODO(b/267634412): Select UserHandle depending on where the user initiated note-taking.
|
||||||
|
val user = context.user
|
||||||
|
val packageName = roleManager.getRoleHoldersAsUser(ROLE_NOTES, user).firstOrNull()
|
||||||
|
|
||||||
|
if (packageName.isNullOrEmpty()) return null
|
||||||
|
|
||||||
|
return NoteTaskInfo(packageName, packageManager.getUidOf(packageName, user))
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Package name and kernel user-ID of a note-taking app. */
|
||||||
|
data class NoteTaskInfo(val packageName: String, val uid: Int)
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val TAG = NoteTaskInfoResolver::class.simpleName.orEmpty()
|
||||||
|
|
||||||
|
private val EMPTY_APPLICATION_INFO_FLAGS = PackageManager.ApplicationInfoFlags.of(0)!!
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the kernel user-ID of [packageName] for a [user]. Returns zero if the app cannot
|
||||||
|
* be found.
|
||||||
|
*/
|
||||||
|
private fun PackageManager.getUidOf(packageName: String, user: UserHandle): Int {
|
||||||
|
val applicationInfo =
|
||||||
|
try {
|
||||||
|
getApplicationInfoAsUser(packageName, EMPTY_APPLICATION_INFO_FLAGS, user)
|
||||||
|
} catch (e: PackageManager.NameNotFoundException) {
|
||||||
|
Log.e(TAG, "Couldn't find notes app UID", e)
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return applicationInfo.uid
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(b/265912743): Use RoleManager.NOTES_ROLE instead.
|
||||||
|
const val ROLE_NOTES = "android.app.role.NOTES"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -16,8 +16,10 @@
|
|||||||
|
|
||||||
package com.android.systemui.notetask
|
package com.android.systemui.notetask
|
||||||
|
|
||||||
|
import android.app.KeyguardManager
|
||||||
import androidx.annotation.VisibleForTesting
|
import androidx.annotation.VisibleForTesting
|
||||||
import com.android.systemui.statusbar.CommandQueue
|
import com.android.systemui.statusbar.CommandQueue
|
||||||
|
import com.android.systemui.util.kotlin.getOrNull
|
||||||
import com.android.wm.shell.bubbles.Bubbles
|
import com.android.wm.shell.bubbles.Bubbles
|
||||||
import java.util.Optional
|
import java.util.Optional
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
@@ -30,6 +32,7 @@ constructor(
|
|||||||
private val noteTaskController: NoteTaskController,
|
private val noteTaskController: NoteTaskController,
|
||||||
private val commandQueue: CommandQueue,
|
private val commandQueue: CommandQueue,
|
||||||
@NoteTaskEnabledKey private val isEnabled: Boolean,
|
@NoteTaskEnabledKey private val isEnabled: Boolean,
|
||||||
|
private val optionalKeyguardManager: Optional<KeyguardManager>,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
@@ -37,11 +40,21 @@ constructor(
|
|||||||
object : CommandQueue.Callbacks {
|
object : CommandQueue.Callbacks {
|
||||||
override fun handleSystemKey(keyCode: Int) {
|
override fun handleSystemKey(keyCode: Int) {
|
||||||
if (keyCode == NoteTaskController.NOTE_TASK_KEY_EVENT) {
|
if (keyCode == NoteTaskController.NOTE_TASK_KEY_EVENT) {
|
||||||
noteTaskController.showNoteTask()
|
showNoteTask()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun showNoteTask() {
|
||||||
|
val uiEvent =
|
||||||
|
if (optionalKeyguardManager.isKeyguardLocked) {
|
||||||
|
NoteTaskController.ShowNoteTaskUiEvent.NOTE_OPENED_VIA_STYLUS_TAIL_BUTTON_LOCKED
|
||||||
|
} else {
|
||||||
|
NoteTaskController.ShowNoteTaskUiEvent.NOTE_OPENED_VIA_STYLUS_TAIL_BUTTON
|
||||||
|
}
|
||||||
|
noteTaskController.showNoteTask(uiEvent = uiEvent)
|
||||||
|
}
|
||||||
|
|
||||||
fun initialize() {
|
fun initialize() {
|
||||||
if (isEnabled && optionalBubbles.isPresent) {
|
if (isEnabled && optionalBubbles.isPresent) {
|
||||||
commandQueue.addCallback(callbacks)
|
commandQueue.addCallback(callbacks)
|
||||||
@@ -49,3 +62,7 @@ constructor(
|
|||||||
noteTaskController.setNoteTaskShortcutEnabled(isEnabled)
|
noteTaskController.setNoteTaskShortcutEnabled(isEnabled)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val Optional<KeyguardManager>.isKeyguardLocked: Boolean
|
||||||
|
// If there's no KeyguardManager, assume that the keyguard is not locked.
|
||||||
|
get() = getOrNull()?.isKeyguardLocked ?: false
|
||||||
|
|||||||
@@ -1,54 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2022 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.app.role.RoleManager
|
|
||||||
import android.content.Context
|
|
||||||
import android.content.Intent
|
|
||||||
import javax.inject.Inject
|
|
||||||
|
|
||||||
internal class NoteTaskIntentResolver
|
|
||||||
@Inject
|
|
||||||
constructor(
|
|
||||||
private val context: Context,
|
|
||||||
private val roleManager: RoleManager,
|
|
||||||
) {
|
|
||||||
|
|
||||||
fun resolveIntent(): Intent? {
|
|
||||||
val packageName = roleManager.getRoleHoldersAsUser(ROLE_NOTES, context.user).firstOrNull()
|
|
||||||
|
|
||||||
if (packageName.isNullOrEmpty()) return null
|
|
||||||
|
|
||||||
return Intent(ACTION_CREATE_NOTE)
|
|
||||||
.setPackage(packageName)
|
|
||||||
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
|
||||||
// EXTRA_USE_STYLUS_MODE does not mean a stylus is in-use, but a stylus entrypoint was
|
|
||||||
// used to start it.
|
|
||||||
.putExtra(INTENT_EXTRA_USE_STYLUS_MODE, true)
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
// TODO(b/265912743): Use Intent.ACTION_CREATE_NOTE instead.
|
|
||||||
const val ACTION_CREATE_NOTE = "android.intent.action.CREATE_NOTE"
|
|
||||||
|
|
||||||
// TODO(b/265912743): Use RoleManager.NOTES_ROLE instead.
|
|
||||||
const val ROLE_NOTES = "android.app.role.NOTES"
|
|
||||||
|
|
||||||
// TODO(b/265912743): Use Intent.INTENT_EXTRA_USE_STYLUS_MODE instead.
|
|
||||||
const val INTENT_EXTRA_USE_STYLUS_MODE = "android.intent.extra.USE_STYLUS_MODE"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -51,7 +51,7 @@ internal interface NoteTaskModule {
|
|||||||
featureFlags: FeatureFlags,
|
featureFlags: FeatureFlags,
|
||||||
roleManager: RoleManager,
|
roleManager: RoleManager,
|
||||||
): Boolean {
|
): Boolean {
|
||||||
val isRoleAvailable = roleManager.isRoleAvailable(NoteTaskIntentResolver.ROLE_NOTES)
|
val isRoleAvailable = roleManager.isRoleAvailable(NoteTaskInfoResolver.ROLE_NOTES)
|
||||||
val isFeatureEnabled = featureFlags.isEnabled(Flags.NOTE_TASKS)
|
val isFeatureEnabled = featureFlags.isEnabled(Flags.NOTE_TASKS)
|
||||||
return isRoleAvailable && isFeatureEnabled
|
return isRoleAvailable && isFeatureEnabled
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanc
|
|||||||
import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceConfig.OnTriggeredResult
|
import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceConfig.OnTriggeredResult
|
||||||
import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceConfig.PickerScreenState
|
import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceConfig.PickerScreenState
|
||||||
import com.android.systemui.notetask.NoteTaskController
|
import com.android.systemui.notetask.NoteTaskController
|
||||||
|
import com.android.systemui.notetask.NoteTaskController.ShowNoteTaskUiEvent
|
||||||
import com.android.systemui.notetask.NoteTaskEnabledKey
|
import com.android.systemui.notetask.NoteTaskEnabledKey
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import kotlinx.coroutines.flow.flowOf
|
import kotlinx.coroutines.flow.flowOf
|
||||||
@@ -64,7 +65,9 @@ constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onTriggered(expandable: Expandable?): OnTriggeredResult {
|
override fun onTriggered(expandable: Expandable?): OnTriggeredResult {
|
||||||
noteTaskController.showNoteTask()
|
noteTaskController.showNoteTask(
|
||||||
|
uiEvent = ShowNoteTaskUiEvent.NOTE_OPENED_VIA_KEYGUARD_QUICK_AFFORDANCE
|
||||||
|
)
|
||||||
return OnTriggeredResult.Handled
|
return OnTriggeredResult.Handled
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ import android.content.Intent
|
|||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import androidx.activity.ComponentActivity
|
import androidx.activity.ComponentActivity
|
||||||
import com.android.systemui.notetask.NoteTaskController
|
import com.android.systemui.notetask.NoteTaskController
|
||||||
import com.android.systemui.notetask.NoteTaskIntentResolver
|
import com.android.systemui.notetask.NoteTaskController.ShowNoteTaskUiEvent
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
/** Activity responsible for launching the note experience, and finish. */
|
/** Activity responsible for launching the note experience, and finish. */
|
||||||
@@ -34,7 +34,10 @@ constructor(
|
|||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
noteTaskController.showNoteTask(isInMultiWindowMode)
|
noteTaskController.showNoteTask(
|
||||||
|
isInMultiWindowMode = isInMultiWindowMode,
|
||||||
|
uiEvent = ShowNoteTaskUiEvent.NOTE_OPENED_VIA_SHORTCUT,
|
||||||
|
)
|
||||||
|
|
||||||
finish()
|
finish()
|
||||||
}
|
}
|
||||||
@@ -46,7 +49,7 @@ constructor(
|
|||||||
return Intent(context, LaunchNoteTaskActivity::class.java).apply {
|
return Intent(context, LaunchNoteTaskActivity::class.java).apply {
|
||||||
// Intent's action must be set in shortcuts, or an exception will be thrown.
|
// Intent's action must be set in shortcuts, or an exception will be thrown.
|
||||||
// TODO(b/254606432): Use Intent.ACTION_CREATE_NOTE instead.
|
// TODO(b/254606432): Use Intent.ACTION_CREATE_NOTE instead.
|
||||||
action = NoteTaskIntentResolver.ACTION_CREATE_NOTE
|
action = NoteTaskController.ACTION_CREATE_NOTE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,10 +23,14 @@ import android.content.pm.PackageManager
|
|||||||
import android.os.UserManager
|
import android.os.UserManager
|
||||||
import android.test.suitebuilder.annotation.SmallTest
|
import android.test.suitebuilder.annotation.SmallTest
|
||||||
import androidx.test.runner.AndroidJUnit4
|
import androidx.test.runner.AndroidJUnit4
|
||||||
|
import com.android.internal.logging.UiEventLogger
|
||||||
import com.android.systemui.SysuiTestCase
|
import com.android.systemui.SysuiTestCase
|
||||||
import com.android.systemui.notetask.NoteTaskIntentResolver.Companion.ACTION_CREATE_NOTE
|
import com.android.systemui.notetask.NoteTaskController.Companion.INTENT_EXTRA_USE_STYLUS_MODE
|
||||||
|
import com.android.systemui.notetask.NoteTaskController.ShowNoteTaskUiEvent
|
||||||
|
import com.android.systemui.notetask.NoteTaskInfoResolver.NoteTaskInfo
|
||||||
import com.android.systemui.notetask.shortcut.CreateNoteTaskShortcutActivity
|
import com.android.systemui.notetask.shortcut.CreateNoteTaskShortcutActivity
|
||||||
import com.android.systemui.util.mockito.argumentCaptor
|
import com.android.systemui.util.mockito.argumentCaptor
|
||||||
|
import com.android.systemui.util.mockito.capture
|
||||||
import com.android.systemui.util.mockito.eq
|
import com.android.systemui.util.mockito.eq
|
||||||
import com.android.systemui.util.mockito.whenever
|
import com.android.systemui.util.mockito.whenever
|
||||||
import com.android.wm.shell.bubbles.Bubbles
|
import com.android.wm.shell.bubbles.Bubbles
|
||||||
@@ -36,8 +40,8 @@ import org.junit.Before
|
|||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.runner.RunWith
|
import org.junit.runner.RunWith
|
||||||
import org.mockito.Mock
|
import org.mockito.Mock
|
||||||
import org.mockito.Mockito.never
|
|
||||||
import org.mockito.Mockito.verify
|
import org.mockito.Mockito.verify
|
||||||
|
import org.mockito.Mockito.verifyZeroInteractions
|
||||||
import org.mockito.MockitoAnnotations
|
import org.mockito.MockitoAnnotations
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -50,24 +54,23 @@ import org.mockito.MockitoAnnotations
|
|||||||
@RunWith(AndroidJUnit4::class)
|
@RunWith(AndroidJUnit4::class)
|
||||||
internal class NoteTaskControllerTest : SysuiTestCase() {
|
internal class NoteTaskControllerTest : SysuiTestCase() {
|
||||||
|
|
||||||
private val notesIntent = Intent(ACTION_CREATE_NOTE)
|
|
||||||
|
|
||||||
@Mock lateinit var context: Context
|
@Mock lateinit var context: Context
|
||||||
@Mock lateinit var packageManager: PackageManager
|
@Mock lateinit var packageManager: PackageManager
|
||||||
@Mock lateinit var noteTaskIntentResolver: NoteTaskIntentResolver
|
@Mock lateinit var resolver: NoteTaskInfoResolver
|
||||||
@Mock lateinit var bubbles: Bubbles
|
@Mock lateinit var bubbles: Bubbles
|
||||||
@Mock lateinit var optionalBubbles: Optional<Bubbles>
|
@Mock lateinit var optionalBubbles: Optional<Bubbles>
|
||||||
@Mock lateinit var keyguardManager: KeyguardManager
|
@Mock lateinit var keyguardManager: KeyguardManager
|
||||||
@Mock lateinit var optionalKeyguardManager: Optional<KeyguardManager>
|
@Mock lateinit var optionalKeyguardManager: Optional<KeyguardManager>
|
||||||
@Mock lateinit var optionalUserManager: Optional<UserManager>
|
@Mock lateinit var optionalUserManager: Optional<UserManager>
|
||||||
@Mock lateinit var userManager: UserManager
|
@Mock lateinit var userManager: UserManager
|
||||||
|
@Mock lateinit var uiEventLogger: UiEventLogger
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
fun setUp() {
|
fun setUp() {
|
||||||
MockitoAnnotations.initMocks(this)
|
MockitoAnnotations.initMocks(this)
|
||||||
|
|
||||||
whenever(context.packageManager).thenReturn(packageManager)
|
whenever(context.packageManager).thenReturn(packageManager)
|
||||||
whenever(noteTaskIntentResolver.resolveIntent()).thenReturn(notesIntent)
|
whenever(resolver.resolveInfo()).thenReturn(NoteTaskInfo(NOTES_PACKAGE_NAME, NOTES_UID))
|
||||||
whenever(optionalBubbles.orElse(null)).thenReturn(bubbles)
|
whenever(optionalBubbles.orElse(null)).thenReturn(bubbles)
|
||||||
whenever(optionalKeyguardManager.orElse(null)).thenReturn(keyguardManager)
|
whenever(optionalKeyguardManager.orElse(null)).thenReturn(keyguardManager)
|
||||||
whenever(optionalUserManager.orElse(null)).thenReturn(userManager)
|
whenever(optionalUserManager.orElse(null)).thenReturn(userManager)
|
||||||
@@ -77,101 +80,182 @@ internal class NoteTaskControllerTest : SysuiTestCase() {
|
|||||||
private fun createNoteTaskController(isEnabled: Boolean = true): NoteTaskController {
|
private fun createNoteTaskController(isEnabled: Boolean = true): NoteTaskController {
|
||||||
return NoteTaskController(
|
return NoteTaskController(
|
||||||
context = context,
|
context = context,
|
||||||
intentResolver = noteTaskIntentResolver,
|
resolver = resolver,
|
||||||
optionalBubbles = optionalBubbles,
|
optionalBubbles = optionalBubbles,
|
||||||
optionalKeyguardManager = optionalKeyguardManager,
|
optionalKeyguardManager = optionalKeyguardManager,
|
||||||
optionalUserManager = optionalUserManager,
|
optionalUserManager = optionalUserManager,
|
||||||
isEnabled = isEnabled,
|
isEnabled = isEnabled,
|
||||||
|
uiEventLogger = uiEventLogger,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// region showNoteTask
|
// region showNoteTask
|
||||||
@Test
|
@Test
|
||||||
fun showNoteTask_keyguardIsLocked_shouldStartActivity() {
|
fun showNoteTask_keyguardIsLocked_shouldStartActivityAndLogUiEvent() {
|
||||||
whenever(keyguardManager.isKeyguardLocked).thenReturn(true)
|
whenever(keyguardManager.isKeyguardLocked).thenReturn(true)
|
||||||
|
|
||||||
createNoteTaskController().showNoteTask(isInMultiWindowMode = false)
|
createNoteTaskController()
|
||||||
|
.showNoteTask(
|
||||||
|
isInMultiWindowMode = false,
|
||||||
|
uiEvent = ShowNoteTaskUiEvent.NOTE_OPENED_VIA_KEYGUARD_QUICK_AFFORDANCE,
|
||||||
|
)
|
||||||
|
|
||||||
verify(context).startActivity(notesIntent)
|
val intentCaptor = argumentCaptor<Intent>()
|
||||||
verify(bubbles, never()).showOrHideAppBubble(notesIntent)
|
verify(context).startActivity(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()
|
||||||
|
}
|
||||||
|
verifyZeroInteractions(bubbles)
|
||||||
|
verify(uiEventLogger)
|
||||||
|
.log(
|
||||||
|
ShowNoteTaskUiEvent.NOTE_OPENED_VIA_KEYGUARD_QUICK_AFFORDANCE,
|
||||||
|
NOTES_UID,
|
||||||
|
NOTES_PACKAGE_NAME
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun showNoteTask_keyguardIsUnlocked_shouldStartBubbles() {
|
fun showNoteTask_keyguardIsUnlocked_shouldStartBubblesAndLogUiEvent() {
|
||||||
whenever(keyguardManager.isKeyguardLocked).thenReturn(false)
|
whenever(keyguardManager.isKeyguardLocked).thenReturn(false)
|
||||||
|
|
||||||
createNoteTaskController().showNoteTask(isInMultiWindowMode = false)
|
createNoteTaskController()
|
||||||
|
.showNoteTask(
|
||||||
|
isInMultiWindowMode = false,
|
||||||
|
uiEvent = ShowNoteTaskUiEvent.NOTE_OPENED_VIA_STYLUS_TAIL_BUTTON,
|
||||||
|
)
|
||||||
|
|
||||||
verify(bubbles).showOrHideAppBubble(notesIntent)
|
verifyZeroInteractions(context)
|
||||||
verify(context, never()).startActivity(notesIntent)
|
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()
|
||||||
|
}
|
||||||
|
verify(uiEventLogger)
|
||||||
|
.log(
|
||||||
|
ShowNoteTaskUiEvent.NOTE_OPENED_VIA_STYLUS_TAIL_BUTTON,
|
||||||
|
NOTES_UID,
|
||||||
|
NOTES_PACKAGE_NAME
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun showNoteTask_isInMultiWindowMode_shouldStartActivity() {
|
fun showNoteTask_keyguardIsUnlocked_uiEventIsNull_shouldStartBubblesWithoutLoggingUiEvent() {
|
||||||
whenever(keyguardManager.isKeyguardLocked).thenReturn(false)
|
whenever(keyguardManager.isKeyguardLocked).thenReturn(false)
|
||||||
|
|
||||||
createNoteTaskController().showNoteTask(isInMultiWindowMode = true)
|
createNoteTaskController().showNoteTask(isInMultiWindowMode = false, uiEvent = null)
|
||||||
|
|
||||||
verify(context).startActivity(notesIntent)
|
verifyZeroInteractions(context)
|
||||||
verify(bubbles, never()).showOrHideAppBubble(notesIntent)
|
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()
|
||||||
|
}
|
||||||
|
verifyZeroInteractions(uiEventLogger)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun showNoteTask_isInMultiWindowMode_shouldStartActivityAndLogUiEvent() {
|
||||||
|
whenever(keyguardManager.isKeyguardLocked).thenReturn(false)
|
||||||
|
|
||||||
|
createNoteTaskController()
|
||||||
|
.showNoteTask(
|
||||||
|
isInMultiWindowMode = true,
|
||||||
|
uiEvent = ShowNoteTaskUiEvent.NOTE_OPENED_VIA_SHORTCUT,
|
||||||
|
)
|
||||||
|
|
||||||
|
val intentCaptor = argumentCaptor<Intent>()
|
||||||
|
verify(context).startActivity(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()
|
||||||
|
}
|
||||||
|
verifyZeroInteractions(bubbles)
|
||||||
|
verify(uiEventLogger)
|
||||||
|
.log(ShowNoteTaskUiEvent.NOTE_OPENED_VIA_SHORTCUT, NOTES_UID, NOTES_PACKAGE_NAME)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun showNoteTask_bubblesIsNull_shouldDoNothing() {
|
fun showNoteTask_bubblesIsNull_shouldDoNothing() {
|
||||||
whenever(optionalBubbles.orElse(null)).thenReturn(null)
|
whenever(optionalBubbles.orElse(null)).thenReturn(null)
|
||||||
|
|
||||||
createNoteTaskController().showNoteTask(isInMultiWindowMode = false)
|
createNoteTaskController()
|
||||||
|
.showNoteTask(
|
||||||
|
isInMultiWindowMode = false,
|
||||||
|
uiEvent = ShowNoteTaskUiEvent.NOTE_OPENED_VIA_STYLUS_TAIL_BUTTON
|
||||||
|
)
|
||||||
|
|
||||||
verify(context, never()).startActivity(notesIntent)
|
verifyZeroInteractions(context, bubbles, uiEventLogger)
|
||||||
verify(bubbles, never()).showOrHideAppBubble(notesIntent)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun showNoteTask_keyguardManagerIsNull_shouldDoNothing() {
|
fun showNoteTask_keyguardManagerIsNull_shouldDoNothing() {
|
||||||
whenever(optionalKeyguardManager.orElse(null)).thenReturn(null)
|
whenever(optionalKeyguardManager.orElse(null)).thenReturn(null)
|
||||||
|
|
||||||
createNoteTaskController().showNoteTask(isInMultiWindowMode = false)
|
createNoteTaskController()
|
||||||
|
.showNoteTask(
|
||||||
|
isInMultiWindowMode = false,
|
||||||
|
uiEvent = ShowNoteTaskUiEvent.NOTE_OPENED_VIA_STYLUS_TAIL_BUTTON,
|
||||||
|
)
|
||||||
|
|
||||||
verify(context, never()).startActivity(notesIntent)
|
verifyZeroInteractions(context, bubbles, uiEventLogger)
|
||||||
verify(bubbles, never()).showOrHideAppBubble(notesIntent)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun showNoteTask_userManagerIsNull_shouldDoNothing() {
|
fun showNoteTask_userManagerIsNull_shouldDoNothing() {
|
||||||
whenever(optionalUserManager.orElse(null)).thenReturn(null)
|
whenever(optionalUserManager.orElse(null)).thenReturn(null)
|
||||||
|
|
||||||
createNoteTaskController().showNoteTask(isInMultiWindowMode = false)
|
createNoteTaskController()
|
||||||
|
.showNoteTask(
|
||||||
|
isInMultiWindowMode = false,
|
||||||
|
uiEvent = ShowNoteTaskUiEvent.NOTE_OPENED_VIA_STYLUS_TAIL_BUTTON,
|
||||||
|
)
|
||||||
|
|
||||||
verify(context, never()).startActivity(notesIntent)
|
verifyZeroInteractions(context, bubbles, uiEventLogger)
|
||||||
verify(bubbles, never()).showOrHideAppBubble(notesIntent)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun showNoteTask_intentResolverReturnsNull_shouldDoNothing() {
|
fun showNoteTask_intentResolverReturnsNull_shouldDoNothing() {
|
||||||
whenever(noteTaskIntentResolver.resolveIntent()).thenReturn(null)
|
whenever(resolver.resolveInfo()).thenReturn(null)
|
||||||
|
|
||||||
createNoteTaskController().showNoteTask(isInMultiWindowMode = false)
|
createNoteTaskController()
|
||||||
|
.showNoteTask(
|
||||||
|
isInMultiWindowMode = false,
|
||||||
|
uiEvent = ShowNoteTaskUiEvent.NOTE_OPENED_VIA_STYLUS_TAIL_BUTTON,
|
||||||
|
)
|
||||||
|
|
||||||
verify(context, never()).startActivity(notesIntent)
|
verifyZeroInteractions(context, bubbles, uiEventLogger)
|
||||||
verify(bubbles, never()).showOrHideAppBubble(notesIntent)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun showNoteTask_flagDisabled_shouldDoNothing() {
|
fun showNoteTask_flagDisabled_shouldDoNothing() {
|
||||||
createNoteTaskController(isEnabled = false).showNoteTask()
|
createNoteTaskController(isEnabled = false)
|
||||||
|
.showNoteTask(uiEvent = ShowNoteTaskUiEvent.NOTE_OPENED_VIA_STYLUS_TAIL_BUTTON)
|
||||||
|
|
||||||
verify(context, never()).startActivity(notesIntent)
|
verifyZeroInteractions(context, bubbles, uiEventLogger)
|
||||||
verify(bubbles, never()).showOrHideAppBubble(notesIntent)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun showNoteTask_userIsLocked_shouldDoNothing() {
|
fun showNoteTask_userIsLocked_shouldDoNothing() {
|
||||||
whenever(userManager.isUserUnlocked).thenReturn(false)
|
whenever(userManager.isUserUnlocked).thenReturn(false)
|
||||||
|
|
||||||
createNoteTaskController().showNoteTask(isInMultiWindowMode = false)
|
createNoteTaskController()
|
||||||
|
.showNoteTask(
|
||||||
|
isInMultiWindowMode = false,
|
||||||
|
uiEvent = ShowNoteTaskUiEvent.NOTE_OPENED_VIA_STYLUS_TAIL_BUTTON,
|
||||||
|
)
|
||||||
|
|
||||||
verify(context, never()).startActivity(notesIntent)
|
verifyZeroInteractions(context, bubbles, uiEventLogger)
|
||||||
verify(bubbles, never()).showOrHideAppBubble(notesIntent)
|
|
||||||
}
|
}
|
||||||
// endregion
|
// endregion
|
||||||
|
|
||||||
@@ -206,4 +290,9 @@ internal class NoteTaskControllerTest : SysuiTestCase() {
|
|||||||
assertThat(argument.value.flattenToString()).isEqualTo(expected.flattenToString())
|
assertThat(argument.value.flattenToString()).isEqualTo(expected.flattenToString())
|
||||||
}
|
}
|
||||||
// endregion
|
// endregion
|
||||||
|
|
||||||
|
private companion object {
|
||||||
|
const val NOTES_PACKAGE_NAME = "com.android.note.app"
|
||||||
|
const val NOTES_UID = 123456
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,108 @@
|
|||||||
|
/*
|
||||||
|
* 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.app.role.RoleManager
|
||||||
|
import android.content.pm.ApplicationInfo
|
||||||
|
import android.content.pm.PackageManager
|
||||||
|
import android.test.suitebuilder.annotation.SmallTest
|
||||||
|
import androidx.test.runner.AndroidJUnit4
|
||||||
|
import com.android.systemui.SysuiTestCase
|
||||||
|
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.mockito.Mock
|
||||||
|
import org.mockito.Mockito.any
|
||||||
|
import org.mockito.MockitoAnnotations
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests for [NoteTaskInfoResolver].
|
||||||
|
*
|
||||||
|
* Build/Install/Run:
|
||||||
|
* - atest SystemUITests:NoteTaskInfoResolverTest
|
||||||
|
*/
|
||||||
|
@SmallTest
|
||||||
|
@RunWith(AndroidJUnit4::class)
|
||||||
|
internal class NoteTaskInfoResolverTest : SysuiTestCase() {
|
||||||
|
|
||||||
|
@Mock lateinit var packageManager: PackageManager
|
||||||
|
@Mock lateinit var roleManager: RoleManager
|
||||||
|
|
||||||
|
private lateinit var underTest: NoteTaskInfoResolver
|
||||||
|
|
||||||
|
@Before
|
||||||
|
fun setUp() {
|
||||||
|
MockitoAnnotations.initMocks(this)
|
||||||
|
underTest = NoteTaskInfoResolver(context, roleManager, packageManager)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun resolveInfo_shouldReturnInfo() {
|
||||||
|
val packageName = "com.android.note.app"
|
||||||
|
val uid = 123456
|
||||||
|
whenever(roleManager.getRoleHoldersAsUser(NoteTaskInfoResolver.ROLE_NOTES, context.user))
|
||||||
|
.then { listOf(packageName) }
|
||||||
|
whenever(
|
||||||
|
packageManager.getApplicationInfoAsUser(
|
||||||
|
eq(packageName),
|
||||||
|
any<PackageManager.ApplicationInfoFlags>(),
|
||||||
|
eq(context.user)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.thenReturn(ApplicationInfo().apply { this.uid = uid })
|
||||||
|
|
||||||
|
val actual = underTest.resolveInfo()
|
||||||
|
|
||||||
|
requireNotNull(actual) { "Note task info must not be null" }
|
||||||
|
assertThat(actual.packageName).isEqualTo(packageName)
|
||||||
|
assertThat(actual.uid).isEqualTo(uid)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun resolveInfo_packageManagerThrowsException_shouldReturnInfoWithZeroUid() {
|
||||||
|
val packageName = "com.android.note.app"
|
||||||
|
whenever(roleManager.getRoleHoldersAsUser(NoteTaskInfoResolver.ROLE_NOTES, context.user))
|
||||||
|
.then { listOf(packageName) }
|
||||||
|
whenever(
|
||||||
|
packageManager.getApplicationInfoAsUser(
|
||||||
|
eq(packageName),
|
||||||
|
any<PackageManager.ApplicationInfoFlags>(),
|
||||||
|
eq(context.user)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.thenThrow(PackageManager.NameNotFoundException(packageName))
|
||||||
|
|
||||||
|
val actual = underTest.resolveInfo()
|
||||||
|
|
||||||
|
requireNotNull(actual) { "Note task info must not be null" }
|
||||||
|
assertThat(actual.packageName).isEqualTo(packageName)
|
||||||
|
assertThat(actual.uid).isEqualTo(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun resolveInfo_noRoleHolderIsSet_shouldReturnNull() {
|
||||||
|
whenever(roleManager.getRoleHoldersAsUser(eq(NoteTaskInfoResolver.ROLE_NOTES), any()))
|
||||||
|
.then { listOf<String>() }
|
||||||
|
|
||||||
|
val actual = underTest.resolveInfo()
|
||||||
|
|
||||||
|
assertThat(actual).isNull()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -15,11 +15,14 @@
|
|||||||
*/
|
*/
|
||||||
package com.android.systemui.notetask
|
package com.android.systemui.notetask
|
||||||
|
|
||||||
|
import android.app.KeyguardManager
|
||||||
import android.test.suitebuilder.annotation.SmallTest
|
import android.test.suitebuilder.annotation.SmallTest
|
||||||
import android.view.KeyEvent
|
import android.view.KeyEvent
|
||||||
import androidx.test.runner.AndroidJUnit4
|
import androidx.test.runner.AndroidJUnit4
|
||||||
import com.android.systemui.SysuiTestCase
|
import com.android.systemui.SysuiTestCase
|
||||||
|
import com.android.systemui.notetask.NoteTaskController.ShowNoteTaskUiEvent
|
||||||
import com.android.systemui.statusbar.CommandQueue
|
import com.android.systemui.statusbar.CommandQueue
|
||||||
|
import com.android.systemui.util.mockito.mock
|
||||||
import com.android.systemui.util.mockito.whenever
|
import com.android.systemui.util.mockito.whenever
|
||||||
import com.android.wm.shell.bubbles.Bubbles
|
import com.android.wm.shell.bubbles.Bubbles
|
||||||
import java.util.Optional
|
import java.util.Optional
|
||||||
@@ -30,6 +33,7 @@ import org.mockito.ArgumentMatchers.any
|
|||||||
import org.mockito.Mock
|
import org.mockito.Mock
|
||||||
import org.mockito.Mockito.never
|
import org.mockito.Mockito.never
|
||||||
import org.mockito.Mockito.verify
|
import org.mockito.Mockito.verify
|
||||||
|
import org.mockito.Mockito.verifyZeroInteractions
|
||||||
import org.mockito.MockitoAnnotations
|
import org.mockito.MockitoAnnotations
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -55,12 +59,16 @@ internal class NoteTaskInitializerTest : SysuiTestCase() {
|
|||||||
whenever(optionalBubbles.orElse(null)).thenReturn(bubbles)
|
whenever(optionalBubbles.orElse(null)).thenReturn(bubbles)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createNoteTaskInitializer(isEnabled: Boolean = true): NoteTaskInitializer {
|
private fun createNoteTaskInitializer(
|
||||||
|
isEnabled: Boolean = true,
|
||||||
|
optionalKeyguardManager: Optional<KeyguardManager> = Optional.empty(),
|
||||||
|
): NoteTaskInitializer {
|
||||||
return NoteTaskInitializer(
|
return NoteTaskInitializer(
|
||||||
optionalBubbles = optionalBubbles,
|
optionalBubbles = optionalBubbles,
|
||||||
noteTaskController = noteTaskController,
|
noteTaskController = noteTaskController,
|
||||||
commandQueue = commandQueue,
|
commandQueue = commandQueue,
|
||||||
isEnabled = isEnabled,
|
isEnabled = isEnabled,
|
||||||
|
optionalKeyguardManager = optionalKeyguardManager,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -105,19 +113,44 @@ internal class NoteTaskInitializerTest : SysuiTestCase() {
|
|||||||
|
|
||||||
// region handleSystemKey
|
// region handleSystemKey
|
||||||
@Test
|
@Test
|
||||||
fun handleSystemKey_receiveValidSystemKey_shouldShowNoteTask() {
|
fun handleSystemKey_receiveValidSystemKey_keyguardNotLocked_shouldShowNoteTaskWithUnlocked() {
|
||||||
createNoteTaskInitializer()
|
val keyguardManager =
|
||||||
|
mock<KeyguardManager>() { whenever(isKeyguardLocked).thenReturn(false) }
|
||||||
|
createNoteTaskInitializer(optionalKeyguardManager = Optional.of(keyguardManager))
|
||||||
.callbacks
|
.callbacks
|
||||||
.handleSystemKey(NoteTaskController.NOTE_TASK_KEY_EVENT)
|
.handleSystemKey(NoteTaskController.NOTE_TASK_KEY_EVENT)
|
||||||
|
|
||||||
verify(noteTaskController).showNoteTask()
|
verify(noteTaskController)
|
||||||
|
.showNoteTask(uiEvent = ShowNoteTaskUiEvent.NOTE_OPENED_VIA_STYLUS_TAIL_BUTTON)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun handleSystemKey_receiveValidSystemKey_keyguardLocked_shouldShowNoteTaskWithLocked() {
|
||||||
|
val keyguardManager =
|
||||||
|
mock<KeyguardManager>() { whenever(isKeyguardLocked).thenReturn(true) }
|
||||||
|
createNoteTaskInitializer(optionalKeyguardManager = Optional.of(keyguardManager))
|
||||||
|
.callbacks
|
||||||
|
.handleSystemKey(NoteTaskController.NOTE_TASK_KEY_EVENT)
|
||||||
|
|
||||||
|
verify(noteTaskController)
|
||||||
|
.showNoteTask(uiEvent = ShowNoteTaskUiEvent.NOTE_OPENED_VIA_STYLUS_TAIL_BUTTON_LOCKED)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun handleSystemKey_receiveValidSystemKey_nullKeyguardManager_shouldShowNoteTaskWithUnlocked() {
|
||||||
|
createNoteTaskInitializer(optionalKeyguardManager = Optional.empty())
|
||||||
|
.callbacks
|
||||||
|
.handleSystemKey(NoteTaskController.NOTE_TASK_KEY_EVENT)
|
||||||
|
|
||||||
|
verify(noteTaskController)
|
||||||
|
.showNoteTask(uiEvent = ShowNoteTaskUiEvent.NOTE_OPENED_VIA_STYLUS_TAIL_BUTTON)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun handleSystemKey_receiveInvalidSystemKey_shouldDoNothing() {
|
fun handleSystemKey_receiveInvalidSystemKey_shouldDoNothing() {
|
||||||
createNoteTaskInitializer().callbacks.handleSystemKey(KeyEvent.KEYCODE_UNKNOWN)
|
createNoteTaskInitializer().callbacks.handleSystemKey(KeyEvent.KEYCODE_UNKNOWN)
|
||||||
|
|
||||||
verify(noteTaskController, never()).showNoteTask()
|
verifyZeroInteractions(noteTaskController)
|
||||||
}
|
}
|
||||||
// endregion
|
// endregion
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,83 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2022 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.app.role.RoleManager
|
|
||||||
import android.content.Intent
|
|
||||||
import android.content.pm.PackageManager
|
|
||||||
import android.test.suitebuilder.annotation.SmallTest
|
|
||||||
import androidx.test.runner.AndroidJUnit4
|
|
||||||
import com.android.systemui.SysuiTestCase
|
|
||||||
import com.android.systemui.notetask.NoteTaskIntentResolver.Companion.ACTION_CREATE_NOTE
|
|
||||||
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.mockito.Mock
|
|
||||||
import org.mockito.Mockito.any
|
|
||||||
import org.mockito.MockitoAnnotations
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests for [NoteTaskIntentResolver].
|
|
||||||
*
|
|
||||||
* Build/Install/Run:
|
|
||||||
* - atest SystemUITests:NoteTaskIntentResolverTest
|
|
||||||
*/
|
|
||||||
@SmallTest
|
|
||||||
@RunWith(AndroidJUnit4::class)
|
|
||||||
internal class NoteTaskIntentResolverTest : SysuiTestCase() {
|
|
||||||
|
|
||||||
@Mock lateinit var packageManager: PackageManager
|
|
||||||
@Mock lateinit var roleManager: RoleManager
|
|
||||||
|
|
||||||
private lateinit var underTest: NoteTaskIntentResolver
|
|
||||||
|
|
||||||
@Before
|
|
||||||
fun setUp() {
|
|
||||||
MockitoAnnotations.initMocks(this)
|
|
||||||
underTest = NoteTaskIntentResolver(context, roleManager)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun resolveIntent_shouldReturnIntentInStylusMode() {
|
|
||||||
val packageName = "com.android.note.app"
|
|
||||||
whenever(roleManager.getRoleHoldersAsUser(NoteTaskIntentResolver.ROLE_NOTES, context.user))
|
|
||||||
.then { listOf(packageName) }
|
|
||||||
|
|
||||||
val actual = underTest.resolveIntent()
|
|
||||||
|
|
||||||
requireNotNull(actual) { "Intent must not be null" }
|
|
||||||
assertThat(actual.action).isEqualTo(ACTION_CREATE_NOTE)
|
|
||||||
assertThat(actual.`package`).isEqualTo(packageName)
|
|
||||||
val expectedExtra = actual.getExtra(NoteTaskIntentResolver.INTENT_EXTRA_USE_STYLUS_MODE)
|
|
||||||
assertThat(expectedExtra).isEqualTo(true)
|
|
||||||
val expectedFlag = actual.flags and Intent.FLAG_ACTIVITY_NEW_TASK
|
|
||||||
assertThat(expectedFlag).isEqualTo(Intent.FLAG_ACTIVITY_NEW_TASK)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun resolveIntent_noRoleHolderIsSet_shouldReturnNull() {
|
|
||||||
whenever(roleManager.getRoleHoldersAsUser(eq(NoteTaskIntentResolver.ROLE_NOTES), any()))
|
|
||||||
.then { listOf<String>() }
|
|
||||||
|
|
||||||
val actual = underTest.resolveIntent()
|
|
||||||
|
|
||||||
assertThat(actual).isNull()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -27,7 +27,7 @@ import com.android.systemui.common.shared.model.Icon
|
|||||||
import com.android.systemui.coroutines.collectLastValue
|
import com.android.systemui.coroutines.collectLastValue
|
||||||
import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceConfig.LockScreenState
|
import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceConfig.LockScreenState
|
||||||
import com.android.systemui.notetask.NoteTaskController
|
import com.android.systemui.notetask.NoteTaskController
|
||||||
import com.android.systemui.util.mockito.whenever
|
import com.android.systemui.notetask.NoteTaskController.ShowNoteTaskUiEvent
|
||||||
import com.google.common.truth.Truth.assertThat
|
import com.google.common.truth.Truth.assertThat
|
||||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
import kotlinx.coroutines.test.runTest
|
import kotlinx.coroutines.test.runTest
|
||||||
@@ -53,7 +53,6 @@ internal class NoteTaskQuickAffordanceConfigTest : SysuiTestCase() {
|
|||||||
@Before
|
@Before
|
||||||
fun setUp() {
|
fun setUp() {
|
||||||
MockitoAnnotations.initMocks(this)
|
MockitoAnnotations.initMocks(this)
|
||||||
whenever(noteTaskController.showNoteTask()).then {}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createUnderTest(isEnabled: Boolean) =
|
private fun createUnderTest(isEnabled: Boolean) =
|
||||||
@@ -96,6 +95,7 @@ internal class NoteTaskQuickAffordanceConfigTest : SysuiTestCase() {
|
|||||||
|
|
||||||
underTest.onTriggered(expandable = null)
|
underTest.onTriggered(expandable = null)
|
||||||
|
|
||||||
verify(noteTaskController).showNoteTask()
|
verify(noteTaskController)
|
||||||
|
.showNoteTask(uiEvent = ShowNoteTaskUiEvent.NOTE_OPENED_VIA_KEYGUARD_QUICK_AFFORDANCE)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user