Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c2beb67c authored by Marcello Galhardo's avatar Marcello Galhardo
Browse files

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
parent 70898897
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -979,6 +979,8 @@
            </intent-filter>
        </activity>

        <service android:name=".notetask.NoteTaskControllerUpdateService" />

        <activity
            android:name=".notetask.shortcut.LaunchNoteTaskActivity"
            android:exported="true"
+9 −1
Original line number Diff line number Diff line
@@ -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 {
+55 −0
Original line number Diff line number Diff line
/*
 * 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)
    }
}
+6 −0
Original line number Diff line number Diff line
@@ -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

+32 −0
Original line number Diff line number Diff line
@@ -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() {