Loading packages/SystemUI/Android.bp +0 −12 Original line number Diff line number Diff line Loading @@ -50,17 +50,6 @@ java_library { srcs: ["src/com/android/systemui/EventLogTags.logtags"], } java_library { name: "SystemUI-flags", srcs: [ "src/com/android/systemui/flags/Flags.java", ], libs: [ "SystemUI-flag-types", ], static_kotlin_stdlib: false, } filegroup { name: "ReleaseJavaFiles", srcs: [ Loading Loading @@ -127,7 +116,6 @@ android_library { "iconloader_base", "SystemUI-tags", "SystemUI-proto", "SystemUI-flags", "monet", "dagger2", "jsr330", Loading packages/SystemUI/shared/Android.bp +0 −4 Original line number Diff line number Diff line Loading @@ -45,9 +45,6 @@ android_library { ":wm_shell-aidls", ":wm_shell_util-sources", ], libs: [ "SystemUI-flags", ], static_libs: [ "PluginCoreLib", "androidx.dynamicanimation_dynamicanimation", Loading Loading @@ -75,7 +72,6 @@ java_library { ], static_kotlin_stdlib: false, libs: [ "SystemUI-flags", "androidx.concurrent_concurrent-futures", ], static_libs: [ Loading packages/SystemUI/shared/src/com/android/systemui/flags/Flag.kt +17 −6 Original line number Diff line number Diff line Loading @@ -22,15 +22,21 @@ import android.os.Parcelable interface Flag<T> : Parcelable { val id: Int val default: T val resourceOverride: Int override fun describeContents() = 0 fun hasResourceOverride(): Boolean { return resourceOverride != -1 } } // Consider using the "parcelize" kotlin library. data class BooleanFlag @JvmOverloads constructor( override val id: Int, override val default: Boolean = false override val default: Boolean = false, override val resourceOverride: Int = -1 ) : Flag<Boolean> { companion object { Loading @@ -54,7 +60,8 @@ data class BooleanFlag @JvmOverloads constructor( data class StringFlag @JvmOverloads constructor( override val id: Int, override val default: String = "" override val default: String = "", override val resourceOverride: Int = -1 ) : Flag<String> { companion object { @JvmField Loading @@ -77,7 +84,8 @@ data class StringFlag @JvmOverloads constructor( data class IntFlag @JvmOverloads constructor( override val id: Int, override val default: Int = 0 override val default: Int = 0, override val resourceOverride: Int = -1 ) : Flag<Int> { companion object { Loading @@ -101,7 +109,8 @@ data class IntFlag @JvmOverloads constructor( data class LongFlag @JvmOverloads constructor( override val id: Int, override val default: Long = 0 override val default: Long = 0, override val resourceOverride: Int = -1 ) : Flag<Long> { companion object { Loading @@ -125,7 +134,8 @@ data class LongFlag @JvmOverloads constructor( data class FloatFlag @JvmOverloads constructor( override val id: Int, override val default: Float = 0f override val default: Float = 0f, override val resourceOverride: Int = -1 ) : Flag<Float> { companion object { Loading @@ -149,7 +159,8 @@ data class FloatFlag @JvmOverloads constructor( data class DoubleFlag @JvmOverloads constructor( override val id: Int, override val default: Double = 0.0 override val default: Double = 0.0, override val resourceOverride: Int = -1 ) : Flag<Double> { companion object { Loading packages/SystemUI/src/com/android/systemui/flags/FeatureFlagReader.javadeleted 100644 → 0 +0 −175 Original line number Diff line number Diff line /* * Copyright (C) 2021 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.flags; import android.content.res.Resources; import android.util.SparseArray; import androidx.annotation.BoolRes; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.android.systemui.Dumpable; import com.android.systemui.R; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.dump.DumpManager; import com.android.systemui.util.wrapper.BuildInfo; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; import javax.inject.Inject; /** * Reads and caches feature flags for quick access * * Feature flags must be defined as boolean resources. For example: * * {@code * <bool name="flag_foo_bar_baz">false</bool> * } * * It is strongly recommended that the name of the resource begin with "flag_". * * Flags can be overridden via adb on development builds. For example, to override the flag from the * previous example, do the following: * * {@code * $ adb shell setprop persist.systemui.flag_foo_bar_baz 1 * } * * Note that all storage keys begin with "flag_", even if their associated resId does not. * * Calls to this class should probably be wrapped by a method in {@link FeatureFlags}. */ @SysUISingleton public class FeatureFlagReader implements Dumpable { private final Resources mResources; private final boolean mAreFlagsOverrideable; private final SystemPropertiesHelper mSystemPropertiesHelper; private final SparseArray<CachedFlag> mCachedFlags = new SparseArray<>(); private FlagReader mFlagReader; @Inject public FeatureFlagReader( @Main Resources resources, BuildInfo build, DumpManager dumpManager, SystemPropertiesHelper systemPropertiesHelper, FlagReader reader) { mResources = resources; mFlagReader = reader; mSystemPropertiesHelper = systemPropertiesHelper; mAreFlagsOverrideable = build.isDebuggable() && mResources.getBoolean(R.bool.are_flags_overrideable); dumpManager.registerDumpable("FeatureFlags", this); } boolean isEnabled(BooleanFlag flag) { return mFlagReader.isEnabled(flag.getId(), flag.getDefault()); } void addListener(FlagReader.Listener listener) { mFlagReader.addListener(listener); } void removeListener(FlagReader.Listener listener) { mFlagReader.removeListener(listener); } /** * Returns true if the specified feature flag has been enabled. * * @param resId The backing boolean resource that determines the value of the flag. This value * can be overridden via DeviceConfig on development builds. */ public boolean isEnabled(@BoolRes int resId) { synchronized (mCachedFlags) { CachedFlag cachedFlag = mCachedFlags.get(resId); if (cachedFlag == null) { String name = resourceIdToFlagName(resId); boolean value = mResources.getBoolean(resId); if (mAreFlagsOverrideable) { value = mSystemPropertiesHelper.getBoolean(flagNameToStorageKey(name), value); } cachedFlag = new CachedFlag(name, value); mCachedFlags.put(resId, cachedFlag); } return cachedFlag.value; } } private String resourceIdToFlagName(@BoolRes int resId) { String resName = mResources.getResourceEntryName(resId); if (resName.startsWith(RESNAME_PREFIX)) { resName = resName.substring(RESNAME_PREFIX.length()); } return resName; } private String flagNameToStorageKey(String flagName) { if (flagName.startsWith(STORAGE_KEY_PREFIX)) { return flagName; } else { return STORAGE_KEY_PREFIX + flagName; } } @Nullable private String storageKeyToFlagName(String configName) { if (configName.startsWith(STORAGE_KEY_PREFIX)) { return configName.substring(STORAGE_KEY_PREFIX.length()); } else { return null; } } @Override public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) { ArrayList<String> flagStrings = new ArrayList<>(mCachedFlags.size()); for (int i = 0; i < mCachedFlags.size(); i++) { int key = mCachedFlags.keyAt(i); // get the object by the key. CachedFlag flag = mCachedFlags.get(key); flagStrings.add(" " + RESNAME_PREFIX + flag.name + ": " + flag.value + "\n"); } flagStrings.sort(String.CASE_INSENSITIVE_ORDER); pw.println("AreFlagsOverrideable: " + mAreFlagsOverrideable); pw.println("Cached FeatureFlags:"); for (String flagString : flagStrings) { pw.print(flagString); } } private static class CachedFlag { public final String name; public final boolean value; private CachedFlag(String name, boolean value) { this.name = name; this.value = value; } } private static final String STORAGE_KEY_PREFIX = "persist.systemui.flag_"; private static final String RESNAME_PREFIX = "flag_"; } packages/SystemUI/src/com/android/systemui/flags/FeatureFlags.java +35 −14 Original line number Diff line number Diff line Loading @@ -17,13 +17,17 @@ package com.android.systemui.flags; import android.content.Context; import android.content.res.Resources; import android.util.FeatureFlagUtils; import android.util.Log; import android.util.SparseArray; import android.widget.Toast; import androidx.annotation.BoolRes; import com.android.internal.annotations.VisibleForTesting; import com.android.systemui.R; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.qualifiers.Main; import java.util.ArrayList; import java.util.HashMap; Loading @@ -39,13 +43,16 @@ import javax.inject.Inject; */ @SysUISingleton public class FeatureFlags { private final FeatureFlagReader mFlagReader; private final Resources mResources; private final FlagReader mFlagReader; private final Context mContext; private final Map<Integer, Flag<?>> mFlagMap = new HashMap<>(); private final Map<Integer, List<Listener>> mListeners = new HashMap<>(); private final SparseArray<Boolean> mCachedFlags = new SparseArray<>(); @Inject public FeatureFlags(FeatureFlagReader flagReader, Context context) { public FeatureFlags(@Main Resources resources, FlagReader flagReader, Context context) { mResources = resources; mFlagReader = flagReader; mContext = context; Loading @@ -59,7 +66,7 @@ public class FeatureFlags { }; @VisibleForTesting void addFlag(Flag flag) { void addFlag(Flag<?> flag) { mFlagMap.put(flag.getId(), flag); } Loading @@ -68,7 +75,15 @@ public class FeatureFlags { * @return The value of the flag. */ public boolean isEnabled(BooleanFlag flag) { return mFlagReader.isEnabled(flag); boolean def = flag.getDefault(); if (flag.hasResourceOverride()) { try { def = isEnabledInOverlay(flag.getResourceOverride()); } catch (Resources.NotFoundException e) { // no-op } } return mFlagReader.isEnabled(flag.getId(), def); } /** Loading Loading @@ -118,13 +133,11 @@ public class FeatureFlags { } public boolean isPeopleTileEnabled() { // TODO(b/202860494): different resource overlays have different values. return mFlagReader.isEnabled(R.bool.flag_conversations); return isEnabled(Flags.PEOPLE_TILE); } public boolean isMonetEnabled() { // TODO(b/202860494): used in wallpaper picker. Always true, maybe delete. return mFlagReader.isEnabled(R.bool.flag_monet); return isEnabled(Flags.MONET); } public boolean isPMLiteEnabled() { Loading @@ -132,8 +145,7 @@ public class FeatureFlags { } public boolean isChargingRippleEnabled() { // TODO(b/202860494): different resource overlays have different values. return mFlagReader.isEnabled(R.bool.flag_charging_ripple); return isEnabled(Flags.CHARGING_RIPPLE); } public boolean isOngoingCallStatusBarChipEnabled() { Loading @@ -150,8 +162,7 @@ public class FeatureFlags { } public boolean isSmartspaceEnabled() { // TODO(b/202860494): different resource overlays have different values. return mFlagReader.isEnabled(R.bool.flag_smartspace); return isEnabled(Flags.SMARTSPACE); } public boolean isSmartspaceDedupingEnabled() { Loading @@ -163,7 +174,7 @@ public class FeatureFlags { } public boolean isKeyguardQsUserDetailsShortcutEnabled() { return mFlagReader.isEnabled(R.bool.flag_lockscreen_qs_user_detail_shortcut); return isEnabled(Flags.QS_USER_DETAIL_SHORTCUT); } public boolean isSmartSpaceSharedElementTransitionEnabled() { Loading Loading @@ -199,6 +210,16 @@ public class FeatureFlags { return FeatureFlagUtils.isEnabled(context, FeatureFlagUtils.SETTINGS_PROVIDER_MODEL); } private boolean isEnabledInOverlay(@BoolRes int resId) { synchronized (mCachedFlags) { if (!mCachedFlags.contains(resId)) { mCachedFlags.put(resId, mResources.getBoolean(resId)); } return mCachedFlags.get(resId); } } /** Simple interface for beinga alerted when a specific flag changes value. */ public interface Listener { /** */ Loading Loading
packages/SystemUI/Android.bp +0 −12 Original line number Diff line number Diff line Loading @@ -50,17 +50,6 @@ java_library { srcs: ["src/com/android/systemui/EventLogTags.logtags"], } java_library { name: "SystemUI-flags", srcs: [ "src/com/android/systemui/flags/Flags.java", ], libs: [ "SystemUI-flag-types", ], static_kotlin_stdlib: false, } filegroup { name: "ReleaseJavaFiles", srcs: [ Loading Loading @@ -127,7 +116,6 @@ android_library { "iconloader_base", "SystemUI-tags", "SystemUI-proto", "SystemUI-flags", "monet", "dagger2", "jsr330", Loading
packages/SystemUI/shared/Android.bp +0 −4 Original line number Diff line number Diff line Loading @@ -45,9 +45,6 @@ android_library { ":wm_shell-aidls", ":wm_shell_util-sources", ], libs: [ "SystemUI-flags", ], static_libs: [ "PluginCoreLib", "androidx.dynamicanimation_dynamicanimation", Loading Loading @@ -75,7 +72,6 @@ java_library { ], static_kotlin_stdlib: false, libs: [ "SystemUI-flags", "androidx.concurrent_concurrent-futures", ], static_libs: [ Loading
packages/SystemUI/shared/src/com/android/systemui/flags/Flag.kt +17 −6 Original line number Diff line number Diff line Loading @@ -22,15 +22,21 @@ import android.os.Parcelable interface Flag<T> : Parcelable { val id: Int val default: T val resourceOverride: Int override fun describeContents() = 0 fun hasResourceOverride(): Boolean { return resourceOverride != -1 } } // Consider using the "parcelize" kotlin library. data class BooleanFlag @JvmOverloads constructor( override val id: Int, override val default: Boolean = false override val default: Boolean = false, override val resourceOverride: Int = -1 ) : Flag<Boolean> { companion object { Loading @@ -54,7 +60,8 @@ data class BooleanFlag @JvmOverloads constructor( data class StringFlag @JvmOverloads constructor( override val id: Int, override val default: String = "" override val default: String = "", override val resourceOverride: Int = -1 ) : Flag<String> { companion object { @JvmField Loading @@ -77,7 +84,8 @@ data class StringFlag @JvmOverloads constructor( data class IntFlag @JvmOverloads constructor( override val id: Int, override val default: Int = 0 override val default: Int = 0, override val resourceOverride: Int = -1 ) : Flag<Int> { companion object { Loading @@ -101,7 +109,8 @@ data class IntFlag @JvmOverloads constructor( data class LongFlag @JvmOverloads constructor( override val id: Int, override val default: Long = 0 override val default: Long = 0, override val resourceOverride: Int = -1 ) : Flag<Long> { companion object { Loading @@ -125,7 +134,8 @@ data class LongFlag @JvmOverloads constructor( data class FloatFlag @JvmOverloads constructor( override val id: Int, override val default: Float = 0f override val default: Float = 0f, override val resourceOverride: Int = -1 ) : Flag<Float> { companion object { Loading @@ -149,7 +159,8 @@ data class FloatFlag @JvmOverloads constructor( data class DoubleFlag @JvmOverloads constructor( override val id: Int, override val default: Double = 0.0 override val default: Double = 0.0, override val resourceOverride: Int = -1 ) : Flag<Double> { companion object { Loading
packages/SystemUI/src/com/android/systemui/flags/FeatureFlagReader.javadeleted 100644 → 0 +0 −175 Original line number Diff line number Diff line /* * Copyright (C) 2021 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.flags; import android.content.res.Resources; import android.util.SparseArray; import androidx.annotation.BoolRes; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.android.systemui.Dumpable; import com.android.systemui.R; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.dump.DumpManager; import com.android.systemui.util.wrapper.BuildInfo; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; import javax.inject.Inject; /** * Reads and caches feature flags for quick access * * Feature flags must be defined as boolean resources. For example: * * {@code * <bool name="flag_foo_bar_baz">false</bool> * } * * It is strongly recommended that the name of the resource begin with "flag_". * * Flags can be overridden via adb on development builds. For example, to override the flag from the * previous example, do the following: * * {@code * $ adb shell setprop persist.systemui.flag_foo_bar_baz 1 * } * * Note that all storage keys begin with "flag_", even if their associated resId does not. * * Calls to this class should probably be wrapped by a method in {@link FeatureFlags}. */ @SysUISingleton public class FeatureFlagReader implements Dumpable { private final Resources mResources; private final boolean mAreFlagsOverrideable; private final SystemPropertiesHelper mSystemPropertiesHelper; private final SparseArray<CachedFlag> mCachedFlags = new SparseArray<>(); private FlagReader mFlagReader; @Inject public FeatureFlagReader( @Main Resources resources, BuildInfo build, DumpManager dumpManager, SystemPropertiesHelper systemPropertiesHelper, FlagReader reader) { mResources = resources; mFlagReader = reader; mSystemPropertiesHelper = systemPropertiesHelper; mAreFlagsOverrideable = build.isDebuggable() && mResources.getBoolean(R.bool.are_flags_overrideable); dumpManager.registerDumpable("FeatureFlags", this); } boolean isEnabled(BooleanFlag flag) { return mFlagReader.isEnabled(flag.getId(), flag.getDefault()); } void addListener(FlagReader.Listener listener) { mFlagReader.addListener(listener); } void removeListener(FlagReader.Listener listener) { mFlagReader.removeListener(listener); } /** * Returns true if the specified feature flag has been enabled. * * @param resId The backing boolean resource that determines the value of the flag. This value * can be overridden via DeviceConfig on development builds. */ public boolean isEnabled(@BoolRes int resId) { synchronized (mCachedFlags) { CachedFlag cachedFlag = mCachedFlags.get(resId); if (cachedFlag == null) { String name = resourceIdToFlagName(resId); boolean value = mResources.getBoolean(resId); if (mAreFlagsOverrideable) { value = mSystemPropertiesHelper.getBoolean(flagNameToStorageKey(name), value); } cachedFlag = new CachedFlag(name, value); mCachedFlags.put(resId, cachedFlag); } return cachedFlag.value; } } private String resourceIdToFlagName(@BoolRes int resId) { String resName = mResources.getResourceEntryName(resId); if (resName.startsWith(RESNAME_PREFIX)) { resName = resName.substring(RESNAME_PREFIX.length()); } return resName; } private String flagNameToStorageKey(String flagName) { if (flagName.startsWith(STORAGE_KEY_PREFIX)) { return flagName; } else { return STORAGE_KEY_PREFIX + flagName; } } @Nullable private String storageKeyToFlagName(String configName) { if (configName.startsWith(STORAGE_KEY_PREFIX)) { return configName.substring(STORAGE_KEY_PREFIX.length()); } else { return null; } } @Override public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) { ArrayList<String> flagStrings = new ArrayList<>(mCachedFlags.size()); for (int i = 0; i < mCachedFlags.size(); i++) { int key = mCachedFlags.keyAt(i); // get the object by the key. CachedFlag flag = mCachedFlags.get(key); flagStrings.add(" " + RESNAME_PREFIX + flag.name + ": " + flag.value + "\n"); } flagStrings.sort(String.CASE_INSENSITIVE_ORDER); pw.println("AreFlagsOverrideable: " + mAreFlagsOverrideable); pw.println("Cached FeatureFlags:"); for (String flagString : flagStrings) { pw.print(flagString); } } private static class CachedFlag { public final String name; public final boolean value; private CachedFlag(String name, boolean value) { this.name = name; this.value = value; } } private static final String STORAGE_KEY_PREFIX = "persist.systemui.flag_"; private static final String RESNAME_PREFIX = "flag_"; }
packages/SystemUI/src/com/android/systemui/flags/FeatureFlags.java +35 −14 Original line number Diff line number Diff line Loading @@ -17,13 +17,17 @@ package com.android.systemui.flags; import android.content.Context; import android.content.res.Resources; import android.util.FeatureFlagUtils; import android.util.Log; import android.util.SparseArray; import android.widget.Toast; import androidx.annotation.BoolRes; import com.android.internal.annotations.VisibleForTesting; import com.android.systemui.R; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.qualifiers.Main; import java.util.ArrayList; import java.util.HashMap; Loading @@ -39,13 +43,16 @@ import javax.inject.Inject; */ @SysUISingleton public class FeatureFlags { private final FeatureFlagReader mFlagReader; private final Resources mResources; private final FlagReader mFlagReader; private final Context mContext; private final Map<Integer, Flag<?>> mFlagMap = new HashMap<>(); private final Map<Integer, List<Listener>> mListeners = new HashMap<>(); private final SparseArray<Boolean> mCachedFlags = new SparseArray<>(); @Inject public FeatureFlags(FeatureFlagReader flagReader, Context context) { public FeatureFlags(@Main Resources resources, FlagReader flagReader, Context context) { mResources = resources; mFlagReader = flagReader; mContext = context; Loading @@ -59,7 +66,7 @@ public class FeatureFlags { }; @VisibleForTesting void addFlag(Flag flag) { void addFlag(Flag<?> flag) { mFlagMap.put(flag.getId(), flag); } Loading @@ -68,7 +75,15 @@ public class FeatureFlags { * @return The value of the flag. */ public boolean isEnabled(BooleanFlag flag) { return mFlagReader.isEnabled(flag); boolean def = flag.getDefault(); if (flag.hasResourceOverride()) { try { def = isEnabledInOverlay(flag.getResourceOverride()); } catch (Resources.NotFoundException e) { // no-op } } return mFlagReader.isEnabled(flag.getId(), def); } /** Loading Loading @@ -118,13 +133,11 @@ public class FeatureFlags { } public boolean isPeopleTileEnabled() { // TODO(b/202860494): different resource overlays have different values. return mFlagReader.isEnabled(R.bool.flag_conversations); return isEnabled(Flags.PEOPLE_TILE); } public boolean isMonetEnabled() { // TODO(b/202860494): used in wallpaper picker. Always true, maybe delete. return mFlagReader.isEnabled(R.bool.flag_monet); return isEnabled(Flags.MONET); } public boolean isPMLiteEnabled() { Loading @@ -132,8 +145,7 @@ public class FeatureFlags { } public boolean isChargingRippleEnabled() { // TODO(b/202860494): different resource overlays have different values. return mFlagReader.isEnabled(R.bool.flag_charging_ripple); return isEnabled(Flags.CHARGING_RIPPLE); } public boolean isOngoingCallStatusBarChipEnabled() { Loading @@ -150,8 +162,7 @@ public class FeatureFlags { } public boolean isSmartspaceEnabled() { // TODO(b/202860494): different resource overlays have different values. return mFlagReader.isEnabled(R.bool.flag_smartspace); return isEnabled(Flags.SMARTSPACE); } public boolean isSmartspaceDedupingEnabled() { Loading @@ -163,7 +174,7 @@ public class FeatureFlags { } public boolean isKeyguardQsUserDetailsShortcutEnabled() { return mFlagReader.isEnabled(R.bool.flag_lockscreen_qs_user_detail_shortcut); return isEnabled(Flags.QS_USER_DETAIL_SHORTCUT); } public boolean isSmartSpaceSharedElementTransitionEnabled() { Loading Loading @@ -199,6 +210,16 @@ public class FeatureFlags { return FeatureFlagUtils.isEnabled(context, FeatureFlagUtils.SETTINGS_PROVIDER_MODEL); } private boolean isEnabledInOverlay(@BoolRes int resId) { synchronized (mCachedFlags) { if (!mCachedFlags.contains(resId)) { mCachedFlags.put(resId, mResources.getBoolean(resId)); } return mCachedFlags.get(resId); } } /** Simple interface for beinga alerted when a specific flag changes value. */ public interface Listener { /** */ Loading