1 /*
2  * Copyright 2018 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  */
16 
17 package android.view.inspector;
18 
19 import android.annotation.AnyRes;
20 import android.annotation.ColorInt;
21 import android.annotation.ColorLong;
22 import android.annotation.NonNull;
23 import android.annotation.Nullable;
24 import android.graphics.Color;
25 
26 /**
27  * An interface for reading the properties of an inspectable object.
28  *
29  * {@code PropertyReader} is defined as an interface that will be called by
30  * {@link InspectionCompanion#readProperties(Object, PropertyReader)}. This approach allows a
31  * client inspector to read the values of primitive properties without the overhead of
32  * instantiating a class to hold the property values for each inspection pass. If an inspectable
33  * remains unchanged between reading passes, it should be possible for a {@code PropertyReader} to
34  * avoid new allocations for subsequent reading passes.
35  *
36  * It has separate methods for all primitive types to avoid autoboxing overhead if a concrete
37  * implementation is able to work with primitives. Implementations should be prepared to accept
38  * {null} as the value of {@link PropertyReader#readObject(int, Object)}.
39  *
40  * @see InspectionCompanion#readProperties(Object, PropertyReader)
41  */
42 public interface PropertyReader {
43     /**
44      * Read a primitive boolean property.
45      *
46      * @param id Identifier of the property from a {@link PropertyMapper}
47      * @param value Value of the property
48      * @throws PropertyTypeMismatchException If the property ID is not mapped as a {@code boolean}
49      */
readBoolean(int id, boolean value)50     void readBoolean(int id, boolean value);
51 
52     /**
53      * Read a primitive byte property.
54      *
55      * @param id Identifier of the property from a {@link PropertyMapper}
56      * @param value Value of the property
57      * @throws PropertyTypeMismatchException If the property ID is not mapped as a {@code byte}
58      */
readByte(int id, byte value)59     void readByte(int id, byte value);
60 
61     /**
62      * Read a primitive character property.
63      *
64      * @param id Identifier of the property from a {@link PropertyMapper}
65      * @param value Value of the property
66      * @throws PropertyTypeMismatchException If the property ID is not mapped as a {@code char}
67      */
readChar(int id, char value)68     void readChar(int id, char value);
69 
70     /**
71      * Read a read a primitive double property.
72      *
73      * @param id Identifier of the property from a {@link PropertyMapper}
74      * @param value Value of the property
75      * @throws PropertyTypeMismatchException If the property ID is not mapped as a {@code double}
76      */
readDouble(int id, double value)77     void readDouble(int id, double value);
78 
79     /**
80      * Read a primitive float property.
81      *
82      * @param id Identifier of the property from a {@link PropertyMapper}
83      * @param value Value of the property
84      * @throws PropertyTypeMismatchException If the property ID is not mapped as a {@code float}
85      */
readFloat(int id, float value)86     void readFloat(int id, float value);
87 
88     /**
89      * Read a primitive integer property.
90      *
91      * @param id Identifier of the property from a {@link PropertyMapper}
92      * @param value Value of the property
93      * @throws PropertyTypeMismatchException If the property ID is not mapped as an {@code int}
94      */
readInt(int id, int value)95     void readInt(int id, int value);
96 
97     /**
98      * Read a primitive long property.
99      *
100      * @param id Identifier of the property from a {@link PropertyMapper}
101      * @param value Value of the property
102      * @throws PropertyTypeMismatchException If the property ID is not mapped as a {@code long}
103      */
readLong(int id, long value)104     void readLong(int id, long value);
105 
106     /**
107      * Read a primitive short property.
108      *
109      * @param id Identifier of the property from a {@link PropertyMapper}
110      * @param value Value of the property
111      * @throws PropertyTypeMismatchException If the property ID is not mapped as a {@code short}
112      */
readShort(int id, short value)113     void readShort(int id, short value);
114 
115     /**
116      * Read any object as a property.
117      *
118      * If value is null, the property is marked as empty.
119      *
120      * @param id Identifier of the property from a {@link PropertyMapper}
121      * @param value Value of the property
122      * @throws PropertyTypeMismatchException If the property ID is not mapped as an object
123      */
readObject(int id, @Nullable Object value)124     void readObject(int id, @Nullable Object value);
125 
126     /**
127      * Read a color packed into a {@link ColorInt} as a property.
128      *
129      * @param id Identifier of the property from a {@link PropertyMapper}
130      * @param value Value of the property
131      * @throws PropertyTypeMismatchException If the property ID is not mapped as a color
132      */
readColor(int id, @ColorInt int value)133     void readColor(int id, @ColorInt int value);
134 
135     /**
136      * Read a color packed into a {@code ColorLong} as a property.
137      *
138      * @param id Identifier of the property from a {@link PropertyMapper}
139      * @param value Value of the property packed as a {@code ColorLong}. See the
140      *              {@link Color} class for details of the packing.
141      * @throws PropertyTypeMismatchException If the property ID is not mapped as a color
142      */
readColor(int id, @ColorLong long value)143     void readColor(int id, @ColorLong long value);
144 
145     /**
146      * Read a {@link Color} object as a property.
147      *
148      * @param id Identifier of the property from a {@link PropertyMapper}
149      * @param value Value of the property
150      * @throws PropertyTypeMismatchException If the property ID is not mapped as a color
151      */
readColor(int id, @Nullable Color value)152     void readColor(int id, @Nullable Color value);
153 
154     /**
155      * Read {@link android.view.Gravity} packed into an primitive {@code int}.
156      *
157      * @param id Identifier of the property from a {@link PropertyMapper}
158      * @param value Value of the property
159      * @throws PropertyTypeMismatchException If the property ID is not mapped as a gravity property
160      */
readGravity(int id, int value)161     void readGravity(int id, int value);
162 
163     /**
164      * Read an enumeration packed into a primitive {@code int}.
165      *
166      * @param id Identifier of the property from a {@link PropertyMapper}
167      * @param value Value of the property
168      * @throws PropertyTypeMismatchException If the property ID is not mapped as an object
169      */
readIntEnum(int id, int value)170     void readIntEnum(int id, int value);
171 
172     /**
173      * Read a flag packed into a primitive {@code int}.
174      *
175      * @param id Identifier of the property from a {@link PropertyMapper}
176      * @param value Value of the property
177      * @throws PropertyTypeMismatchException If the property ID is not mapped as an object
178      */
readIntFlag(int id, int value)179     void readIntFlag(int id, int value);
180 
181     /**
182      * Read an integer that contains a resource ID.
183      *
184      * @param id Identifier of the property from a {@link PropertyMapper}
185      * @param value Value of the property
186      * @throws PropertyTypeMismatchException If the property ID is not mapped as a resource ID.
187      */
readResourceId(int id, @AnyRes int value)188     void readResourceId(int id, @AnyRes int value);
189 
190     /**
191      * Thrown if a client calls a typed read method for a property of a different type.
192      */
193     class PropertyTypeMismatchException extends RuntimeException {
PropertyTypeMismatchException( int id, @NonNull String expectedPropertyType, @NonNull String actualPropertyType, @Nullable String propertyName)194         public PropertyTypeMismatchException(
195                 int id,
196                 @NonNull String expectedPropertyType,
197                 @NonNull String actualPropertyType,
198                 @Nullable String propertyName) {
199             super(formatMessage(id, expectedPropertyType, actualPropertyType, propertyName));
200         }
201 
PropertyTypeMismatchException( int id, @NonNull String expectedPropertyType, @NonNull String actualPropertyType)202         public PropertyTypeMismatchException(
203                 int id,
204                 @NonNull String expectedPropertyType,
205                 @NonNull String actualPropertyType) {
206             super(formatMessage(id, expectedPropertyType, actualPropertyType, null));
207         }
208 
formatMessage( int id, @NonNull String expectedPropertyType, @NonNull String actualPropertyType, @Nullable String propertyName)209         private static @NonNull String formatMessage(
210                 int id,
211                 @NonNull String expectedPropertyType,
212                 @NonNull String actualPropertyType,
213                 @Nullable String propertyName) {
214 
215             if (propertyName == null) {
216                 return String.format(
217                         "Attempted to read property with ID 0x%08X as type %s, "
218                             + "but the ID is of type %s.",
219                         id,
220                         expectedPropertyType,
221                         actualPropertyType
222                 );
223             } else {
224                 return String.format(
225                         "Attempted to read property \"%s\" with ID 0x%08X as type %s, "
226                             + "but the ID is of type %s.",
227                         propertyName,
228                         id,
229                         expectedPropertyType,
230                         actualPropertyType
231                 );
232             }
233         }
234     }
235 }
236