Add intDef annotation processor to generate mapping
Test: Run 'mp :framework-all' and check if mapping file is properly
generated
Change-Id: I58f7ea5894e8ec994a74781663654508205c4db1
diff --git a/Android.bp b/Android.bp
index aae78a0..ded666f 100644
--- a/Android.bp
+++ b/Android.bp
@@ -626,6 +626,9 @@
// Additional dependencies needed to build the ike API classes.
"ike-internals",
],
+ plugins: [
+ "intdef-annotation-processor",
+ ],
libs: ["icing-java-proto-lite"],
apex_available: ["//apex_available:platform"],
visibility: [
@@ -886,6 +889,7 @@
exclude_srcs: [
"core/proto/android/privacy.proto",
"core/proto/android/section.proto",
+ "core/proto/android/typedef.proto",
],
sdk_version: "9",
srcs: [
@@ -911,6 +915,7 @@
exclude_srcs: [
"core/proto/android/privacy.proto",
"core/proto/android/section.proto",
+ "core/proto/android/typedef.proto",
],
sdk_version: "core_current",
// Protos have lots of MissingOverride and similar.
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 2168fe3..3d594b4 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -4323,9 +4323,46 @@
equals = STATUS_BAR_TRANSPARENT,
name = "STATUS_BAR_TRANSPARENT")
}, formatToHexString = true)
+ @SystemUiVisibility
int mSystemUiVisibility;
/**
+ * @hide
+ */
+ @IntDef(flag = true, prefix = "", value = {
+ SYSTEM_UI_FLAG_LOW_PROFILE,
+ SYSTEM_UI_FLAG_HIDE_NAVIGATION,
+ SYSTEM_UI_FLAG_FULLSCREEN,
+ SYSTEM_UI_FLAG_LAYOUT_STABLE,
+ SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION,
+ SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN,
+ SYSTEM_UI_FLAG_IMMERSIVE,
+ SYSTEM_UI_FLAG_IMMERSIVE_STICKY,
+ SYSTEM_UI_FLAG_LIGHT_STATUS_BAR,
+ SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR,
+ STATUS_BAR_DISABLE_EXPAND,
+ STATUS_BAR_DISABLE_NOTIFICATION_ICONS,
+ STATUS_BAR_DISABLE_NOTIFICATION_ALERTS,
+ STATUS_BAR_DISABLE_NOTIFICATION_TICKER,
+ STATUS_BAR_DISABLE_SYSTEM_INFO,
+ STATUS_BAR_DISABLE_HOME,
+ STATUS_BAR_DISABLE_BACK,
+ STATUS_BAR_DISABLE_CLOCK,
+ STATUS_BAR_DISABLE_RECENT,
+ STATUS_BAR_DISABLE_SEARCH,
+ STATUS_BAR_TRANSIENT,
+ NAVIGATION_BAR_TRANSIENT,
+ STATUS_BAR_UNHIDE,
+ NAVIGATION_BAR_UNHIDE,
+ STATUS_BAR_TRANSLUCENT,
+ NAVIGATION_BAR_TRANSLUCENT,
+ NAVIGATION_BAR_TRANSPARENT,
+ STATUS_BAR_TRANSPARENT,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface SystemUiVisibility {}
+
+ /**
* Reference count for transient state.
* @see #setHasTransientState(boolean)
*/
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 795e8f3..1d54d92 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -1229,32 +1229,54 @@
* @hide
*/
@IntDef(prefix = "TYPE_", value = {
- TYPE_ACCESSIBILITY_OVERLAY,
- TYPE_APPLICATION,
- TYPE_APPLICATION_ATTACHED_DIALOG,
- TYPE_APPLICATION_MEDIA,
- TYPE_APPLICATION_OVERLAY,
- TYPE_APPLICATION_PANEL,
- TYPE_APPLICATION_STARTING,
- TYPE_APPLICATION_SUB_PANEL,
TYPE_BASE_APPLICATION,
+ TYPE_APPLICATION,
+ TYPE_APPLICATION_STARTING,
TYPE_DRAWN_APPLICATION,
+ TYPE_APPLICATION_PANEL,
+ TYPE_APPLICATION_MEDIA,
+ TYPE_APPLICATION_SUB_PANEL,
+ TYPE_APPLICATION_ATTACHED_DIALOG,
+ TYPE_APPLICATION_MEDIA_OVERLAY,
+ TYPE_APPLICATION_ABOVE_SUB_PANEL,
+ TYPE_STATUS_BAR,
+ TYPE_SEARCH_BAR,
+ TYPE_PHONE,
+ TYPE_SYSTEM_ALERT,
+ TYPE_KEYGUARD,
+ TYPE_TOAST,
+ TYPE_SYSTEM_OVERLAY,
+ TYPE_PRIORITY_PHONE,
+ TYPE_SYSTEM_DIALOG,
+ TYPE_KEYGUARD_DIALOG,
+ TYPE_SYSTEM_ERROR,
TYPE_INPUT_METHOD,
TYPE_INPUT_METHOD_DIALOG,
- TYPE_KEYGUARD,
- TYPE_KEYGUARD_DIALOG,
- TYPE_PHONE,
- TYPE_PRIORITY_PHONE,
- TYPE_PRIVATE_PRESENTATION,
- TYPE_SEARCH_BAR,
- TYPE_STATUS_BAR,
- TYPE_STATUS_BAR_PANEL,
- TYPE_SYSTEM_ALERT,
- TYPE_SYSTEM_DIALOG,
- TYPE_SYSTEM_ERROR,
- TYPE_SYSTEM_OVERLAY,
- TYPE_TOAST,
TYPE_WALLPAPER,
+ TYPE_STATUS_BAR_PANEL,
+ TYPE_SECURE_SYSTEM_OVERLAY,
+ TYPE_DRAG,
+ TYPE_STATUS_BAR_SUB_PANEL,
+ TYPE_POINTER,
+ TYPE_NAVIGATION_BAR,
+ TYPE_VOLUME_OVERLAY,
+ TYPE_BOOT_PROGRESS,
+ TYPE_INPUT_CONSUMER,
+ TYPE_NAVIGATION_BAR_PANEL,
+ TYPE_DISPLAY_OVERLAY,
+ TYPE_MAGNIFICATION_OVERLAY,
+ TYPE_PRIVATE_PRESENTATION,
+ TYPE_VOICE_INTERACTION,
+ TYPE_ACCESSIBILITY_OVERLAY,
+ TYPE_VOICE_INTERACTION_STARTING,
+ TYPE_DOCK_DIVIDER,
+ TYPE_QS_DIALOG,
+ TYPE_SCREENSHOT,
+ TYPE_PRESENTATION,
+ TYPE_APPLICATION_OVERLAY,
+ TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY,
+ TYPE_NOTIFICATION_SHADE,
+ TYPE_STATUS_BAR_ADDITIONAL
})
@Retention(RetentionPolicy.SOURCE)
public @interface WindowType {}
@@ -1715,6 +1737,46 @@
public static final int FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS = 0x80000000;
/**
+ * @hide
+ */
+ @IntDef(flag = true, prefix = "FLAG_", value = {
+ FLAG_ALLOW_LOCK_WHILE_SCREEN_ON,
+ FLAG_DIM_BEHIND,
+ FLAG_BLUR_BEHIND,
+ FLAG_NOT_FOCUSABLE,
+ FLAG_NOT_TOUCHABLE,
+ FLAG_NOT_TOUCH_MODAL,
+ FLAG_TOUCHABLE_WHEN_WAKING,
+ FLAG_KEEP_SCREEN_ON,
+ FLAG_LAYOUT_IN_SCREEN,
+ FLAG_LAYOUT_NO_LIMITS,
+ FLAG_FULLSCREEN,
+ FLAG_FORCE_NOT_FULLSCREEN,
+ FLAG_DITHER,
+ FLAG_SECURE,
+ FLAG_SCALED,
+ FLAG_IGNORE_CHEEK_PRESSES,
+ FLAG_LAYOUT_INSET_DECOR,
+ FLAG_ALT_FOCUSABLE_IM,
+ FLAG_WATCH_OUTSIDE_TOUCH,
+ FLAG_SHOW_WHEN_LOCKED,
+ FLAG_SHOW_WALLPAPER,
+ FLAG_TURN_SCREEN_ON,
+ FLAG_DISMISS_KEYGUARD,
+ FLAG_SPLIT_TOUCH,
+ FLAG_HARDWARE_ACCELERATED,
+ FLAG_LAYOUT_IN_OVERSCAN,
+ FLAG_TRANSLUCENT_STATUS,
+ FLAG_TRANSLUCENT_NAVIGATION,
+ FLAG_LOCAL_FOCUS_MODE,
+ FLAG_SLIPPERY,
+ FLAG_LAYOUT_ATTACHED_IN_DECOR,
+ FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Flags {}
+
+ /**
* Various behavioral options/flags. Default is none.
*
* @see #FLAG_ALLOW_LOCK_WHILE_SCREEN_ON
@@ -1809,6 +1871,7 @@
@ViewDebug.FlagToString(mask = FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS, equals = FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,
name = "DRAWS_SYSTEM_BAR_BACKGROUNDS")
}, formatToHexString = true)
+ @Flags
public int flags;
/**
@@ -2027,6 +2090,7 @@
* @hide
*/
public static final int PRIVATE_FLAG_TRUSTED_OVERLAY = 0x20000000;
+
/**
* An internal annotation for flags that can be specified to {@link #softInputMode}.
*
@@ -2041,6 +2105,38 @@
public @interface SystemFlags {}
/**
+ * @hide
+ */
+ @IntDef(flag = true, prefix="PRIVATE_FLAG_", value = {
+ PRIVATE_FLAG_FAKE_HARDWARE_ACCELERATED,
+ PRIVATE_FLAG_FORCE_HARDWARE_ACCELERATED,
+ PRIVATE_FLAG_WANTS_OFFSET_NOTIFICATIONS,
+ SYSTEM_FLAG_SHOW_FOR_ALL_USERS,
+ PRIVATE_FLAG_NO_MOVE_ANIMATION,
+ PRIVATE_FLAG_COMPATIBLE_WINDOW,
+ PRIVATE_FLAG_SYSTEM_ERROR,
+ PRIVATE_FLAG_DISABLE_WALLPAPER_TOUCH_EVENTS,
+ PRIVATE_FLAG_FORCE_SHOW_STATUS_BAR,
+ PRIVATE_FLAG_PRESERVE_GEOMETRY,
+ PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY,
+ PRIVATE_FLAG_WILL_NOT_REPLACE_ON_RELAUNCH,
+ PRIVATE_FLAG_LAYOUT_CHILD_WINDOW_IN_PARENT_FRAME,
+ PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS,
+ PRIVATE_FLAG_SUSTAINED_PERFORMANCE_MODE,
+ SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS,
+ PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY,
+ PRIVATE_FLAG_IS_SCREEN_DECOR,
+ PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION,
+ PRIVATE_FLAG_COLOR_SPACE_AGNOSTIC,
+ PRIVATE_FLAG_USE_BLAST,
+ PRIVATE_FLAG_APPEARANCE_CONTROLLED,
+ PRIVATE_FLAG_BEHAVIOR_CONTROLLED,
+ PRIVATE_FLAG_FIT_INSETS_CONTROLLED,
+ PRIVATE_FLAG_TRUSTED_OVERLAY,
+ })
+ public @interface PrivateFlags {}
+
+ /**
* Control flags that are private to the platform.
* @hide
*/
@@ -2127,6 +2223,10 @@
equals = PRIVATE_FLAG_COLOR_SPACE_AGNOSTIC,
name = "COLOR_SPACE_AGNOSTIC"),
@ViewDebug.FlagToString(
+ mask = PRIVATE_FLAG_USE_BLAST,
+ equals = PRIVATE_FLAG_USE_BLAST,
+ name = "USE_BLAST"),
+ @ViewDebug.FlagToString(
mask = PRIVATE_FLAG_APPEARANCE_CONTROLLED,
equals = PRIVATE_FLAG_APPEARANCE_CONTROLLED,
name = "APPEARANCE_CONTROLLED"),
@@ -2143,6 +2243,7 @@
equals = PRIVATE_FLAG_TRUSTED_OVERLAY,
name = "TRUSTED_OVERLAY")
})
+ @PrivateFlags
@TestApi
public int privateFlags;
diff --git a/core/proto/android/server/windowmanagerservice.proto b/core/proto/android/server/windowmanagerservice.proto
index 02213ed..c216638 100644
--- a/core/proto/android/server/windowmanagerservice.proto
+++ b/core/proto/android/server/windowmanagerservice.proto
@@ -28,6 +28,7 @@
import "frameworks/base/core/proto/android/view/surface.proto";
import "frameworks/base/core/proto/android/view/windowlayoutparams.proto";
import "frameworks/base/core/proto/android/privacy.proto";
+import "frameworks/base/core/proto/android/typedef.proto";
package com.android.server.wm;
@@ -43,8 +44,8 @@
optional string focused_app = 4;
optional IdentifierProto input_method_window = 5;
optional bool display_frozen = 6;
- optional int32 rotation = 7;
- optional int32 last_orientation = 8;
+ optional int32 rotation = 7 [(.android.typedef) = "android.view.Surface.Rotation"];
+ optional int32 last_orientation = 8 [(.android.typedef) = "android.content.pm.ActivityInfo.ScreenOrientation"];
optional int32 focused_display_id = 9;
}
@@ -177,7 +178,7 @@
repeated WindowTokenProto ime_windows = 8 [deprecated=true];
optional int32 dpi = 9;
optional .android.view.DisplayInfoProto display_info = 10;
- optional int32 rotation = 11;
+ optional int32 rotation = 11 [(.android.typedef) = "android.view.Surface.Rotation"];
optional ScreenRotationAnimationProto screen_rotation_animation = 12;
optional DisplayFramesProto display_frames = 13;
optional int32 surface_size = 14 [deprecated=true];
@@ -264,8 +265,8 @@
optional int32 display_id = 15;
optional int32 root_task_id = 16;
- optional int32 activity_type = 17;
- optional int32 resize_mode = 18;
+ optional int32 activity_type = 17 [(.android.typedef) = "android.app.WindowConfiguration.ActivityType"];
+ optional int32 resize_mode = 18 [(.android.typedef) = "android.appwidget.AppWidgetProviderInfo.ResizeModeFlags"];
optional int32 min_width = 19;
optional int32 min_height = 20;
@@ -351,7 +352,7 @@
optional .android.graphics.RectProto surface_position = 16;
optional int32 requested_width = 18;
optional int32 requested_height = 19;
- optional int32 view_visibility = 20;
+ optional int32 view_visibility = 20 [(.android.typedef) = "android.view.View.Visibility"];
optional int32 system_ui_visibility = 21;
optional bool has_surface = 22;
optional bool is_ready_for_display = 23;
@@ -424,7 +425,7 @@
option (.android.msg_privacy).dest = DEST_AUTOMATIC;
optional ConfigurationContainerProto configuration_container = 1;
- optional int32 orientation = 2;
+ optional int32 orientation = 2 [(.android.typedef) = "android.content.pm.ActivityInfo.ScreenOrientation"];
optional bool visible = 3;
optional SurfaceAnimatorProto surface_animator = 4;
repeated WindowContainerChildProto children = 5;
diff --git a/core/proto/android/typedef.proto b/core/proto/android/typedef.proto
new file mode 100644
index 0000000..be8742d
--- /dev/null
+++ b/core/proto/android/typedef.proto
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+syntax = "proto2";
+
+package android;
+
+import "google/protobuf/descriptor.proto";
+
+extend google.protobuf.FieldOptions {
+ // Used to specify the IntDef annotation type so that ints
+ // can be associated with their string representation
+
+ // 60001 is a random field numbers assigned to the custom options
+ // numbers between 50000 and 99999 are reserved for internal use within individual organizations
+ optional string typedef = 60001;
+}
diff --git a/core/proto/android/view/windowlayoutparams.proto b/core/proto/android/view/windowlayoutparams.proto
index 272a245..64e6da8 100644
--- a/core/proto/android/view/windowlayoutparams.proto
+++ b/core/proto/android/view/windowlayoutparams.proto
@@ -19,6 +19,7 @@
import "frameworks/base/core/proto/android/graphics/pixelformat.proto";
import "frameworks/base/core/proto/android/view/display.proto";
import "frameworks/base/core/proto/android/privacy.proto";
+import "frameworks/base/core/proto/android/typedef.proto";
package android.view;
option java_multiple_files = true;
@@ -27,15 +28,15 @@
message WindowLayoutParamsProto {
option (.android.msg_privacy).dest = DEST_AUTOMATIC;
- optional int32 type = 1;
+ optional int32 type = 1 [(.android.typedef) = "android.view.WindowManager.LayoutParams.WindowType"];
optional int32 x = 2;
optional int32 y = 3;
optional int32 width = 4;
optional int32 height = 5;
optional float horizontal_margin = 6;
optional float vertical_margin = 7;
- optional int32 gravity = 8;
- optional int32 soft_input_mode = 9;
+ optional int32 gravity = 8; // TODO (b/160129453): Add IntDef
+ optional int32 soft_input_mode = 9 [(.android.typedef) = "android.view.WindowManager.LayoutParams.SoftInputModeFlags"];
optional .android.graphics.PixelFormatProto.Format format = 10;
optional int32 window_animations = 11;
optional float alpha = 12;
@@ -53,17 +54,17 @@
optional float preferred_refresh_rate = 16;
optional int32 preferred_display_mode_id = 17;
optional bool has_system_ui_listeners = 18;
- optional uint32 input_feature_flags = 19;
+ optional uint32 input_feature_flags = 19; // TODO (b/160129453): Add IntDef
optional int64 user_activity_timeout = 20;
optional DisplayProto.ColorMode color_mode = 23;
- optional uint32 flags = 24;
- optional uint32 private_flags = 26;
- optional uint32 system_ui_visibility_flags = 27;
- optional uint32 subtree_system_ui_visibility_flags = 28;
- optional uint32 appearance = 29;
- optional uint32 behavior = 30;
- optional uint32 fit_insets_types = 31;
- optional uint32 fit_insets_sides = 32;
+ optional uint32 flags = 24 [(.android.typedef) = "android.view.WindowManager.LayoutParams.Flags"];
+ optional uint32 private_flags = 26 [(.android.typedef) = "android.view.WindowManager.LayoutParams.PrivateFlags"];
+ optional uint32 system_ui_visibility_flags = 27; // TODO (b/160129453): Add IntDef
+ optional uint32 subtree_system_ui_visibility_flags = 28; // TODO (b/160129453): Add IntDef
+ optional uint32 appearance = 29 [(.android.typedef) = "android.view.WindowInsetsController.Appearance"];
+ optional uint32 behavior = 30 [(.android.typedef) = "android.view.WindowInsetsController.Behavior"];
+ optional uint32 fit_insets_types = 31 [(.android.typedef) = "android.view.WindowInsets.Type.InsetsType"];
+ optional uint32 fit_insets_sides = 32 [(.android.typedef) = "android.view.WindowInsets.Side.InsetsSide"];
optional bool fit_ignore_visibility = 33;
}
diff --git a/tools/processors/intdef_mappings/Android.bp b/tools/processors/intdef_mappings/Android.bp
new file mode 100644
index 0000000..e255f7c
--- /dev/null
+++ b/tools/processors/intdef_mappings/Android.bp
@@ -0,0 +1,33 @@
+java_plugin {
+ name: "intdef-annotation-processor",
+
+ processor_class: "android.processor.IntDefProcessor",
+
+ srcs: [
+ ":framework-annotations",
+ "src/**/*.java",
+ "src/**/*.kt"
+ ],
+
+ use_tools_jar: true,
+}
+
+java_test_host {
+ name: "intdef-annotation-processor-test",
+
+ srcs: [
+ "test/**/*.java",
+ "test/**/*.kt"
+ ],
+ java_resource_dirs: ["test/resources"],
+
+ static_libs: [
+ "compile-testing-prebuilt",
+ "truth-prebuilt",
+ "junit",
+ "guava",
+ "intdef-annotation-processor"
+ ],
+
+ test_suites: ["general-tests"],
+}
\ No newline at end of file
diff --git a/tools/processors/intdef_mappings/src/android/processor/IntDefProcessor.kt b/tools/processors/intdef_mappings/src/android/processor/IntDefProcessor.kt
new file mode 100644
index 0000000..84faeea
--- /dev/null
+++ b/tools/processors/intdef_mappings/src/android/processor/IntDefProcessor.kt
@@ -0,0 +1,190 @@
+/*
+ * Copyright (C) 2020 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 android.processor
+
+import android.annotation.IntDef
+import com.sun.source.tree.IdentifierTree
+import com.sun.source.tree.MemberSelectTree
+import com.sun.source.tree.NewArrayTree
+import com.sun.source.util.SimpleTreeVisitor
+import com.sun.source.util.Trees
+import java.io.IOException
+import java.io.Writer
+import javax.annotation.processing.AbstractProcessor
+import javax.annotation.processing.RoundEnvironment
+import javax.lang.model.SourceVersion
+import javax.lang.model.element.AnnotationValue
+import javax.lang.model.element.TypeElement
+import javax.tools.Diagnostic.Kind
+import javax.tools.StandardLocation.CLASS_OUTPUT
+import kotlin.collections.set
+
+
+/**
+ * The IntDefProcessor is intended to generate a mapping from ints to their respective string
+ * identifier for each IntDef for use by Winscope or any other tool which requires such a mapping.
+ *
+ * The processor will run when building :frameworks-all and dump all the IntDef mappings found the
+ * files the make up :frameworks-all as json to outputPath.
+ */
+class IntDefProcessor : AbstractProcessor() {
+ private val outputName = "intDefMapping.json"
+
+ override fun getSupportedSourceVersion(): SourceVersion = SourceVersion.latest()
+
+ // Define what the annotation we care about are for compiler optimization
+ override fun getSupportedAnnotationTypes() = LinkedHashSet<String>().apply {
+ add(IntDef::class.java.name)
+ }
+
+ override fun process(annotations: Set<TypeElement>, roundEnv: RoundEnvironment): Boolean {
+ // There should only be one matching annotation definition for intDef
+ val annotationType = annotations.firstOrNull() ?: return false
+ val annotatedElements = roundEnv.getElementsAnnotatedWith(annotationType)
+
+ val annotationTypeToIntDefMapping = annotatedElements.associate { annotatedElement ->
+ val type = (annotatedElement as TypeElement).qualifiedName.toString()
+ val mapping = generateIntDefMapping(annotatedElement, annotationType)
+ val intDef = annotatedElement.getAnnotation(IntDef::class.java)
+ type to IntDefMapping(mapping, intDef.flag)
+ }
+
+ try {
+ outputToFile(annotationTypeToIntDefMapping)
+ } catch (e: IOException) {
+ error("Failed to write IntDef mappings :: $e")
+ }
+ return false
+ }
+
+ private fun generateIntDefMapping(
+ annotatedElement: TypeElement,
+ annotationType: TypeElement
+ ): Map<Int, String> {
+ // LinkedHashMap makes sure ordering is the same as in the code
+ val mapping = LinkedHashMap<Int, String>()
+
+ val annotationMirror = annotatedElement.annotationMirrors
+ // Should only ever be one matching this condition
+ .first { it.annotationType.asElement() == annotationType }
+
+ val value = annotationMirror.elementValues.entries
+ .first { entry -> entry.key.simpleName.contentEquals("value") }
+ .value
+
+ val trees = Trees.instance(processingEnv)
+ val tree = trees.getTree(annotatedElement, annotationMirror, value)
+
+ val identifiers = ArrayList<String>()
+ tree.accept(IdentifierVisitor(), identifiers)
+
+ val values = value.value as List<AnnotationValue>
+
+ for (i in identifiers.indices) {
+ mapping[values[i].value as Int] = identifiers[i]
+ }
+
+ return mapping
+ }
+
+ private class IdentifierVisitor : SimpleTreeVisitor<Void, ArrayList<String>>() {
+ override fun visitNewArray(node: NewArrayTree, indentifiers: ArrayList<String>): Void? {
+ for (initializer in node.initializers) {
+ initializer.accept(this, indentifiers)
+ }
+
+ return null
+ }
+
+ override fun visitMemberSelect(node: MemberSelectTree, indentifiers: ArrayList<String>):
+ Void? {
+ indentifiers.add(node.identifier.toString())
+
+ return null
+ }
+
+ override fun visitIdentifier(node: IdentifierTree, indentifiers: ArrayList<String>): Void? {
+ indentifiers.add(node.name.toString())
+
+ return null
+ }
+ }
+
+ @Throws(IOException::class)
+ private fun outputToFile(annotationTypeToIntDefMapping: Map<String, IntDefMapping>) {
+ val resource = processingEnv.filer.createResource(
+ CLASS_OUTPUT, "com.android.winscope", outputName)
+ val writer = resource.openWriter()
+ serializeTo(annotationTypeToIntDefMapping, writer)
+ writer.close()
+ }
+
+ private fun error(message: String) {
+ processingEnv.messager.printMessage(Kind.ERROR, message)
+ }
+
+ private fun note(message: String) {
+ processingEnv.messager.printMessage(Kind.NOTE, message)
+ }
+
+ class IntDefMapping(val mapping: Map<Int, String>, val flag: Boolean) {
+ val size
+ get() = this.mapping.size
+
+ val entries
+ get() = this.mapping.entries
+ }
+
+ companion object {
+ fun serializeTo(
+ annotationTypeToIntDefMapping: Map<String, IntDefMapping>,
+ writer: Writer
+ ) {
+ val indent = " "
+
+ writer.appendln("{")
+
+ val intDefTypesCount = annotationTypeToIntDefMapping.size
+ var currentIntDefTypesCount = 0
+ for ((field, intDefMapping) in annotationTypeToIntDefMapping) {
+ writer.appendln("""$indent"$field": {""")
+
+ // Start IntDef
+
+ writer.appendln("""$indent$indent"flag": ${intDefMapping.flag},""")
+
+ writer.appendln("""$indent$indent"values": {""")
+ intDefMapping.entries.joinTo(writer, separator = ",\n") { (value, identifier) ->
+ """$indent$indent$indent"$value": "$identifier""""
+ }
+ writer.appendln()
+ writer.appendln("$indent$indent}")
+
+ // End IntDef
+
+ writer.append("$indent}")
+ if (++currentIntDefTypesCount < intDefTypesCount) {
+ writer.appendln(",")
+ } else {
+ writer.appendln("")
+ }
+ }
+
+ writer.appendln("}")
+ }
+ }
+}
diff --git a/tools/processors/intdef_mappings/test/android/processor/IntDefProcessorTest.kt b/tools/processors/intdef_mappings/test/android/processor/IntDefProcessorTest.kt
new file mode 100644
index 0000000..c0c159c
--- /dev/null
+++ b/tools/processors/intdef_mappings/test/android/processor/IntDefProcessorTest.kt
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2020 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 android.processor
+
+import android.processor.IntDefProcessor.IntDefMapping
+import com.google.common.collect.ObjectArrays.concat
+import com.google.testing.compile.CompilationSubject.assertThat
+import com.google.testing.compile.Compiler.javac
+import com.google.testing.compile.JavaFileObjects
+import junit.framework.Assert.assertEquals
+import org.junit.Test
+import java.io.StringWriter
+import javax.tools.JavaFileObject
+import javax.tools.StandardLocation.CLASS_OUTPUT
+
+/**
+ * Tests for [IntDefProcessor]
+ */
+class IntDefProcessorTest {
+ private val mAnnotations = arrayOf<JavaFileObject>(
+ JavaFileObjects.forSourceLines("android.annotation.IntDef",
+ "package android.annotation;",
+ "import java.lang.annotation.Retention;",
+ "import java.lang.annotation.Target;",
+ "import static java.lang.annotation.ElementType.ANNOTATION_TYPE;",
+ "import static java.lang.annotation.RetentionPolicy.SOURCE;",
+ "@Retention(SOURCE)",
+ "@Target({ANNOTATION_TYPE})",
+ "public @interface IntDef {",
+ " String[] prefix() default {};",
+ " String[] suffix() default {};",
+ " int[] value() default {};",
+ " boolean flag() default false;",
+ "}")
+ )
+
+ @Test
+ public fun annotationProcessorGeneratesMapping() {
+ val sources: Array<JavaFileObject> = arrayOf(
+ JavaFileObjects.forSourceLines(
+ "com.android.server.accessibility.magnification.MagnificationGestureMatcher",
+ "package com.android.server.accessibility.magnification;",
+ "import android.annotation.IntDef;",
+ "import java.lang.annotation.Retention;",
+ "import java.lang.annotation.RetentionPolicy;",
+ "class MagnificationGestureMatcher {",
+ " private static final int GESTURE_BASE = 100;",
+ " public static final int GESTURE_TWO_FINGER_DOWN = GESTURE_BASE + 1;",
+ " public static final int GESTURE_SWIPE = GESTURE_BASE + 2;",
+ " @IntDef(prefix = {\"GESTURE_MAGNIFICATION_\"}, value = {",
+ " GESTURE_TWO_FINGER_DOWN,",
+ " GESTURE_SWIPE",
+ " })",
+ " @Retention(RetentionPolicy.SOURCE)",
+ " @interface GestureId {}",
+ "}"
+ ),
+ JavaFileObjects.forSourceLines(
+ "android.service.storage.ExternalStorageService",
+ "package android.service.storage;",
+ "import android.annotation.IntDef;",
+ "import java.lang.annotation.Retention;",
+ "import java.lang.annotation.RetentionPolicy;",
+ "class MagnificationGestureMatcher {",
+ " public static final int FLAG_SESSION_TYPE_FUSE = 1 << 0;",
+ " public static final int FLAG_SESSION_ATTRIBUTE_INDEXABLE = 1 << 1;",
+ " @IntDef(flag = true, prefix = {\"FLAG_SESSION_\"},",
+ " value = {FLAG_SESSION_TYPE_FUSE, FLAG_SESSION_ATTRIBUTE_INDEXABLE})",
+ " @Retention(RetentionPolicy.SOURCE)",
+ " public @interface SessionFlag {}",
+ "}"
+ )
+ )
+
+ val expectedFile = """
+ {
+ "com.android.server.accessibility.magnification.MagnificationGestureMatcher.GestureId": {
+ "flag": false,
+ "values": {
+ "101": "GESTURE_TWO_FINGER_DOWN",
+ "102": "GESTURE_SWIPE"
+ }
+ },
+ "android.service.storage.MagnificationGestureMatcher.SessionFlag": {
+ "flag": true,
+ "values": {
+ "1": "FLAG_SESSION_TYPE_FUSE",
+ "2": "FLAG_SESSION_ATTRIBUTE_INDEXABLE"
+ }
+ }
+ }
+
+ """.trimIndent()
+
+ val filesToCompile = concat(mAnnotations, sources, JavaFileObject::class.java)
+
+ val compilation = javac()
+ .withProcessors(IntDefProcessor())
+ .compile(filesToCompile.toMutableList())
+
+ assertThat(compilation).succeeded()
+ assertThat(compilation).generatedFile(CLASS_OUTPUT, "com.android.winscope",
+ "intDefMapping.json").contentsAsUtf8String().isEqualTo(expectedFile)
+ }
+
+ @Test
+ public fun serializesMappingCorrectly() {
+ val map = linkedMapOf(
+ "SimpleIntDef" to IntDefMapping(linkedMapOf(
+ 0x0001 to "VAL_1",
+ 0x0002 to "VAL_2",
+ 0x0003 to "VAL_3"
+ ), flag = false),
+ "Flags" to IntDefMapping(linkedMapOf(
+ 0b0001 to "PRIVATE_FLAG_1",
+ 0b0010 to "PRIVATE_FLAG_2",
+ 0b0100 to "PRIVATE_FLAG_3"
+ ), flag = true)
+ )
+
+ val writer = StringWriter()
+ IntDefProcessor.serializeTo(map, writer)
+
+ val actualOutput = writer.toString()
+ val expectedOutput = """
+ {
+ "SimpleIntDef": {
+ "flag": false,
+ "values": {
+ "1": "VAL_1",
+ "2": "VAL_2",
+ "3": "VAL_3"
+ }
+ },
+ "Flags": {
+ "flag": true,
+ "values": {
+ "1": "PRIVATE_FLAG_1",
+ "2": "PRIVATE_FLAG_2",
+ "4": "PRIVATE_FLAG_3"
+ }
+ }
+ }
+
+ """.trimIndent()
+
+ assertEquals(actualOutput, expectedOutput)
+ }
+}
\ No newline at end of file