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

Commit e4b01812 authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "[Catalyst] Remove UserManager.addUserRestrictionsListener usage" into main

parents 42e47f1a 2043c1e7
Loading
Loading
Loading
Loading
+0 −8
Original line number Diff line number Diff line
@@ -17,7 +17,6 @@
package com.android.settings;

import static com.android.settings.SettingsActivity.EXTRA_FRAGMENT_ARG_KEY;
import static com.android.settingslib.media.PhoneMediaDevice.isDesktop;

import android.app.Activity;
import android.app.Dialog;
@@ -187,13 +186,6 @@ public abstract class SettingsPreferenceFragment extends InstrumentedPreferenceF

    /** Returns if catalyst is enabled on current screen. */
    public final boolean isCatalystEnabled() {
        // TODO(b/379130874): make Catalyst compatible with desktop device, such as user restriction
        // check.
        Context context = getContext();
        if (context != null && isDesktop(context)) {
            return false;
        }

        return getPreferenceScreenCreator() != null;
    }

+17 −15
Original line number Diff line number Diff line
@@ -25,9 +25,9 @@ import com.android.settingslib.preference.PreferenceScreenBindingHelper.Companio

/** Helper to rebind preference immediately when user restriction is changed. */
class UserRestrictionBindingHelper(
    context: Context,
    private val context: Context,
    private val screenBindingHelper: PreferenceScreenBindingHelper,
) : AutoCloseable {
) : KeyedObserver<String>, AutoCloseable {
    private val restrictionKeysToPreferenceKeys: Map<String, MutableSet<String>> =
        mutableMapOf<String, MutableSet<String>>()
            .apply {
@@ -42,27 +42,29 @@ class UserRestrictionBindingHelper(
            }
            .toMap()

    private val userRestrictionObserver: KeyedObserver<String?>?

    init {
        if (restrictionKeysToPreferenceKeys.isEmpty()) {
            userRestrictionObserver = null
        } else {
            val observer =
                KeyedObserver<String?> { restrictionKey, _ ->
                    restrictionKey?.let { notifyRestrictionChanged(it) }
        val restrictionKeys = restrictionKeysToPreferenceKeys.keys
        if (restrictionKeys.isNotEmpty()) {
            val userRestrictions = UserRestrictions.get(context)
            val executor = HandlerExecutor.main
            for (restrictionKey in restrictionKeys) {
                userRestrictions.addObserver(restrictionKey, this, executor)
            }
            UserRestrictions.addObserver(context, observer, HandlerExecutor.main)
            userRestrictionObserver = observer
        }
    }

    private fun notifyRestrictionChanged(restrictionKey: String) {
    override fun onKeyChanged(restrictionKey: String, reason: Int) {
        val keys = restrictionKeysToPreferenceKeys[restrictionKey] ?: return
        for (key in keys) screenBindingHelper.notifyChange(key, CHANGE_REASON_STATE)
    }

    override fun close() {
        userRestrictionObserver?.let { UserRestrictions.removeObserver(it) }
        val restrictionKeys = restrictionKeysToPreferenceKeys.keys
        if (restrictionKeys.isNotEmpty()) {
            val userRestrictions = UserRestrictions.get(context)
            for (restrictionKey in restrictionKeys) {
                userRestrictions.removeObserver(restrictionKey, this)
            }
        }
    }
}
+34 −44
Original line number Diff line number Diff line
@@ -16,68 +16,58 @@

package com.android.settings.restriction

import android.content.BroadcastReceiver
import android.content.Context
import android.os.Bundle
import android.os.IUserRestrictionsListener
import android.content.Intent
import android.content.IntentFilter
import android.os.UserManager
import com.android.settingslib.datastore.KeyedDataObservable
import com.android.settingslib.datastore.AbstractKeyedDataObservable
import com.android.settingslib.datastore.DataChangeReason
import com.android.settingslib.datastore.KeyedObserver
import java.util.concurrent.Executor
import java.util.concurrent.atomic.AtomicBoolean

/** Helper class to monitor user restriction changes. */
object UserRestrictions {
    private val observable = KeyedDataObservable<String>()
class UserRestrictions private constructor(private val applicationContext: Context) {

    private val userRestrictionsListener =
        object : IUserRestrictionsListener.Stub() {
            override fun onUserRestrictionsChanged(
                userId: Int,
                newRestrictions: Bundle,
                prevRestrictions: Bundle,
            ) {
                // there is no API to remove listener, do a quick check to avoid unnecessary work
                if (!observable.hasAnyObserver()) return
    private val observable =
        object : AbstractKeyedDataObservable<String>() {
            override fun onFirstObserverAdded() {
                val intentFilter = IntentFilter()
                intentFilter.addAction(UserManager.ACTION_USER_RESTRICTIONS_CHANGED)
                applicationContext.registerReceiver(broadcastReceiver, intentFilter)
            }

                val changedKeys = mutableSetOf<String>()
                val keys = newRestrictions.keySet() + prevRestrictions.keySet()
                for (key in keys) {
                    if (newRestrictions.getBoolean(key) != prevRestrictions.getBoolean(key)) {
                        changedKeys.add(key)
            override fun onLastObserverRemoved() {
                applicationContext.unregisterReceiver(broadcastReceiver)
            }
        }

                for (key in changedKeys) observable.notifyChange(key, 0)
    private val broadcastReceiver: BroadcastReceiver =
        object : BroadcastReceiver() {
            override fun onReceive(context: Context, intent: Intent) {
                // there is no way to get the changed keys, just notify all observers
                observable.notifyChange(DataChangeReason.UPDATE)
            }
        }

    private val listenerAdded = AtomicBoolean()

    fun addObserver(context: Context, observer: KeyedObserver<String?>, executor: Executor) {
        context.addUserRestrictionsListener()
    fun addObserver(observer: KeyedObserver<String?>, executor: Executor) =
        observable.addObserver(observer, executor)
    }

    fun addObserver(
        context: Context,
        key: String,
        observer: KeyedObserver<String>,
        executor: Executor,
    ) {
        context.addUserRestrictionsListener()
    fun addObserver(key: String, observer: KeyedObserver<String>, executor: Executor) =
        observable.addObserver(key, observer, executor)
    }

    private fun Context.addUserRestrictionsListener() {
        if (listenerAdded.getAndSet(true)) return
        // surprisingly, there is no way to remove the listener
        applicationContext
            .getSystemService(UserManager::class.java)
            .addUserRestrictionsListener(userRestrictionsListener)
    }

    fun removeObserver(observer: KeyedObserver<String?>) = observable.removeObserver(observer)

    fun removeObserver(key: String, observer: KeyedObserver<String>) =
        observable.removeObserver(key, observer)

    companion object {
        @Volatile private var instance: UserRestrictions? = null

        fun get(context: Context) =
            instance
                ?: synchronized(this) {
                    instance ?: UserRestrictions(context.applicationContext).also { instance = it }
                }
    }
}