1/*
2 * Copyright 2021 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16syntax = "proto3";
17package layoutinspector.compose.inspection;
18option java_package = "layoutinspector.compose.inspection";
19option java_outer_classname = "LayoutInspectorComposeProtocol";
20
21// ======= MESSAGES =======
22
23// A mapping of |string| to |int32|, so strings can be efficiently reused across nodes
24// Any time a text value in any of these messages has an |int32| type, it means it will do a
25// lookup in a string table on the client.
26message StringEntry {
27    int32 id = 1;
28    string str = 2;
29}
30
31message Point {
32    int32 x = 1;
33    int32 y = 2;
34}
35
36message Rect {
37    int32 x = 1;
38    int32 y = 2;
39    int32 w = 3;
40    int32 h = 4;
41}
42
43// A Quad holds the 4 corners of a polygon in drawing order, that represent the transformed shape
44// of a Rect after applying some affine or perspective transformations.
45message Quad {
46    sint32 x0 = 1;
47    sint32 y0 = 2;
48    sint32 x1 = 3;
49    sint32 y1 = 4;
50    sint32 x2 = 5;
51    sint32 y2 = 6;
52    sint32 x3 = 7;
53    sint32 y3 = 8;
54}
55
56message Bounds {
57    // The bounds of some element in the layout tree
58    Rect layout = 1;
59    // Bounds transformed in preparation for final rendering
60    Quad render = 2;
61}
62
63message ComposableRoot {
64    // The ID of the View this Composable tree is rooted underneath
65    int64 view_id = 1;
66    // All composables owned by this view (usually just one but could be more)
67    repeated ComposableNode nodes = 2;
68    // All views owned by this view that should be hidden
69    repeated int64 views_to_skip = 3;
70}
71
72message ComposableNode {
73    sint64 id = 1;
74    repeated ComposableNode children = 2;
75
76    // The hash of the file's package, for disambiguating same filenames in different folders
77    int32 package_hash = 3;
78    int32 filename = 4; // The file this Composable is defined in
79    int32 line_number = 5;  // The line number within the file
80    int32 offset = 6; // Offset into the file for the exact character position
81
82    int32 name = 7;
83
84    Bounds bounds = 8;
85
86    enum Flags {
87      NONE = 0;
88      SYSTEM_CREATED = 0x1;
89      HAS_MERGED_SEMANTICS = 0x2;
90      HAS_UNMERGED_SEMANTICS = 0x4;
91      INLINED = 0x8;
92      // If a node has the NESTED_SINGLE_CHILDREN flag, it means the children should be
93      // interpreted as a subtree of single nodes.
94      NESTED_SINGLE_CHILDREN = 0x10;
95    }
96    int32 flags = 9;
97
98    int64 view_id = 10;
99
100    // The number of recompositions detected since the last counter reset
101    int32 recompose_count = 11;
102
103    // The number of recomposition skips detected since the last counter reset
104    int32 recompose_skips = 12;
105
106    // The unique id of an anchor. This used to be its hashcode. See InspectorNode.anchorId.
107    sint32 anchor_hash = 13;
108}
109
110// In Android, a resource id is a simple integer. This class holds the namespace, type, and name
111// of such a resource id.
112// For example, with "@android:id/textView":
113//   type: id
114//   namespace: android
115//   name: textView
116message Resource {
117    int32 type = 1;
118    int32 namespace = 2;
119    int32 name = 3;
120}
121
122// Data that helps us identify a lambda block in code
123message LambdaValue {
124  int32 package_name = 1;       // the package part of the containing class name
125  int32 file_name = 2;          // the file name of the containing class
126  int32 lambda_name = 3;        // the name of the lambda class
127  int32 function_name = 4;      // the function name if this is a function reference
128  int32 start_line_number = 5;  // the line number of the start of the lambda
129  int32 end_line_number = 6;    // the line number of the end of the lambda
130}
131
132// Parameters to a @Composable function
133message Parameter {
134    enum Type {
135      UNSPECIFIED = 0;
136      STRING = 1;
137      BOOLEAN = 2;
138      DOUBLE = 3;
139      FLOAT = 4;
140      INT32 = 5;
141      INT64 = 6;
142      COLOR = 7;
143      RESOURCE = 8;
144      DIMENSION_DP = 9;
145      DIMENSION_SP = 10;
146      DIMENSION_EM = 11;
147      LAMBDA = 12;
148      FUNCTION_REFERENCE = 13;
149      ITERABLE = 14;
150    }
151
152    Type type = 1;
153    int32 name = 2;
154    repeated Parameter elements = 3;
155    ParameterReference reference = 4;
156
157    // For elements inside another Parameter instance, this index refer to the
158    // "natural" index of the parent composite value in the agent.
159    //
160    // We record this to be able to identify a reference to another parameter in
161    // the client and agent. Note that e.g:
162    //   - null elements in a List are omitted
163    // A reference will indicate the index among all values, such that we don't
164    // have to count nulls during a GetParameterDetailsCommand.
165    sint32 index = 5;
166
167    oneof value {
168        int32 int32_value = 11;
169        int64 int64_value = 12;
170        double double_value = 13;
171        float float_value = 14;
172        Resource resource_value = 15;
173        LambdaValue lambda_value = 16;
174    }
175}
176
177// A reference to a "part" of a parameter value
178message ParameterReference {
179  enum Kind {
180    UNSPECIFIED = 0;
181    NORMAL = 1;
182    MERGED_SEMANTICS = 2;
183    UNMERGED_SEMANTICS = 3;
184  }
185
186  sint64 composable_id = 1;
187
188  // Identifies an index into a ParameterGroup
189  int32 parameter_index = 2;
190
191  // If the parameter value is a composite value such as:
192  //    List<MyClass>
193  // then:
194  //    composite_index[0] is the index into the List
195  //    composite_index[1] is the index into the fields in MyClass
196  //    composite_index[2] is the index into the field found by [1] etc...
197  repeated int32 composite_index = 3;
198
199  // The kind of parameter this is a reference to
200  Kind kind = 4;
201
202  // The anchor hash of the composable. See InspectorNode.anchorId.
203  sint32 anchor_hash = 5;
204}
205
206// A collection of all parameters associated with a single composable
207message ParameterGroup {
208  sint64 composable_id = 1;
209  repeated Parameter parameter = 3;
210  repeated Parameter merged_semantics = 4;
211  repeated Parameter unmerged_semantics = 5;
212}
213
214// ======= COMMANDS, RESPONSES, AND EVENTS =======
215
216// Response fired when incoming command bytes cannot be parsed or handled. This may occur if a newer
217// version of the client tries to interact with an older inspector.
218message UnknownCommandResponse {
219  // The initial command bytes received that couldn't be handled. By returning this back to the
220  // client, it should be able to identify what they sent that failed on the inspector side.
221  bytes command_bytes = 1;
222}
223
224// Request all composables found under a layout tree rooted under the specified view
225message GetComposablesCommand {
226   int64 root_view_id = 1;
227  // If true, only show composable nodes created by the user's own app
228  bool skip_system_composables = 2;
229  // If the cached data generation matches the specified generation then the cache is still valid.
230  int32 generation = 3;
231  // If true, extract all parameters even if `delayParameterExtractions` is off.
232  bool extract_all_parameters = 4;
233}
234
235message GetComposablesResponse {
236    // A collection of all text referenced by other fields in this message
237    repeated StringEntry strings = 1;
238    repeated ComposableRoot roots = 2;
239}
240
241message GetParametersCommand {
242  int64 root_view_id = 1; // Used for filtering out composables from unrelated layout trees
243  sint64 composable_id = 2;
244  // As an optimization, we can skip over searching system composables if we know we don't care
245  // about them.
246  bool skip_system_composables = 3;
247  // Max number of recursions into nested composite parameter values.
248  // It is possible to dig in further by using: GetParameterDetailsCommand.
249  // If not specified the default is 2.
250  int32 max_recursions = 4;
251  // Max number of initial elements in an iterable such as a List/Array.
252  // It is possible to request more elements by using: GetParameterDetailsCommand.
253  // If not specified the default is 5.
254  int32 max_initial_iterable_size = 5;
255  // If the cached data generation matches the specified generation then the cache is still valid.
256  int32 generation = 6;
257  // The anchor hash of the composable. See InspectorNode.anchorId.
258  sint32 anchor_hash = 7;
259}
260
261message GetParametersResponse {
262  // A collection of all text referenced by other fields in this message
263  repeated StringEntry strings = 1;
264  ParameterGroup parameter_group = 2;
265}
266
267// Request all parameters for all composables under a particular layout tree
268message GetAllParametersCommand {
269  int64 root_view_id = 1;
270  bool skip_system_composables = 2;
271  int32 max_recursions = 3;
272  int32 max_initial_iterable_size = 4;
273  // If the cached data generation matches the specified generation then the cache is still valid.
274  int32 generation = 5;
275}
276
277message GetAllParametersResponse {
278  int64 root_view_id = 1; // Echoed from GetAllParametersCommand
279  repeated StringEntry strings = 2;
280  repeated ParameterGroup parameter_groups = 3;
281}
282
283// Request parameter details for the parameter specified
284message GetParameterDetailsCommand {
285  int64 root_view_id = 1;
286  ParameterReference reference = 2;
287  int32 start_index = 3;
288  int32 max_elements = 4;
289  bool skip_system_composables = 5;
290  int32 max_recursions = 6;
291  int32 max_initial_iterable_size = 7;
292  // If the cached data generation matches the specified generation then the cache is still valid.
293  int32 generation = 8;
294}
295
296message GetParameterDetailsResponse {
297  int64 root_view_id = 1; // Echoed from GetParameterDetailsCommand
298  repeated StringEntry strings = 2;
299  Parameter parameter = 3;
300}
301
302message UpdateSettingsCommand {
303  // If true, start (or continue) counting repositions.
304  // If false stop counting recompositions.
305  bool include_recompose_counts = 1;
306  // If true, the recomposition counts will be kept.
307  // If false, the recomposition counts will be reset.
308  bool keep_recompose_counts = 2;
309  // If true, the compose parameters will not be extracted before
310  bool delay_parameter_extractions = 3;
311  // If true, encode nested single children under the top node.
312  bool reduce_child_nesting = 4;
313}
314
315// The active settings after handling of an UpdateSettingsCommand
316message UpdateSettingsResponse {
317  // If true, the agent has the capability for delaying parameter extractions
318  bool can_delay_parameter_extractions = 3;
319}
320
321message Command {
322  oneof specialized {
323    GetComposablesCommand get_composables_command = 1;
324    GetParametersCommand get_parameters_command = 2;
325    GetAllParametersCommand get_all_parameters_command = 3;
326    GetParameterDetailsCommand get_parameter_details_command = 4;
327    UpdateSettingsCommand update_settings_command = 5;
328  }
329}
330
331message Response {
332  oneof specialized {
333    GetComposablesResponse get_composables_response = 1;
334    GetParametersResponse get_parameters_response = 2;
335    GetAllParametersResponse get_all_parameters_response = 3;
336    GetParameterDetailsResponse get_parameter_details_response = 4;
337    UpdateSettingsResponse update_settings_response = 5;
338
339    UnknownCommandResponse unknown_command_response = 100;
340  }
341}
342