Default to the work profile notes app on COPE devices

The default to the work profile notes app on COPE devices only applies
to `TAIL_BUTTON` & `QUICK_AFFORDANCE` entry points, which don't allow
users to select the work or personal default notes app to be launched.

Test: atest SystemUITests:com.android.systemui.notetask.NoteTaskControllerTest
Bug: 259952057

Change-Id: I572b00e17c4b4296952ab0807a262cd79b8a0527
This commit is contained in:
Steven Ng
2023-03-24 12:25:46 +00:00
parent 55a6e8d0d2
commit 5fff477859
2 changed files with 101 additions and 24 deletions

View File

@@ -107,11 +107,30 @@ 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,
) {
showNoteTaskAsUser(entryPoint, userTracker.userHandle)
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)
}
/** A variant of [showNoteTask] which launches note task in the given [user]. */
@@ -149,7 +168,7 @@ constructor(
when (info.launchMode) {
is NoteTaskLaunchMode.AppBubble -> {
// TODO: provide app bubble icon
bubbles.showOrHideAppBubble(intent, userTracker.userHandle, null /* icon */)
bubbles.showOrHideAppBubble(intent, user, null /* icon */)
// App bubble logging happens on `onBubbleExpandChanged`.
logDebug { "onShowNoteTask - opened as app bubble: $info" }
}
@@ -239,6 +258,16 @@ constructor(
* @see com.android.launcher3.icons.IconCache.EXTRA_SHORTCUT_BADGE_OVERRIDE_PACKAGE
*/
const val EXTRA_SHORTCUT_BADGE_OVERRIDE_PACKAGE = "extra_shortcut_badge_override_package"
/**
* A list of entry points which should be redirected to the work profile default notes app
* on company owned personally enabled (COPE) devices.
*
* Entry points in this list don't let users / admin to select the work or personal default
* notes app to be launched.
*/
val FORCE_WORK_NOTE_APPS_ENTRY_POINTS_ON_COPE_DEVICES =
listOf(NoteTaskEntryPoint.TAIL_BUTTON, NoteTaskEntryPoint.QUICK_AFFORDANCE)
}
}

View File

@@ -33,6 +33,7 @@ import android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED
import android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED
import android.content.pm.ShortcutInfo
import android.content.pm.ShortcutManager
import android.content.pm.UserInfo
import android.os.UserHandle
import android.os.UserManager
import androidx.test.filters.SmallTest
@@ -44,7 +45,6 @@ import com.android.systemui.notetask.NoteTaskController.Companion.SHORTCUT_ID
import com.android.systemui.notetask.shortcut.CreateNoteTaskShortcutActivity
import com.android.systemui.notetask.shortcut.LaunchNoteTaskActivity
import com.android.systemui.settings.FakeUserTracker
import com.android.systemui.settings.UserTracker
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.argumentCaptor
import com.android.systemui.util.mockito.capture
@@ -81,7 +81,7 @@ internal class NoteTaskControllerTest : SysuiTestCase() {
@Mock private lateinit var shortcutManager: ShortcutManager
@Mock private lateinit var activityManager: ActivityManager
@Mock private lateinit var devicePolicyManager: DevicePolicyManager
private val userTracker: UserTracker = FakeUserTracker()
private val userTracker = FakeUserTracker()
@Before
fun setUp() {
@@ -102,6 +102,7 @@ internal class NoteTaskControllerTest : SysuiTestCase() {
whenever(roleManager.getRoleHoldersAsUser(ROLE_NOTES, userTracker.userHandle))
.thenReturn(listOf(NOTE_TASK_PACKAGE_NAME))
whenever(activityManager.getRunningTasks(anyInt())).thenReturn(emptyList())
whenever(userManager.isManagedProfile(workUserInfo.id)).thenReturn(true)
}
private fun createNoteTaskController(
@@ -308,15 +309,7 @@ internal class NoteTaskControllerTest : SysuiTestCase() {
)
verifyZeroInteractions(context)
val intentCaptor = argumentCaptor<Intent>()
verify(bubbles)
.showOrHideAppBubble(capture(intentCaptor), eq(userTracker.userHandle), isNull())
intentCaptor.value.let { intent ->
assertThat(intent.action).isEqualTo(Intent.ACTION_CREATE_NOTE)
assertThat(intent.`package`).isEqualTo(NOTE_TASK_PACKAGE_NAME)
assertThat(intent.flags).isEqualTo(FLAG_ACTIVITY_NEW_TASK)
assertThat(intent.getBooleanExtra(Intent.EXTRA_USE_STYLUS_MODE, false)).isTrue()
}
verifyNoteTaskOpenInBubbleInUser(userTracker.userHandle)
verifyZeroInteractions(eventLogger)
}
@@ -443,15 +436,7 @@ internal class NoteTaskControllerTest : SysuiTestCase() {
createNoteTaskController().showNoteTask(entryPoint = NoteTaskEntryPoint.QUICK_AFFORDANCE)
val intentCaptor = argumentCaptor<Intent>()
verify(bubbles)
.showOrHideAppBubble(capture(intentCaptor), eq(userTracker.userHandle), isNull())
intentCaptor.value.let { intent ->
assertThat(intent.action).isEqualTo(Intent.ACTION_CREATE_NOTE)
assertThat(intent.`package`).isEqualTo(NOTE_TASK_PACKAGE_NAME)
assertThat(intent.flags).isEqualTo(FLAG_ACTIVITY_NEW_TASK)
assertThat(intent.getBooleanExtra(Intent.EXTRA_USE_STYLUS_MODE, false)).isTrue()
}
verifyNoteTaskOpenInBubbleInUser(userTracker.userHandle)
}
@Test
@@ -467,9 +452,67 @@ internal class NoteTaskControllerTest : SysuiTestCase() {
createNoteTaskController().showNoteTask(entryPoint = NoteTaskEntryPoint.QUICK_AFFORDANCE)
verifyNoteTaskOpenInBubbleInUser(userTracker.userHandle)
}
// endregion
// region showNoteTask, COPE devices
@Test
fun showNoteTask_copeDevices_quickAffordanceEntryPoint_managedProfileNotFound_shouldStartBubbleInTheMainProfile() { // ktlint-disable max-line-length
whenever(devicePolicyManager.isOrganizationOwnedDeviceWithManagedProfile).thenReturn(true)
userTracker.set(listOf(mainUserInfo), mainAndWorkProfileUsers.indexOf(mainUserInfo))
createNoteTaskController().showNoteTask(entryPoint = NoteTaskEntryPoint.QUICK_AFFORDANCE)
verifyNoteTaskOpenInBubbleInUser(mainUserInfo.userHandle)
}
@Test
fun showNoteTask_copeDevices_quickAffordanceEntryPoint_shouldStartBubbleInWorkProfile() {
whenever(devicePolicyManager.isOrganizationOwnedDeviceWithManagedProfile).thenReturn(true)
userTracker.set(mainAndWorkProfileUsers, mainAndWorkProfileUsers.indexOf(mainUserInfo))
createNoteTaskController().showNoteTask(entryPoint = NoteTaskEntryPoint.QUICK_AFFORDANCE)
verifyNoteTaskOpenInBubbleInUser(workUserInfo.userHandle)
}
@Test
fun showNoteTask_copeDevices_tailButtonEntryPoint_shouldStartBubbleInWorkProfile() {
whenever(devicePolicyManager.isOrganizationOwnedDeviceWithManagedProfile).thenReturn(true)
userTracker.set(mainAndWorkProfileUsers, mainAndWorkProfileUsers.indexOf(mainUserInfo))
createNoteTaskController().showNoteTask(entryPoint = NoteTaskEntryPoint.TAIL_BUTTON)
verifyNoteTaskOpenInBubbleInUser(workUserInfo.userHandle)
}
@Test
fun showNoteTask_copeDevices_shortcutsEntryPoint_shouldStartBubbleInTheSelectedUser() {
whenever(devicePolicyManager.isOrganizationOwnedDeviceWithManagedProfile).thenReturn(true)
userTracker.set(mainAndWorkProfileUsers, mainAndWorkProfileUsers.indexOf(mainUserInfo))
createNoteTaskController()
.showNoteTask(entryPoint = NoteTaskEntryPoint.WIDGET_PICKER_SHORTCUT)
verifyNoteTaskOpenInBubbleInUser(mainUserInfo.userHandle)
}
@Test
fun showNoteTask_copeDevices_appClipsEntryPoint_shouldStartBubbleInTheSelectedUser() {
whenever(devicePolicyManager.isOrganizationOwnedDeviceWithManagedProfile).thenReturn(true)
userTracker.set(mainAndWorkProfileUsers, mainAndWorkProfileUsers.indexOf(mainUserInfo))
createNoteTaskController().showNoteTask(entryPoint = NoteTaskEntryPoint.APP_CLIPS)
verifyNoteTaskOpenInBubbleInUser(mainUserInfo.userHandle)
}
// endregion
private fun verifyNoteTaskOpenInBubbleInUser(userHandle: UserHandle) {
val intentCaptor = argumentCaptor<Intent>()
verify(bubbles)
.showOrHideAppBubble(capture(intentCaptor), eq(userTracker.userHandle), isNull())
.showOrHideAppBubble(capture(intentCaptor), eq(userHandle), /* icon = */ isNull())
intentCaptor.value.let { intent ->
assertThat(intent.action).isEqualTo(Intent.ACTION_CREATE_NOTE)
assertThat(intent.`package`).isEqualTo(NOTE_TASK_PACKAGE_NAME)
@@ -477,7 +520,6 @@ internal class NoteTaskControllerTest : SysuiTestCase() {
assertThat(intent.getBooleanExtra(Intent.EXTRA_USE_STYLUS_MODE, false)).isTrue()
}
}
// endregion
// region updateNoteTaskAsUser
@Test
@@ -564,5 +606,11 @@ internal class NoteTaskControllerTest : SysuiTestCase() {
ActivityManager.RunningTaskInfo().apply {
topActivity = ComponentName(NOTE_TASK_PACKAGE_NAME, NOTE_TASK_ACTIVITY_NAME)
}
val mainUserInfo =
UserInfo(/* id= */ 0, /* name= */ "primary", /* flags= */ UserInfo.FLAG_MAIN)
val workUserInfo =
UserInfo(/* id= */ 10, /* name= */ "work", /* flags= */ UserInfo.FLAG_PROFILE)
val mainAndWorkProfileUsers = listOf(mainUserInfo, workUserInfo)
}
}