Merge "Add support for flag change listeners library." into sc-v2-dev am: c61d506a90 am: 6a9f7f79f6
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/16182385 Change-Id: Ic4e7ec1b6b80e6690d06c50e66751ee4162d48ae
This commit is contained in:
@@ -83,8 +83,7 @@ android_library {
|
||||
"src/**/*.kt",
|
||||
"src/**/*.java",
|
||||
"src/**/I*.aidl",
|
||||
"src-release/**/*.kt",
|
||||
"src-release/**/*.java",
|
||||
":ReleaseJavaFiles",
|
||||
],
|
||||
product_variables: {
|
||||
debuggable: {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
# SystemUI Plugins
|
||||
|
||||
Plugins provide an easy way to rapidly prototype SystemUI features. Plugins are APKs that will be installable only on Build.IS_DEBUGGABLE (dogfood) builds, that can change the behavior of SystemUI at runtime. This is done by creating a basic set of interfaces that the plugins can expect to be in SysUI, then the portion of code controlled by the interface can be iterated on faster than currently.
|
||||
|
||||
@@ -75,10 +75,10 @@ java_library {
|
||||
static_kotlin_stdlib: false,
|
||||
libs: [
|
||||
"androidx.concurrent_concurrent-futures",
|
||||
"SystemUI-flags",
|
||||
],
|
||||
static_libs: [
|
||||
"SystemUI-flag-types",
|
||||
"SystemUI-flags",
|
||||
],
|
||||
java_version: "1.8",
|
||||
min_sdk_version: "current",
|
||||
|
||||
@@ -18,13 +18,19 @@ package com.android.systemui.flags
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.database.ContentObserver
|
||||
import android.net.Uri
|
||||
import android.os.Handler
|
||||
import android.provider.Settings
|
||||
import androidx.concurrent.futures.CallbackToFutureAdapter
|
||||
import com.google.common.util.concurrent.ListenableFuture
|
||||
import org.json.JSONException
|
||||
import org.json.JSONObject
|
||||
|
||||
class FlagManager constructor(val context: Context) : FlagReader {
|
||||
class FlagManager constructor(
|
||||
private val context: Context,
|
||||
private val handler: Handler
|
||||
) : FlagReader {
|
||||
companion object {
|
||||
const val RECEIVING_PACKAGE = "com.android.systemui"
|
||||
const val ACTION_SET_FLAG = "com.android.systemui.action.SET_FLAG"
|
||||
@@ -36,6 +42,9 @@ class FlagManager constructor(val context: Context) : FlagReader {
|
||||
private const val SETTINGS_PREFIX = "systemui/flags"
|
||||
}
|
||||
|
||||
private val listeners: MutableSet<FlagReader.Listener> = mutableSetOf()
|
||||
private val settingsObserver: ContentObserver = SettingsObserver()
|
||||
|
||||
fun getFlagsFuture(): ListenableFuture<Collection<Flag<*>>> {
|
||||
val knownFlagMap = Flags.collectFlags()
|
||||
// Possible todo in the future: query systemui async to actually get the known flag ids.
|
||||
@@ -82,6 +91,27 @@ class FlagManager constructor(val context: Context) : FlagReader {
|
||||
}
|
||||
}
|
||||
|
||||
override fun addListener(listener: FlagReader.Listener) {
|
||||
synchronized(listeners) {
|
||||
val registerNeeded = listeners.isEmpty()
|
||||
listeners.add(listener)
|
||||
if (registerNeeded) {
|
||||
context.contentResolver.registerContentObserver(
|
||||
Settings.Secure.getUriFor(SETTINGS_PREFIX), true, settingsObserver)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun removeListener(listener: FlagReader.Listener) {
|
||||
synchronized(listeners) {
|
||||
val isRegistered = !listeners.isEmpty()
|
||||
listeners.remove(listener)
|
||||
if (isRegistered && listeners.isEmpty()) {
|
||||
context.contentResolver.unregisterContentObserver(settingsObserver)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun createIntent(id: Int): Intent {
|
||||
val intent = Intent(ACTION_SET_FLAG)
|
||||
intent.setPackage(RECEIVING_PACKAGE)
|
||||
@@ -90,7 +120,7 @@ class FlagManager constructor(val context: Context) : FlagReader {
|
||||
return intent
|
||||
}
|
||||
|
||||
fun keyToSettingsPrefix(key: Int): String? {
|
||||
fun keyToSettingsPrefix(key: Int): String {
|
||||
return SETTINGS_PREFIX + "/" + key
|
||||
}
|
||||
|
||||
@@ -101,6 +131,22 @@ class FlagManager constructor(val context: Context) : FlagReader {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
inner class SettingsObserver : ContentObserver(handler) {
|
||||
override fun onChange(selfChange: Boolean, uri: Uri?) {
|
||||
if (uri == null) {
|
||||
return
|
||||
}
|
||||
val parts = uri.pathSegments
|
||||
val idStr = parts[parts.size - 1]
|
||||
try {
|
||||
val id = idStr.toInt()
|
||||
listeners.forEach { l -> l.onFlagChanged(id) }
|
||||
} catch (e: NumberFormatException) {
|
||||
// no-op
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class InvalidFlagStorageException : Exception("Data found but is invalid")
|
||||
@@ -31,7 +31,7 @@ interface FlagReader {
|
||||
fun removeListener(listener: Listener) {}
|
||||
|
||||
/** A simple listener to be alerted when a flag changes. */
|
||||
interface Listener {
|
||||
fun interface Listener {
|
||||
/** */
|
||||
fun onFlagChanged(id: Int)
|
||||
}
|
||||
|
||||
@@ -129,10 +129,14 @@ public class FeatureFlagManager implements FlagReader, FlagWriter, Dumpable {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addListener(Listener run) {}
|
||||
public void addListener(Listener run) {
|
||||
mFlagManager.addListener(run);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeListener(Listener run) {}
|
||||
public void removeListener(Listener run) {
|
||||
mFlagManager.removeListener(run);
|
||||
}
|
||||
|
||||
private void restartSystemUI() {
|
||||
Log.i(TAG, "Restarting SystemUI");
|
||||
|
||||
@@ -17,14 +17,19 @@
|
||||
package com.android.systemui.flags
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Handler
|
||||
import com.android.systemui.dagger.qualifiers.Main
|
||||
import com.android.systemui.util.settings.SettingsUtilModule
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
|
||||
@Module
|
||||
@Module(includes = [
|
||||
SettingsUtilModule::class
|
||||
])
|
||||
object FlagsModule {
|
||||
@JvmStatic
|
||||
@Provides
|
||||
fun provideFlagManager(context: Context): FlagManager {
|
||||
return FlagManager(context)
|
||||
fun provideFlagManager(context: Context, @Main handler: Handler): FlagManager {
|
||||
return FlagManager(context, handler)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user