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

Commit d5f33804 authored by Bharat Singh's avatar Bharat Singh
Browse files

[SysUI][Floaty] Add a flow to detect change in active user or assistant

* Add a flow which combines active user flow and active assistant flow
* Cache active user and assistant to compare it against the saved
  preference later to check they were set for which user and assistant

Bug: 412616963
Test: NONE just introducing a flow, tests will be added in later CLs
Flag: com.android.systemui.shared.enable_lpp_assist_invocation_effect

Change-Id: Ie8c8f20df8a3650617aa2b1e7c65cb6ce7b3e18f
parent 675677cf
Loading
Loading
Loading
Loading
+68 −7
Original line number Original line Diff line number Diff line
@@ -16,18 +16,33 @@


package com.android.systemui.topwindoweffects.data.repository
package com.android.systemui.topwindoweffects.data.repository


import android.annotation.SuppressLint
import android.app.role.OnRoleHoldersChangedListener
import android.app.role.RoleManager
import android.content.Context
import android.content.Context
import android.content.SharedPreferences
import android.content.SharedPreferences
import android.os.UserHandle
import androidx.core.content.edit
import androidx.core.content.edit
import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.user.data.repository.UserRepository
import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow
import java.util.concurrent.Executor
import javax.inject.Inject
import javax.inject.Inject
import kotlin.coroutines.CoroutineContext
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.launch
import kotlinx.coroutines.launch


interface InvocationEffectPreferences {
interface InvocationEffectPreferences {


    val activeUserOrAssistantChanged: Flow<Boolean>

    fun saveCurrentAssistant()
    fun saveCurrentAssistant()


    fun saveCurrentUserId()
    fun saveCurrentUserId()
@@ -52,17 +67,56 @@ interface InvocationEffectPreferences {
@SysUISingleton
@SysUISingleton
class InvocationEffectPreferencesImpl
class InvocationEffectPreferencesImpl
@Inject
@Inject
constructor(@Application context: Context, @Background private val bgScope: CoroutineScope) :
constructor(
    InvocationEffectPreferences {
    @Application context: Context,

    @Background private val bgScope: CoroutineScope,
    // TODO(b/33606670): Detect change in current active user and assistant
    private val userRepository: UserRepository,
    private var activeUser: Int = Int.MIN_VALUE
    roleManager: RoleManager,
    private var activeAssistant = ""
    @Background executor: Executor,
    @Background coroutineContext: CoroutineContext,
) : InvocationEffectPreferences {


    private val sharedPreferences by lazy {
    private val sharedPreferences by lazy {
        context.getSharedPreferences(SHARED_PREFERENCES_FILE_NAME, Context.MODE_PRIVATE)
        context.getSharedPreferences(SHARED_PREFERENCES_FILE_NAME, Context.MODE_PRIVATE)
    }
    }


    private var activeUser: Int = userRepository.selectedUserHandle.identifier
    private var activeAssistant: String =
        roleManager.getCurrentAssistantFor(userRepository.selectedUserHandle)

    override val activeUserOrAssistantChanged: Flow<Boolean> =
        conflatedCallbackFlow {
                val listener = OnRoleHoldersChangedListener { roleName, _ ->
                    if (roleName == RoleManager.ROLE_ASSISTANT) {
                        trySendWithFailureLogging(
                            roleManager.getCurrentAssistantFor(userRepository.selectedUserHandle),
                            TAG,
                            "updated currentlyActiveAssistantName due to role change",
                        )
                    }
                }

                roleManager.addOnRoleHoldersChangedListenerAsUser(
                    executor,
                    listener,
                    UserHandle.ALL,
                )

                awaitClose {
                    roleManager.removeOnRoleHoldersChangedListenerAsUser(listener, UserHandle.ALL)
                }
            }
            .flowOn(coroutineContext)
            .combine(userRepository.selectedUser) { assistant, user ->
                val userId = user.userInfo.userHandle.identifier
                val changed = activeUser != userId || activeAssistant != assistant
                if (changed) {
                    activeUser = userId
                    activeAssistant = assistant
                }
                changed
            }

    override fun saveCurrentAssistant() {
    override fun saveCurrentAssistant() {
        setInPreferences { putString(PERSISTED_FOR_ASSISTANT_PREFERENCE, activeAssistant) }
        setInPreferences { putString(PERSISTED_FOR_ASSISTANT_PREFERENCE, activeAssistant) }
    }
    }
@@ -158,7 +212,7 @@ constructor(@Application context: Context, @Background private val bgScope: Coro
                    Long::class -> sharedPreferences.getLong(key, default as Long)
                    Long::class -> sharedPreferences.getLong(key, default as Long)
                    Boolean::class -> sharedPreferences.getBoolean(key, default as Boolean)
                    Boolean::class -> sharedPreferences.getBoolean(key, default as Boolean)
                    String::class -> sharedPreferences.getString(key, default as String)
                    String::class -> sharedPreferences.getString(key, default as String)
                    else -> null
                    else -> /* type not supported */ null
                }
                }
            } catch (e: ClassCastException /* ignore */) {
            } catch (e: ClassCastException /* ignore */) {
                null
                null
@@ -204,3 +258,10 @@ constructor(@Application context: Context, @Background private val bgScope: Coro
        const val DEFAULT_OUTWARD_EFFECT_DURATION_MS = 400L
        const val DEFAULT_OUTWARD_EFFECT_DURATION_MS = 400L
    }
    }
}
}

private val UserRepository.selectedUserHandle
    get() = selectedUser.value.userInfo.userHandle

@SuppressLint("MissingPermission")
private fun RoleManager.getCurrentAssistantFor(userHandle: UserHandle) =
    getRoleHoldersAsUser(RoleManager.ROLE_ASSISTANT, userHandle).firstOrNull() ?: ""