RESTRICT AUTOMERGE Support split-mode on Note Shortcut am: a896a94ed7

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

Change-Id: I4401c2279cafaba9d11d553ac1d7f8271a0ec42d
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
Marcello Galhardo
2023-06-08 09:36:28 +00:00
committed by Automerger Merge Worker
9 changed files with 119 additions and 73 deletions

View File

@@ -996,7 +996,6 @@
android:name=".notetask.shortcut.LaunchNoteTaskActivity" android:name=".notetask.shortcut.LaunchNoteTaskActivity"
android:exported="true" android:exported="true"
android:excludeFromRecents="true" android:excludeFromRecents="true"
android:resizeableActivity="false"
android:theme="@android:style/Theme.NoDisplay" > android:theme="@android:style/Theme.NoDisplay" >
<intent-filter> <intent-filter>
@@ -1012,7 +1011,6 @@
android:exported="false" android:exported="false"
android:enabled="true" android:enabled="true"
android:excludeFromRecents="true" android:excludeFromRecents="true"
android:resizeableActivity="false"
android:theme="@android:style/Theme.NoDisplay" /> android:theme="@android:style/Theme.NoDisplay" />
<activity <activity

View File

@@ -215,7 +215,7 @@ constructor(
debugLog { "onShowNoteTask - opened as app bubble: $info" } debugLog { "onShowNoteTask - opened as app bubble: $info" }
} }
is NoteTaskLaunchMode.Activity -> { is NoteTaskLaunchMode.Activity -> {
if (activityManager.isInForeground(info.packageName)) { if (info.isKeyguardLocked && activityManager.isInForeground(info.packageName)) {
// Force note task into background by calling home. // Force note task into background by calling home.
val intent = createHomeIntent() val intent = createHomeIntent()
context.startActivityAsUser(intent, user) context.startActivityAsUser(intent, user)

View File

@@ -25,12 +25,14 @@ import com.android.systemui.screenshot.appclips.AppClipsTrampolineActivity
* An entry point represents where the note task has ben called from. In rare cases, it may * An entry point represents where the note task has ben called from. In rare cases, it may
* represent a "re-entry" (i.e., [APP_CLIPS]). * represent a "re-entry" (i.e., [APP_CLIPS]).
*/ */
enum class enum class NoteTaskEntryPoint {
NoteTaskEntryPoint {
/** @see [LaunchNoteTaskActivity] */ /** @see [LaunchNoteTaskActivity] */
WIDGET_PICKER_SHORTCUT, WIDGET_PICKER_SHORTCUT,
/** @see [LaunchNoteTaskActivity] */
WIDGET_PICKER_SHORTCUT_IN_MULTI_WINDOW_MODE,
/** @see [NoteTaskQuickAffordanceConfig] */ /** @see [NoteTaskQuickAffordanceConfig] */
QUICK_AFFORDANCE, QUICK_AFFORDANCE,

View File

@@ -22,6 +22,8 @@ import com.android.systemui.notetask.NoteTaskEntryPoint.KEYBOARD_SHORTCUT
import com.android.systemui.notetask.NoteTaskEntryPoint.QUICK_AFFORDANCE import com.android.systemui.notetask.NoteTaskEntryPoint.QUICK_AFFORDANCE
import com.android.systemui.notetask.NoteTaskEntryPoint.TAIL_BUTTON import com.android.systemui.notetask.NoteTaskEntryPoint.TAIL_BUTTON
import com.android.systemui.notetask.NoteTaskEntryPoint.WIDGET_PICKER_SHORTCUT import com.android.systemui.notetask.NoteTaskEntryPoint.WIDGET_PICKER_SHORTCUT
import com.android.systemui.notetask.NoteTaskEntryPoint.WIDGET_PICKER_SHORTCUT_IN_MULTI_WINDOW_MODE
import com.android.systemui.notetask.NoteTaskEventLogger.NoteTaskUiEvent
import com.android.systemui.notetask.NoteTaskEventLogger.NoteTaskUiEvent.NOTE_OPENED_VIA_KEYGUARD_QUICK_AFFORDANCE import com.android.systemui.notetask.NoteTaskEventLogger.NoteTaskUiEvent.NOTE_OPENED_VIA_KEYGUARD_QUICK_AFFORDANCE
import com.android.systemui.notetask.NoteTaskEventLogger.NoteTaskUiEvent.NOTE_OPENED_VIA_SHORTCUT import com.android.systemui.notetask.NoteTaskEventLogger.NoteTaskUiEvent.NOTE_OPENED_VIA_SHORTCUT
import com.android.systemui.notetask.NoteTaskEventLogger.NoteTaskUiEvent.NOTE_OPENED_VIA_STYLUS_TAIL_BUTTON import com.android.systemui.notetask.NoteTaskEventLogger.NoteTaskUiEvent.NOTE_OPENED_VIA_STYLUS_TAIL_BUTTON
@@ -41,40 +43,45 @@ class NoteTaskEventLogger @Inject constructor(private val uiEventLogger: UiEvent
/** Logs a [NoteTaskInfo] as an **open** [NoteTaskUiEvent], including package name and uid. */ /** Logs a [NoteTaskInfo] as an **open** [NoteTaskUiEvent], including package name and uid. */
fun logNoteTaskOpened(info: NoteTaskInfo) { fun logNoteTaskOpened(info: NoteTaskInfo) {
val event = val event =
when (info.entryPoint) { when (info.entryPoint) {
TAIL_BUTTON -> { TAIL_BUTTON -> {
if (info.isKeyguardLocked) { if (info.isKeyguardLocked) {
NOTE_OPENED_VIA_STYLUS_TAIL_BUTTON_LOCKED NOTE_OPENED_VIA_STYLUS_TAIL_BUTTON_LOCKED
} else { } else {
NOTE_OPENED_VIA_STYLUS_TAIL_BUTTON NOTE_OPENED_VIA_STYLUS_TAIL_BUTTON
}
} }
WIDGET_PICKER_SHORTCUT,
WIDGET_PICKER_SHORTCUT_IN_MULTI_WINDOW_MODE -> NOTE_OPENED_VIA_SHORTCUT
QUICK_AFFORDANCE -> NOTE_OPENED_VIA_KEYGUARD_QUICK_AFFORDANCE
APP_CLIPS,
KEYBOARD_SHORTCUT,
null -> return
} }
WIDGET_PICKER_SHORTCUT -> NOTE_OPENED_VIA_SHORTCUT
QUICK_AFFORDANCE -> NOTE_OPENED_VIA_KEYGUARD_QUICK_AFFORDANCE
APP_CLIPS -> return
KEYBOARD_SHORTCUT -> return
null -> return
}
uiEventLogger.log(event, info.uid, info.packageName) uiEventLogger.log(event, info.uid, info.packageName)
} }
/** Logs a [NoteTaskInfo] as a **closed** [NoteTaskUiEvent], including package name and uid. */ /** Logs a [NoteTaskInfo] as a **closed** [NoteTaskUiEvent], including package name and uid. */
fun logNoteTaskClosed(info: NoteTaskInfo) { fun logNoteTaskClosed(info: NoteTaskInfo) {
val event = val event =
when (info.entryPoint) { when (info.entryPoint) {
TAIL_BUTTON -> { TAIL_BUTTON -> {
if (info.isKeyguardLocked) { if (info.isKeyguardLocked) {
NoteTaskUiEvent.NOTE_CLOSED_VIA_STYLUS_TAIL_BUTTON_LOCKED NoteTaskUiEvent.NOTE_CLOSED_VIA_STYLUS_TAIL_BUTTON_LOCKED
} else { } else {
NoteTaskUiEvent.NOTE_CLOSED_VIA_STYLUS_TAIL_BUTTON NoteTaskUiEvent.NOTE_CLOSED_VIA_STYLUS_TAIL_BUTTON
}
} }
WIDGET_PICKER_SHORTCUT,
WIDGET_PICKER_SHORTCUT_IN_MULTI_WINDOW_MODE,
QUICK_AFFORDANCE,
APP_CLIPS,
KEYBOARD_SHORTCUT,
null -> return
} }
WIDGET_PICKER_SHORTCUT -> return
QUICK_AFFORDANCE -> return
APP_CLIPS -> return
KEYBOARD_SHORTCUT -> return
null -> return
}
uiEventLogger.log(event, info.uid, info.packageName) uiEventLogger.log(event, info.uid, info.packageName)
} }

View File

@@ -16,6 +16,7 @@
package com.android.systemui.notetask package com.android.systemui.notetask
import android.os.UserHandle import android.os.UserHandle
import com.android.systemui.notetask.NoteTaskEntryPoint.WIDGET_PICKER_SHORTCUT_IN_MULTI_WINDOW_MODE
/** Contextual information required to launch a Note Task by [NoteTaskController]. */ /** Contextual information required to launch a Note Task by [NoteTaskController]. */
data class NoteTaskInfo( data class NoteTaskInfo(
@@ -27,7 +28,7 @@ data class NoteTaskInfo(
) { ) {
val launchMode: NoteTaskLaunchMode = val launchMode: NoteTaskLaunchMode =
if (isKeyguardLocked) { if (isKeyguardLocked || entryPoint == WIDGET_PICKER_SHORTCUT_IN_MULTI_WINDOW_MODE) {
NoteTaskLaunchMode.Activity NoteTaskLaunchMode.Activity
} else { } else {
NoteTaskLaunchMode.AppBubble NoteTaskLaunchMode.AppBubble

View File

@@ -51,7 +51,8 @@ internal object NoteTaskRoleManagerExt {
val icon = Icon.createWithResource(context, R.drawable.ic_note_task_shortcut_widget) val icon = Icon.createWithResource(context, R.drawable.ic_note_task_shortcut_widget)
return ShortcutInfo.Builder(context, NoteTaskController.SHORTCUT_ID) return ShortcutInfo.Builder(context, NoteTaskController.SHORTCUT_ID)
.setIntent(LaunchNoteTaskActivity.newIntent(context = context)) .setIntent(LaunchNoteTaskActivity.createIntent(context))
.setActivity(LaunchNoteTaskActivity.createComponent(context))
.setShortLabel(context.getString(R.string.note_task_button_label)) .setShortLabel(context.getString(R.string.note_task_button_label))
.setLongLived(true) .setLongLived(true)
.setIcon(icon) .setIcon(icon)

View File

@@ -16,6 +16,7 @@
package com.android.systemui.notetask.shortcut package com.android.systemui.notetask.shortcut
import android.content.ComponentName
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.os.Bundle import android.os.Bundle
@@ -72,7 +73,13 @@ constructor(
controller.startNoteTaskProxyActivityForUser(mainUser) controller.startNoteTaskProxyActivityForUser(mainUser)
} }
} else { } else {
controller.showNoteTask(entryPoint = NoteTaskEntryPoint.WIDGET_PICKER_SHORTCUT) val entryPoint =
if (isInMultiWindowMode) {
NoteTaskEntryPoint.WIDGET_PICKER_SHORTCUT_IN_MULTI_WINDOW_MODE
} else {
NoteTaskEntryPoint.WIDGET_PICKER_SHORTCUT
}
controller.showNoteTask(entryPoint)
} }
finish() finish()
} }
@@ -80,11 +87,14 @@ constructor(
companion object { companion object {
/** Creates a new [Intent] set to start [LaunchNoteTaskActivity]. */ /** Creates a new [Intent] set to start [LaunchNoteTaskActivity]. */
fun newIntent(context: Context): Intent { fun createIntent(context: Context): Intent =
return Intent(context, LaunchNoteTaskActivity::class.java).apply { 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.
action = Intent.ACTION_CREATE_NOTE action = Intent.ACTION_CREATE_NOTE
} }
}
/** Creates a new [ComponentName] for [LaunchNoteTaskActivity]. */
fun createComponent(context: Context): ComponentName =
ComponentName(context, LaunchNoteTaskActivity::class.java)
} }
} }

View File

@@ -72,6 +72,7 @@ import org.junit.Test
import org.junit.runner.RunWith import org.junit.runner.RunWith
import org.mockito.ArgumentMatchers.anyInt import org.mockito.ArgumentMatchers.anyInt
import org.mockito.Mock import org.mockito.Mock
import org.mockito.Mockito.atLeastOnce
import org.mockito.Mockito.doNothing import org.mockito.Mockito.doNothing
import org.mockito.Mockito.never import org.mockito.Mockito.never
import org.mockito.Mockito.spy import org.mockito.Mockito.spy
@@ -227,31 +228,7 @@ internal class NoteTaskControllerTest : SysuiTestCase() {
// region showNoteTask // region showNoteTask
@Test @Test
fun showNoteTask_keyguardIsLocked_shouldStartActivityAndLogUiEvent() { fun showNoteTaskAsUser_keyguardIsLocked_shouldStartActivityWithExpectedUserAndLogUiEvent() {
val expectedInfo = NOTE_TASK_INFO.copy(entryPoint = TAIL_BUTTON, isKeyguardLocked = true)
whenever(keyguardManager.isKeyguardLocked).thenReturn(expectedInfo.isKeyguardLocked)
whenever(resolver.resolveInfo(any(), any(), any())).thenReturn(expectedInfo)
createNoteTaskController().showNoteTask(entryPoint = expectedInfo.entryPoint!!)
val intentCaptor = argumentCaptor<Intent>()
val userCaptor = argumentCaptor<UserHandle>()
verify(context).startActivityAsUser(capture(intentCaptor), capture(userCaptor))
assertThat(intentCaptor.value).run {
hasAction(ACTION_CREATE_NOTE)
hasPackage(NOTE_TASK_PACKAGE_NAME)
hasFlags(FLAG_ACTIVITY_NEW_TASK)
hasFlags(FLAG_ACTIVITY_MULTIPLE_TASK)
hasFlags(FLAG_ACTIVITY_NEW_DOCUMENT)
extras().bool(EXTRA_USE_STYLUS_MODE).isTrue()
}
assertThat(userCaptor.value).isEqualTo(userTracker.userHandle)
verify(eventLogger).logNoteTaskOpened(expectedInfo)
verifyZeroInteractions(bubbles)
}
@Test
fun showNoteTaskWithUser_keyguardIsLocked_shouldStartActivityWithExpectedUserAndLogUiEvent() {
val user10 = UserHandle.of(/* userId= */ 10) val user10 = UserHandle.of(/* userId= */ 10)
val expectedInfo = val expectedInfo =
NOTE_TASK_INFO.copy(entryPoint = TAIL_BUTTON, isKeyguardLocked = true, user = user10) NOTE_TASK_INFO.copy(entryPoint = TAIL_BUTTON, isKeyguardLocked = true, user = user10)
@@ -277,6 +254,30 @@ internal class NoteTaskControllerTest : SysuiTestCase() {
verifyZeroInteractions(bubbles) verifyZeroInteractions(bubbles)
} }
@Test
fun showNoteTask_keyguardIsLocked_notesIsClosed_shouldStartActivityAndLogUiEvent() {
val expectedInfo = NOTE_TASK_INFO.copy(entryPoint = TAIL_BUTTON, isKeyguardLocked = true)
whenever(keyguardManager.isKeyguardLocked).thenReturn(expectedInfo.isKeyguardLocked)
whenever(resolver.resolveInfo(any(), any(), any())).thenReturn(expectedInfo)
createNoteTaskController().showNoteTask(entryPoint = expectedInfo.entryPoint!!)
val intentCaptor = argumentCaptor<Intent>()
val userCaptor = argumentCaptor<UserHandle>()
verify(context).startActivityAsUser(capture(intentCaptor), capture(userCaptor))
assertThat(intentCaptor.value).run {
hasAction(ACTION_CREATE_NOTE)
hasPackage(NOTE_TASK_PACKAGE_NAME)
hasFlags(FLAG_ACTIVITY_NEW_TASK)
hasFlags(FLAG_ACTIVITY_MULTIPLE_TASK)
hasFlags(FLAG_ACTIVITY_NEW_DOCUMENT)
extras().bool(EXTRA_USE_STYLUS_MODE).isTrue()
}
assertThat(userCaptor.value).isEqualTo(userTracker.userHandle)
verify(eventLogger).logNoteTaskOpened(expectedInfo)
verifyZeroInteractions(bubbles)
}
@Test @Test
fun showNoteTask_keyguardIsLocked_noteIsOpen_shouldCloseActivityAndLogUiEvent() { fun showNoteTask_keyguardIsLocked_noteIsOpen_shouldCloseActivityAndLogUiEvent() {
val expectedInfo = NOTE_TASK_INFO.copy(entryPoint = TAIL_BUTTON, isKeyguardLocked = true) val expectedInfo = NOTE_TASK_INFO.copy(entryPoint = TAIL_BUTTON, isKeyguardLocked = true)
@@ -301,7 +302,7 @@ internal class NoteTaskControllerTest : SysuiTestCase() {
} }
@Test @Test
fun showNoteTask_keyguardIsUnlocked_shouldStartBubblesWithoutLoggingUiEvent() { fun showNoteTask_keyguardIsUnlocked_noteIsClosed_shouldStartBubblesWithoutLoggingUiEvent() {
val expectedInfo = NOTE_TASK_INFO.copy(entryPoint = TAIL_BUTTON, isKeyguardLocked = false) val expectedInfo = NOTE_TASK_INFO.copy(entryPoint = TAIL_BUTTON, isKeyguardLocked = false)
whenever(resolver.resolveInfo(any(), any(), any())).thenReturn(expectedInfo) whenever(resolver.resolveInfo(any(), any(), any())).thenReturn(expectedInfo)
whenever(keyguardManager.isKeyguardLocked).thenReturn(expectedInfo.isKeyguardLocked) whenever(keyguardManager.isKeyguardLocked).thenReturn(expectedInfo.isKeyguardLocked)
@@ -309,7 +310,23 @@ internal class NoteTaskControllerTest : SysuiTestCase() {
createNoteTaskController().showNoteTask(entryPoint = expectedInfo.entryPoint!!) createNoteTaskController().showNoteTask(entryPoint = expectedInfo.entryPoint!!)
// Context package name used to create bubble icon from drawable resource id // Context package name used to create bubble icon from drawable resource id
verify(context).packageName verify(context, atLeastOnce()).packageName
verifyNoteTaskOpenInBubbleInUser(userTracker.userHandle)
verifyZeroInteractions(eventLogger)
}
@Test
fun showNoteTask_keyguardIsUnlocked_noteIsOpen_shouldStartBubblesWithoutLoggingUiEvent() {
val expectedInfo = NOTE_TASK_INFO.copy(entryPoint = TAIL_BUTTON, isKeyguardLocked = false)
whenever(resolver.resolveInfo(any(), any(), any())).thenReturn(expectedInfo)
whenever(keyguardManager.isKeyguardLocked).thenReturn(expectedInfo.isKeyguardLocked)
whenever(activityManager.getRunningTasks(anyInt()))
.thenReturn(listOf(NOTE_RUNNING_TASK_INFO))
createNoteTaskController().showNoteTask(entryPoint = expectedInfo.entryPoint!!)
// Context package name used to create bubble icon from drawable resource id
verify(context, atLeastOnce()).packageName
verifyNoteTaskOpenInBubbleInUser(userTracker.userHandle) verifyNoteTaskOpenInBubbleInUser(userTracker.userHandle)
verifyZeroInteractions(eventLogger) verifyZeroInteractions(eventLogger)
} }

View File

@@ -16,37 +16,47 @@
package com.android.systemui.notetask package com.android.systemui.notetask
import android.os.UserHandle import android.os.UserHandle
import android.test.suitebuilder.annotation.SmallTest import android.testing.AndroidTestingRunner
import androidx.test.runner.AndroidJUnit4 import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase import com.android.systemui.SysuiTestCase
import com.android.systemui.notetask.NoteTaskEntryPoint.WIDGET_PICKER_SHORTCUT_IN_MULTI_WINDOW_MODE
import com.google.common.truth.Truth.assertThat import com.google.common.truth.Truth.assertThat
import org.junit.Test import org.junit.Test
import org.junit.runner.RunWith import org.junit.runner.RunWith
/** atest SystemUITests:NoteTaskInfoTest */ /** atest SystemUITests:NoteTaskInfoTest */
@SmallTest @SmallTest
@RunWith(AndroidJUnit4::class) @RunWith(AndroidTestingRunner::class)
internal class NoteTaskInfoTest : SysuiTestCase() { internal class NoteTaskInfoTest : SysuiTestCase() {
private fun createNoteTaskInfo(): NoteTaskInfo =
NoteTaskInfo(packageName = NOTES_PACKAGE_NAME, uid = NOTES_UID, UserHandle.of(0))
@Test @Test
fun launchMode_keyguardLocked_launchModeActivity() { fun launchMode_keyguardLocked_launchModeActivity() {
val underTest = createNoteTaskInfo().copy(isKeyguardLocked = true) val underTest = DEFAULT_INFO.copy(isKeyguardLocked = true)
assertThat(underTest.launchMode).isEqualTo(NoteTaskLaunchMode.Activity) assertThat(underTest.launchMode).isEqualTo(NoteTaskLaunchMode.Activity)
} }
@Test @Test
fun launchMode_keyguardUnlocked_launchModeActivity() { fun launchMode_multiWindowMode_launchModeActivity() {
val underTest = createNoteTaskInfo().copy(isKeyguardLocked = false) val underTest = DEFAULT_INFO.copy(entryPoint = WIDGET_PICKER_SHORTCUT_IN_MULTI_WINDOW_MODE)
assertThat(underTest.launchMode).isEqualTo(NoteTaskLaunchMode.Activity)
}
@Test
fun launchMode_keyguardUnlocked_launchModeAppBubble() {
val underTest = DEFAULT_INFO.copy(isKeyguardLocked = false)
assertThat(underTest.launchMode).isEqualTo(NoteTaskLaunchMode.AppBubble) assertThat(underTest.launchMode).isEqualTo(NoteTaskLaunchMode.AppBubble)
} }
private companion object { private companion object {
const val NOTES_PACKAGE_NAME = "com.android.note.app"
const val NOTES_UID = 123456 val DEFAULT_INFO =
NoteTaskInfo(
packageName = "com.android.note.app",
uid = 123456,
user = UserHandle.of(0),
)
} }
} }