diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml index 0a9a1842dd775..0aa121dfcc497 100644 --- a/packages/SystemUI/AndroidManifest.xml +++ b/packages/SystemUI/AndroidManifest.xml @@ -996,7 +996,6 @@ android:name=".notetask.shortcut.LaunchNoteTaskActivity" android:exported="true" android:excludeFromRecents="true" - android:resizeableActivity="false" android:theme="@android:style/Theme.NoDisplay" > @@ -1012,7 +1011,6 @@ android:exported="false" android:enabled="true" android:excludeFromRecents="true" - android:resizeableActivity="false" android:theme="@android:style/Theme.NoDisplay" /> { - if (activityManager.isInForeground(info.packageName)) { + if (info.isKeyguardLocked && activityManager.isInForeground(info.packageName)) { // Force note task into background by calling home. val intent = createHomeIntent() context.startActivityAsUser(intent, user) diff --git a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskEntryPoint.kt b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskEntryPoint.kt index fae325cc3147d..442000281862c 100644 --- a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskEntryPoint.kt +++ b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskEntryPoint.kt @@ -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 * represent a "re-entry" (i.e., [APP_CLIPS]). */ -enum class -NoteTaskEntryPoint { +enum class NoteTaskEntryPoint { /** @see [LaunchNoteTaskActivity] */ WIDGET_PICKER_SHORTCUT, + /** @see [LaunchNoteTaskActivity] */ + WIDGET_PICKER_SHORTCUT_IN_MULTI_WINDOW_MODE, + /** @see [NoteTaskQuickAffordanceConfig] */ QUICK_AFFORDANCE, diff --git a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskEventLogger.kt b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskEventLogger.kt index 48a5933a60307..a79057e5464b5 100644 --- a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskEventLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskEventLogger.kt @@ -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.TAIL_BUTTON 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_SHORTCUT 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. */ fun logNoteTaskOpened(info: NoteTaskInfo) { val event = - when (info.entryPoint) { - TAIL_BUTTON -> { - if (info.isKeyguardLocked) { - NOTE_OPENED_VIA_STYLUS_TAIL_BUTTON_LOCKED - } else { - NOTE_OPENED_VIA_STYLUS_TAIL_BUTTON + when (info.entryPoint) { + TAIL_BUTTON -> { + if (info.isKeyguardLocked) { + NOTE_OPENED_VIA_STYLUS_TAIL_BUTTON_LOCKED + } else { + 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) } /** Logs a [NoteTaskInfo] as a **closed** [NoteTaskUiEvent], including package name and uid. */ fun logNoteTaskClosed(info: NoteTaskInfo) { val event = - when (info.entryPoint) { - TAIL_BUTTON -> { - if (info.isKeyguardLocked) { - NoteTaskUiEvent.NOTE_CLOSED_VIA_STYLUS_TAIL_BUTTON_LOCKED - } else { - NoteTaskUiEvent.NOTE_CLOSED_VIA_STYLUS_TAIL_BUTTON + when (info.entryPoint) { + TAIL_BUTTON -> { + if (info.isKeyguardLocked) { + NoteTaskUiEvent.NOTE_CLOSED_VIA_STYLUS_TAIL_BUTTON_LOCKED + } else { + 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) } diff --git a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskInfo.kt b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskInfo.kt index a75834760d300..269eb870686c9 100644 --- a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskInfo.kt +++ b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskInfo.kt @@ -16,6 +16,7 @@ package com.android.systemui.notetask 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]. */ data class NoteTaskInfo( @@ -27,7 +28,7 @@ data class NoteTaskInfo( ) { val launchMode: NoteTaskLaunchMode = - if (isKeyguardLocked) { + if (isKeyguardLocked || entryPoint == WIDGET_PICKER_SHORTCUT_IN_MULTI_WINDOW_MODE) { NoteTaskLaunchMode.Activity } else { NoteTaskLaunchMode.AppBubble diff --git a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskRoleManagerExt.kt b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskRoleManagerExt.kt index 441b9f5d01819..754c3650a5ed2 100644 --- a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskRoleManagerExt.kt +++ b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskRoleManagerExt.kt @@ -51,7 +51,8 @@ internal object NoteTaskRoleManagerExt { val icon = Icon.createWithResource(context, R.drawable.ic_note_task_shortcut_widget) 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)) .setLongLived(true) .setIcon(icon) diff --git a/packages/SystemUI/src/com/android/systemui/notetask/shortcut/LaunchNoteTaskActivity.kt b/packages/SystemUI/src/com/android/systemui/notetask/shortcut/LaunchNoteTaskActivity.kt index 8ca13b9776bb8..7ef149de2794b 100644 --- a/packages/SystemUI/src/com/android/systemui/notetask/shortcut/LaunchNoteTaskActivity.kt +++ b/packages/SystemUI/src/com/android/systemui/notetask/shortcut/LaunchNoteTaskActivity.kt @@ -16,6 +16,7 @@ package com.android.systemui.notetask.shortcut +import android.content.ComponentName import android.content.Context import android.content.Intent import android.os.Bundle @@ -72,7 +73,13 @@ constructor( controller.startNoteTaskProxyActivityForUser(mainUser) } } 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() } @@ -80,11 +87,14 @@ constructor( companion object { /** Creates a new [Intent] set to start [LaunchNoteTaskActivity]. */ - fun newIntent(context: Context): Intent { - return Intent(context, LaunchNoteTaskActivity::class.java).apply { + fun createIntent(context: Context): Intent = + Intent(context, LaunchNoteTaskActivity::class.java).apply { // Intent's action must be set in shortcuts, or an exception will be thrown. action = Intent.ACTION_CREATE_NOTE } - } + + /** Creates a new [ComponentName] for [LaunchNoteTaskActivity]. */ + fun createComponent(context: Context): ComponentName = + ComponentName(context, LaunchNoteTaskActivity::class.java) } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskControllerTest.kt index e99f8b6aa47b7..0954f6f0ffafe 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskControllerTest.kt @@ -72,6 +72,7 @@ import org.junit.Test import org.junit.runner.RunWith import org.mockito.ArgumentMatchers.anyInt import org.mockito.Mock +import org.mockito.Mockito.atLeastOnce import org.mockito.Mockito.doNothing import org.mockito.Mockito.never import org.mockito.Mockito.spy @@ -227,31 +228,7 @@ internal class NoteTaskControllerTest : SysuiTestCase() { // region showNoteTask @Test - fun showNoteTask_keyguardIsLocked_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() - val userCaptor = argumentCaptor() - 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() { + fun showNoteTaskAsUser_keyguardIsLocked_shouldStartActivityWithExpectedUserAndLogUiEvent() { val user10 = UserHandle.of(/* userId= */ 10) val expectedInfo = NOTE_TASK_INFO.copy(entryPoint = TAIL_BUTTON, isKeyguardLocked = true, user = user10) @@ -277,6 +254,30 @@ internal class NoteTaskControllerTest : SysuiTestCase() { 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() + val userCaptor = argumentCaptor() + 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 showNoteTask_keyguardIsLocked_noteIsOpen_shouldCloseActivityAndLogUiEvent() { val expectedInfo = NOTE_TASK_INFO.copy(entryPoint = TAIL_BUTTON, isKeyguardLocked = true) @@ -301,7 +302,7 @@ internal class NoteTaskControllerTest : SysuiTestCase() { } @Test - fun showNoteTask_keyguardIsUnlocked_shouldStartBubblesWithoutLoggingUiEvent() { + fun showNoteTask_keyguardIsUnlocked_noteIsClosed_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) @@ -309,7 +310,23 @@ internal class NoteTaskControllerTest : SysuiTestCase() { createNoteTaskController().showNoteTask(entryPoint = expectedInfo.entryPoint!!) // 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) verifyZeroInteractions(eventLogger) } diff --git a/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskInfoTest.kt b/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskInfoTest.kt index 34354504abf04..24f39d187f882 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskInfoTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskInfoTest.kt @@ -16,37 +16,47 @@ package com.android.systemui.notetask import android.os.UserHandle -import android.test.suitebuilder.annotation.SmallTest -import androidx.test.runner.AndroidJUnit4 +import android.testing.AndroidTestingRunner +import androidx.test.filters.SmallTest 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 org.junit.Test import org.junit.runner.RunWith /** atest SystemUITests:NoteTaskInfoTest */ @SmallTest -@RunWith(AndroidJUnit4::class) +@RunWith(AndroidTestingRunner::class) internal class NoteTaskInfoTest : SysuiTestCase() { - private fun createNoteTaskInfo(): NoteTaskInfo = - NoteTaskInfo(packageName = NOTES_PACKAGE_NAME, uid = NOTES_UID, UserHandle.of(0)) - @Test fun launchMode_keyguardLocked_launchModeActivity() { - val underTest = createNoteTaskInfo().copy(isKeyguardLocked = true) + val underTest = DEFAULT_INFO.copy(isKeyguardLocked = true) assertThat(underTest.launchMode).isEqualTo(NoteTaskLaunchMode.Activity) } @Test - fun launchMode_keyguardUnlocked_launchModeActivity() { - val underTest = createNoteTaskInfo().copy(isKeyguardLocked = false) + fun launchMode_multiWindowMode_launchModeActivity() { + 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) } 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), + ) } }