Run update note task shortcut in a service if user is different
Shortcut Manager injects the main user, and do not allow us to set what user should have their shortcuts modified. To workaround that until we add support to custom users, we are launching a service and triggering the update task from that user's process. Running a different service may delay the update by a fraction of a second, in case the user jump into the home screen just after. Test: atest NoteTaskControllerTest Fixes: b/276889922 Change-Id: If503df7af038c51829e9267af7a9d0aafd7da986
This commit is contained in:
@@ -979,6 +979,8 @@
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<service android:name=".notetask.NoteTaskControllerUpdateService" />
|
||||
|
||||
<activity
|
||||
android:name=".notetask.shortcut.LaunchNoteTaskActivity"
|
||||
android:exported="true"
|
||||
|
||||
@@ -284,7 +284,15 @@ constructor(
|
||||
|
||||
/** @see OnRoleHoldersChangedListener */
|
||||
fun onRoleHoldersChanged(roleName: String, user: UserHandle) {
|
||||
if (roleName == ROLE_NOTES) updateNoteTaskAsUser(user)
|
||||
if (roleName != ROLE_NOTES) return
|
||||
|
||||
if (user == userTracker.userHandle) {
|
||||
updateNoteTaskAsUser(user)
|
||||
} else {
|
||||
// TODO(b/278729185): Replace fire and forget service with a bounded service.
|
||||
val intent = NoteTaskControllerUpdateService.createIntent(context)
|
||||
context.startServiceAsUser(intent, user)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* 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 androidx.lifecycle.LifecycleService
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
* A fire & forget service for updating note task shortcuts.
|
||||
*
|
||||
* The main use is to update shortcuts in different user by launching it using `startServiceAsUser`.
|
||||
* The service will open with access to a context from that user, trigger
|
||||
* [NoteTaskController.updateNoteTaskAsUser] and [stopSelf] immediately.
|
||||
*
|
||||
* The fire and forget approach was created due to its simplicity but may use unnecessary resources
|
||||
* by recreating the services. We will investigate its impacts and consider to move to a bounded
|
||||
* services - the implementation is more complex as a bounded service is asynchronous by default.
|
||||
*
|
||||
* TODO(b/278729185): Replace fire and forget service with a bounded service.
|
||||
*/
|
||||
@InternalNoteTaskApi
|
||||
class NoteTaskControllerUpdateService
|
||||
@Inject
|
||||
constructor(
|
||||
val controller: NoteTaskController,
|
||||
) : LifecycleService() {
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
// TODO(b/278729185): Replace fire and forget service with a bounded service.
|
||||
controller.updateNoteTaskAsUser(user)
|
||||
stopSelf()
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun createIntent(context: Context): Intent =
|
||||
Intent(context, NoteTaskControllerUpdateService::class.java)
|
||||
}
|
||||
}
|
||||
@@ -14,9 +14,12 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
@file:OptIn(InternalNoteTaskApi::class)
|
||||
|
||||
package com.android.systemui.notetask
|
||||
|
||||
import android.app.Activity
|
||||
import android.app.Service
|
||||
import android.app.role.RoleManager
|
||||
import com.android.systemui.flags.FeatureFlags
|
||||
import com.android.systemui.flags.Flags
|
||||
@@ -34,6 +37,9 @@ import dagger.multibindings.IntoMap
|
||||
@Module(includes = [NoteTaskQuickAffordanceModule::class])
|
||||
interface NoteTaskModule {
|
||||
|
||||
@[Binds IntoMap ClassKey(NoteTaskControllerUpdateService::class)]
|
||||
fun NoteTaskControllerUpdateService.bindNoteTaskControllerUpdateService(): Service
|
||||
|
||||
@[Binds IntoMap ClassKey(LaunchNoteTaskActivity::class)]
|
||||
fun LaunchNoteTaskActivity.bindNoteTaskLauncherActivity(): Activity
|
||||
|
||||
|
||||
@@ -620,6 +620,38 @@ internal class NoteTaskControllerTest : SysuiTestCase() {
|
||||
}
|
||||
}
|
||||
|
||||
// region onRoleHoldersChanged
|
||||
@Test
|
||||
fun onRoleHoldersChanged_notNotesRole_doNothing() {
|
||||
val user = UserHandle.of(0)
|
||||
|
||||
createNoteTaskController(isEnabled = true).onRoleHoldersChanged("NOT_NOTES", user)
|
||||
|
||||
verifyZeroInteractions(context)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun onRoleHoldersChanged_notesRole_sameUser_shouldUpdateShortcuts() {
|
||||
val user = userTracker.userHandle
|
||||
val controller = spy(createNoteTaskController())
|
||||
doNothing().whenever(controller).updateNoteTaskAsUser(any())
|
||||
|
||||
controller.onRoleHoldersChanged(ROLE_NOTES, user)
|
||||
|
||||
verify(controller).updateNoteTaskAsUser(user)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun onRoleHoldersChanged_notesRole_differentUser_shouldUpdateShortcutsInUserProcess() {
|
||||
// FakeUserTracker will default to UserHandle.SYSTEM.
|
||||
val user = UserHandle.CURRENT
|
||||
|
||||
createNoteTaskController(isEnabled = true).onRoleHoldersChanged(ROLE_NOTES, user)
|
||||
|
||||
verify(context).startServiceAsUser(any(), eq(user))
|
||||
}
|
||||
// endregion
|
||||
|
||||
// region updateNoteTaskAsUser
|
||||
@Test
|
||||
fun updateNoteTaskAsUser_withNotesRole_withShortcuts_shouldUpdateShortcuts() {
|
||||
|
||||
Reference in New Issue
Block a user