diff options
| author | 2022-11-06 14:38:44 +0000 | |
|---|---|---|
| committer | 2022-11-06 14:38:44 +0000 | |
| commit | 1becd8179ae29a2582fcae8de147acb79e620b9c (patch) | |
| tree | 7a3d449bee2a127d998b7c1f56acfd4e225d023e | |
| parent | b8baeb7bc951cf84cfdbaa4e75ed27320d92ec20 (diff) | |
| parent | 8fd3032fce2126988e30806aa102124e4aadda44 (diff) | |
Merge "Include all flags in our flag list." into tm-qpr-dev am: 8fd3032fce
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/20318731
Change-Id: I02c36fb40401663a7028b8f745dc6e5ff4f06405
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
7 files changed, 171 insertions, 189 deletions
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp index a544d9b7af39..b3b5529897da 100644 --- a/packages/SystemUI/Android.bp +++ b/packages/SystemUI/Android.bp @@ -115,6 +115,7 @@ android_library { "androidx-constraintlayout_constraintlayout", "androidx.exifinterface_exifinterface", "com.google.android.material_material", + "kotlin-reflect", "kotlinx_coroutines_android", "kotlinx_coroutines", "iconloader_base", diff --git a/packages/SystemUI/shared/src/com/android/systemui/flags/Flag.kt b/packages/SystemUI/shared/src/com/android/systemui/flags/Flag.kt index f7049cf8f4f2..933e58639ccf 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/flags/Flag.kt +++ b/packages/SystemUI/shared/src/com/android/systemui/flags/Flag.kt @@ -89,7 +89,7 @@ abstract class BooleanFlag constructor( * * It can be changed or overridden in debug builds but not in release builds. */ -data class UnreleasedFlag @JvmOverloads constructor( +data class UnreleasedFlag constructor( override val id: Int, override val teamfood: Boolean = false, override val overridden: Boolean = false @@ -100,7 +100,7 @@ data class UnreleasedFlag @JvmOverloads constructor( * * It can be changed or overridden in any build, meaning it can be turned off if needed. */ -data class ReleasedFlag @JvmOverloads constructor( +data class ReleasedFlag constructor( override val id: Int, override val teamfood: Boolean = false, override val overridden: Boolean = false @@ -111,7 +111,7 @@ data class ReleasedFlag @JvmOverloads constructor( * * Prefer [UnreleasedFlag] and [ReleasedFlag]. */ -data class ResourceBooleanFlag @JvmOverloads constructor( +data class ResourceBooleanFlag constructor( override val id: Int, @BoolRes override val resourceId: Int, override val teamfood: Boolean = false @@ -124,7 +124,7 @@ data class ResourceBooleanFlag @JvmOverloads constructor( * * Prefer [UnreleasedFlag] and [ReleasedFlag]. */ -data class DeviceConfigBooleanFlag @JvmOverloads constructor( +data class DeviceConfigBooleanFlag constructor( override val id: Int, override val name: String, override val namespace: String, @@ -139,7 +139,7 @@ data class DeviceConfigBooleanFlag @JvmOverloads constructor( * * Prefer [UnreleasedFlag] and [ReleasedFlag]. */ -data class SysPropBooleanFlag @JvmOverloads constructor( +data class SysPropBooleanFlag constructor( override val id: Int, override val name: String, override val default: Boolean = false @@ -148,7 +148,7 @@ data class SysPropBooleanFlag @JvmOverloads constructor( override val teamfood: Boolean = false } -data class StringFlag @JvmOverloads constructor( +data class StringFlag constructor( override val id: Int, override val default: String = "", override val teamfood: Boolean = false, @@ -173,13 +173,13 @@ data class StringFlag @JvmOverloads constructor( } } -data class ResourceStringFlag @JvmOverloads constructor( +data class ResourceStringFlag constructor( override val id: Int, @StringRes override val resourceId: Int, override val teamfood: Boolean = false ) : ResourceFlag<String> -data class IntFlag @JvmOverloads constructor( +data class IntFlag constructor( override val id: Int, override val default: Int = 0, override val teamfood: Boolean = false, @@ -205,13 +205,13 @@ data class IntFlag @JvmOverloads constructor( } } -data class ResourceIntFlag @JvmOverloads constructor( +data class ResourceIntFlag constructor( override val id: Int, @IntegerRes override val resourceId: Int, override val teamfood: Boolean = false ) : ResourceFlag<Int> -data class LongFlag @JvmOverloads constructor( +data class LongFlag constructor( override val id: Int, override val default: Long = 0, override val teamfood: Boolean = false, @@ -237,7 +237,7 @@ data class LongFlag @JvmOverloads constructor( } } -data class FloatFlag @JvmOverloads constructor( +data class FloatFlag constructor( override val id: Int, override val default: Float = 0f, override val teamfood: Boolean = false, @@ -263,13 +263,13 @@ data class FloatFlag @JvmOverloads constructor( } } -data class ResourceFloatFlag @JvmOverloads constructor( +data class ResourceFloatFlag constructor( override val id: Int, override val resourceId: Int, override val teamfood: Boolean = false ) : ResourceFlag<Int> -data class DoubleFlag @JvmOverloads constructor( +data class DoubleFlag constructor( override val id: Int, override val default: Double = 0.0, override val teamfood: Boolean = false, diff --git a/packages/SystemUI/src/com/android/systemui/flags/FlagCommand.java b/packages/SystemUI/src/com/android/systemui/flags/FlagCommand.java index 2a1e3cd937bd..ad4b87da0744 100644 --- a/packages/SystemUI/src/com/android/systemui/flags/FlagCommand.java +++ b/packages/SystemUI/src/com/android/systemui/flags/FlagCommand.java @@ -23,7 +23,6 @@ import androidx.annotation.NonNull; import com.android.systemui.statusbar.commandline.Command; import java.io.PrintWriter; -import java.lang.reflect.Field; import java.util.List; import java.util.Map; @@ -230,33 +229,22 @@ public class FlagCommand implements Command { } private int flagNameToId(String flagName) { - List<Field> fields = Flags.getFlagFields(); - for (Field field : fields) { - if (flagName.equals(field.getName())) { - return fieldToId(field); + Map<String, Flag<?>> flagFields = Flags.getFlagFields(); + for (String fieldName : flagFields.keySet()) { + if (flagName.equals(fieldName)) { + return flagFields.get(fieldName).getId(); } } return 0; } - private int fieldToId(Field field) { - try { - Flag<?> flag = (Flag<?>) field.get(null); - return flag.getId(); - } catch (IllegalAccessException e) { - // no-op - } - - return 0; - } - private void printKnownFlags(PrintWriter pw) { - List<Field> fields = Flags.getFlagFields(); + Map<String, Flag<?>> fields = Flags.getFlagFields(); int longestFieldName = 0; - for (Field field : fields) { - longestFieldName = Math.max(longestFieldName, field.getName().length()); + for (String fieldName : fields.keySet()) { + longestFieldName = Math.max(longestFieldName, fieldName.length()); } pw.println("Known Flags:"); @@ -268,16 +256,15 @@ public class FlagCommand implements Command { for (int i = 0; i < longestFieldName; i++) { pw.print("="); } - pw.println(" ==== ====="); - for (Field field : fields) { - int id = fieldToId(field); - Flag<?> flag = mAllFlags.get(id); - + pw.println(" ==== ========"); + for (String fieldName : fields.keySet()) { + Flag<?> flag = fields.get(fieldName); + int id = flag.getId(); if (id == 0 || !mAllFlags.containsKey(id)) { continue; } - pw.print(field.getName()); - int fieldWidth = field.getName().length(); + pw.print(fieldName); + int fieldWidth = fieldName.length(); for (int i = 0; i < longestFieldName - fieldWidth + 1; i++) { pw.print(" "); } diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt index 0258b23d11a8..9d4a3a9e686b 100644 --- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt +++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt @@ -17,8 +17,12 @@ package com.android.systemui.flags import android.provider.DeviceConfig import com.android.internal.annotations.Keep +import com.android.internal.annotations.VisibleForTesting import com.android.systemui.R -import java.lang.reflect.Field +import kotlin.reflect.KClass +import kotlin.reflect.full.declaredMembers +import kotlin.reflect.full.isSubclassOf +import kotlin.reflect.full.staticProperties /** * List of [Flag] objects for use in SystemUI. @@ -63,6 +67,7 @@ object Flags { @JvmField val NOTIFICATION_DISMISSAL_FADE = UnreleasedFlag(113, teamfood = true) val STABILITY_INDEX_FIX = UnreleasedFlag(114, teamfood = true) val SEMI_STABLE_SORT = UnreleasedFlag(115, teamfood = true) + @JvmField val NOTIFICATION_GROUP_CORNER = UnreleasedFlag(116, teamfood = true) // next id: 117 @@ -148,6 +153,7 @@ object Flags { // TODO(b/254512321): Tracking Bug @JvmField val COMBINED_QS_HEADERS = UnreleasedFlag(501, teamfood = true) val PEOPLE_TILE = ResourceBooleanFlag(502, R.bool.flag_conversations) + @JvmField val QS_USER_DETAIL_SHORTCUT = ResourceBooleanFlag(503, R.bool.flag_lockscreen_qs_user_detail_shortcut) @@ -244,14 +250,14 @@ object Flags { @JvmField val ROUNDED_BOX_RIPPLE = ReleasedFlag(1002) // 1100 - windowing - @JvmField @Keep + @JvmField val WM_ENABLE_SHELL_TRANSITIONS = SysPropBooleanFlag(1100, "persist.wm.debug.shell_transit", false) // TODO(b/254513207): Tracking Bug - @JvmField @Keep + @JvmField val WM_ENABLE_PARTIAL_SCREEN_SHARING = DeviceConfigBooleanFlag( 1102, @@ -262,30 +268,30 @@ object Flags { ) // TODO(b/254512674): Tracking Bug - @JvmField @Keep + @JvmField val HIDE_NAVBAR_WINDOW = SysPropBooleanFlag(1103, "persist.wm.debug.hide_navbar_window", false) - @JvmField @Keep + @JvmField val WM_DESKTOP_WINDOWING = SysPropBooleanFlag(1104, "persist.wm.debug.desktop_mode", false) - @JvmField @Keep + @JvmField val WM_CAPTION_ON_SHELL = SysPropBooleanFlag(1105, "persist.wm.debug.caption_on_shell", false) - @JvmField @Keep + @JvmField val ENABLE_FLING_TO_DISMISS_BUBBLE = SysPropBooleanFlag(1108, "persist.wm.debug.fling_to_dismiss_bubble", true) - @JvmField @Keep + @JvmField val ENABLE_FLING_TO_DISMISS_PIP = SysPropBooleanFlag(1109, "persist.wm.debug.fling_to_dismiss_pip", true) - @JvmField @Keep + @JvmField val ENABLE_PIP_KEEP_CLEAR_ALGORITHM = SysPropBooleanFlag(1110, "persist.wm.debug.enable_pip_keep_clear_algorithm", false) @@ -293,18 +299,18 @@ object Flags { @JvmField @Keep val WM_BUBBLE_BAR = UnreleasedFlag(1111) // 1200 - predictive back - @JvmField @Keep + @JvmField val WM_ENABLE_PREDICTIVE_BACK = SysPropBooleanFlag(1200, "persist.wm.debug.predictive_back", true) - @JvmField @Keep + @JvmField val WM_ENABLE_PREDICTIVE_BACK_ANIM = SysPropBooleanFlag(1201, "persist.wm.debug.predictive_back_anim", false) - @JvmField @Keep + @JvmField val WM_ALWAYS_ENFORCE_PREDICTIVE_BACK = SysPropBooleanFlag(1202, "persist.wm.debug.predictive_back_always_enforce", false) @@ -313,7 +319,7 @@ object Flags { // 1300 - screenshots // TODO(b/254512719): Tracking Bug - @JvmField val SCREENSHOT_REQUEST_PROCESSOR = UnreleasedFlag(1300, true) + @JvmField val SCREENSHOT_REQUEST_PROCESSOR = UnreleasedFlag(1300, teamfood = true) // TODO(b/254513155): Tracking Bug @JvmField val SCREENSHOT_WORK_PROFILE_POLICY = UnreleasedFlag(1301) @@ -327,7 +333,7 @@ object Flags { val CHOOSER_UNBUNDLED = UnreleasedFlag(1500, teamfood = true) // 1700 - clipboard - @JvmField val CLIPBOARD_OVERLAY_REFACTOR = UnreleasedFlag(1700, true) + @JvmField val CLIPBOARD_OVERLAY_REFACTOR = UnreleasedFlag(1700, teamfood = true) @JvmField val CLIPBOARD_REMOTE_BEHAVIOR = UnreleasedFlag(1701) // 1800 - shade container @@ -337,7 +343,7 @@ object Flags { @JvmField val NOTE_TASKS = SysPropBooleanFlag(1900, "persist.sysui.debug.note_tasks") // 2000 - device controls - @Keep val USE_APP_PANELS = UnreleasedFlag(2000, true) + @Keep @JvmField val USE_APP_PANELS = UnreleasedFlag(2000, teamfood = true) // 2100 - Falsing Manager @JvmField val FALSING_FOR_LONG_TAPS = ReleasedFlag(2100) @@ -348,24 +354,48 @@ object Flags { // | . . . . . . . . . . . . . . . . . . . | @JvmStatic fun collectFlags(): Map<Int, Flag<*>> { - return flagFields - .map { field -> - // field[null] returns the current value of the field. - // See java.lang.Field#get - val flag = field[null] as Flag<*> - flag.id to flag - } - .toMap() + return flagFields.mapKeys { field -> field.value.id } } // | . . . . . . . . . . . . . . . . . . . | @JvmStatic - val flagFields: List<Field> - get() { - return Flags::class.java.fields.filter { f -> - Flag::class.java.isAssignableFrom(f.type) + val flagFields: Map<String, Flag<*>> + get() = collectFlagsInClass(Flags) + + @VisibleForTesting + fun collectFlagsInClass(instance: Any): Map<String, Flag<*>> { + val cls = instance::class + val javaPropNames = cls.java.fields.map { it.name } + val props = cls.declaredMembers + val staticProps = cls.staticProperties + val staticPropNames = staticProps.map { it.name } + return props + .mapNotNull { property -> + if ((property.returnType.classifier as KClass<*>).isSubclassOf(Flag::class)) { + // Fields with @JvmStatic should be accessed via java mechanisms + if (javaPropNames.contains(property.name)) { + property.name to cls.java.getField(property.name)[null] as Flag<*> + // Fields with @Keep but not @JvmField. Don't do this. + } else if (staticPropNames.contains(property.name)) { + // The below code causes access violation exceptions. I don't know why. + // property.name to (property.call() as Flag<*>) + // property.name to (staticProps.find { it.name == property.name }!! + // .getter.call() as Flag<*>) + throw java.lang.RuntimeException( + "The {$property.name} flag needs @JvmField" + ) + // Everything else. Skip the `get` prefixed fields that kotlin adds. + } else if (property.name.subSequence(0, 3) != "get") { + property.name to (property.call(instance) as Flag<*>) + } else { + null + } + } else { + null + } } - } + .toMap() + } // | | // \_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/ } diff --git a/packages/SystemUI/tests/src/com/android/systemui/flags/FlagsTest.java b/packages/SystemUI/tests/src/com/android/systemui/flags/FlagsTest.java deleted file mode 100644 index 250cc48fece3..000000000000 --- a/packages/SystemUI/tests/src/com/android/systemui/flags/FlagsTest.java +++ /dev/null @@ -1,119 +0,0 @@ -/* - * 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 static com.google.common.truth.Truth.assertWithMessage; - -import android.util.Pair; - -import androidx.test.filters.SmallTest; - -import com.android.systemui.SysuiTestCase; - -import org.junit.Test; - -import java.lang.reflect.Field; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -@SmallTest -public class FlagsTest extends SysuiTestCase { - - @Test - public void testDuplicateFlagIdCheckWorks() { - List<Pair<String, Flag<?>>> flags = collectFlags(DuplicateFlagContainer.class); - Map<Integer, List<String>> duplicates = groupDuplicateFlags(flags); - - assertWithMessage(generateAssertionMessage(duplicates)) - .that(duplicates.size()).isEqualTo(2); - } - - @Test - public void testNoDuplicateFlagIds() { - List<Pair<String, Flag<?>>> flags = collectFlags(Flags.class); - Map<Integer, List<String>> duplicates = groupDuplicateFlags(flags); - - assertWithMessage(generateAssertionMessage(duplicates)) - .that(duplicates.size()).isEqualTo(0); - } - - private String generateAssertionMessage(Map<Integer, List<String>> duplicates) { - StringBuilder stringBuilder = new StringBuilder(); - stringBuilder.append("Duplicate flag keys found: {"); - for (int id : duplicates.keySet()) { - stringBuilder - .append(" ") - .append(id) - .append(": [") - .append(String.join(", ", duplicates.get(id))) - .append("]"); - } - stringBuilder.append(" }"); - - return stringBuilder.toString(); - } - - private List<Pair<String, Flag<?>>> collectFlags(Class<?> clz) { - List<Pair<String, Flag<?>>> flags = new ArrayList<>(); - - Field[] fields = clz.getFields(); - - for (Field field : fields) { - Class<?> t = field.getType(); - if (Flag.class.isAssignableFrom(t)) { - try { - flags.add(Pair.create(field.getName(), (Flag<?>) field.get(null))); - } catch (IllegalAccessException e) { - // no-op - } - } - } - - return flags; - } - - private Map<Integer, List<String>> groupDuplicateFlags(List<Pair<String, Flag<?>>> flags) { - Map<Integer, List<String>> grouping = new HashMap<>(); - - for (Pair<String, Flag<?>> flag : flags) { - grouping.putIfAbsent(flag.second.getId(), new ArrayList<>()); - grouping.get(flag.second.getId()).add(flag.first); - } - - Map<Integer, List<String>> result = new HashMap<>(); - for (Integer id : grouping.keySet()) { - if (grouping.get(id).size() > 1) { - result.put(id, grouping.get(id)); - } - } - - return result; - } - - private static class DuplicateFlagContainer { - public static final BooleanFlag A_FLAG = new UnreleasedFlag(0); - public static final BooleanFlag B_FLAG = new UnreleasedFlag(0); - public static final StringFlag C_FLAG = new StringFlag(0); - - public static final BooleanFlag D_FLAG = new UnreleasedFlag(1); - - public static final DoubleFlag E_FLAG = new DoubleFlag(3); - public static final DoubleFlag F_FLAG = new DoubleFlag(3); - } -} diff --git a/packages/SystemUI/tests/src/com/android/systemui/flags/FlagsTest.kt b/packages/SystemUI/tests/src/com/android/systemui/flags/FlagsTest.kt new file mode 100644 index 000000000000..2b556f112e5f --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/flags/FlagsTest.kt @@ -0,0 +1,84 @@ +/* + * 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 androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.google.common.truth.Truth +import java.lang.StringBuilder +import java.util.ArrayList +import java.util.HashMap +import org.junit.Test + +@SmallTest +class FlagsTest : SysuiTestCase() { + @Test + fun testDuplicateFlagIdCheckWorks() { + val flags = Flags.collectFlagsInClass(DuplicateFlagContainer) + val duplicates = groupDuplicateFlags(flags) + Truth.assertWithMessage(generateAssertionMessage(duplicates)) + .that(duplicates.size) + .isEqualTo(2) + } + + @Test + fun testNoDuplicateFlagIds() { + val flags = Flags.collectFlagsInClass(Flags) + val duplicates = groupDuplicateFlags(flags) + Truth.assertWithMessage(generateAssertionMessage(duplicates)) + .that(duplicates.size) + .isEqualTo(0) + } + + private fun generateAssertionMessage(duplicates: Map<Int, List<String>>): String { + val stringBuilder = StringBuilder() + stringBuilder.append("Duplicate flag keys found: {") + for (id in duplicates.keys) { + stringBuilder + .append(" ") + .append(id) + .append(": [") + .append(java.lang.String.join(", ", duplicates[id])) + .append("]") + } + stringBuilder.append(" }") + return stringBuilder.toString() + } + + private fun groupDuplicateFlags(flags: Map<String, Flag<*>>): Map<Int, List<String>> { + val grouping: MutableMap<Int, MutableList<String>> = HashMap() + for (flag in flags) { + grouping.putIfAbsent(flag.value.id, ArrayList()) + grouping[flag.value.id]!!.add(flag.key) + } + val result: MutableMap<Int, List<String>> = HashMap() + for (id in grouping.keys) { + if (grouping[id]!!.size > 1) { + result[id] = grouping[id]!! + } + } + return result + } + + private object DuplicateFlagContainer { + val A_FLAG: BooleanFlag = UnreleasedFlag(0) + val B_FLAG: BooleanFlag = UnreleasedFlag(0) + val C_FLAG = StringFlag(0) + val D_FLAG: BooleanFlag = UnreleasedFlag(1) + val E_FLAG = DoubleFlag(3) + val F_FLAG = DoubleFlag(3) + } +} diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/flags/FakeFeatureFlags.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/flags/FakeFeatureFlags.kt index c132537eeb71..a35427f5ec3a 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/flags/FakeFeatureFlags.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/flags/FakeFeatureFlags.kt @@ -27,9 +27,8 @@ class FakeFeatureFlags : FeatureFlags { private val listenerFlagIds = mutableMapOf<FlagListenable.Listener, MutableSet<Int>>() init { - Flags.flagFields.forEach { field -> - val flag: Flag<*> = field.get(null) as Flag<*> - knownFlagNames[flag.id] = field.name + Flags.flagFields.forEach { entry: Map.Entry<String, Flag<*>> -> + knownFlagNames[entry.value.id] = entry.key } } |