1 /* 2 * Copyright 2023 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 androidx.appsearch.safeparcel; 18 19 import android.os.Parcel; 20 21 import androidx.annotation.RestrictTo; 22 23 import org.jspecify.annotations.NonNull; 24 25 /** 26 * Implements {@link SafeParcelable}. 27 * 28 * <p>In Jetpack, the annotations from {@SafeParcelable} are moved here so {@code NULL} can be 29 * package private. 30 * 31 * <p>This class is put in androidx.appsearch.app. Thus we can restrict the scope to avoid making it 32 * public. 33 * 34 * <p>DON'T modify this class unless it is necessary. E.g. port new annotations from SafeParcelable. 35 */ 36 // @exportToFramework:skipFile() 37 @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) 38 public abstract class AbstractSafeParcelable implements SafeParcelable { 39 // Note: the field name and value are accessed using reflection for backwards compatibility, and 40 // must not be changed. 41 static final String NULL = "SAFE_PARCELABLE_NULL_STRING"; 42 43 /** Use this annotation on members that you wish to be marshalled in the SafeParcelable. */ 44 public @interface Field { 45 /** 46 * Valid values for id are between 1 and 65535. This field id is marshalled into a Parcel 47 * . To 48 * maintain backwards compatibility, never reuse old id's. It is okay to no longer use 49 * old id's 50 * and add new ones in subsequent versions of a SafeParcelable. 51 */ id()52 int id(); 53 54 /** 55 * This specifies the name of the getter method for retrieving the value of this field. This 56 * must be specified for fields that do not have at least package visibility because the 57 * "creator" class will be unable to access the value when attempting to marshall this 58 * field. 59 * The getter method should take no parameters and return the type of this field (unless 60 * overridden by the "type" attribute below). 61 */ getter()62 String getter() default NULL; 63 64 /** 65 * For advanced uses, this specifies the type for the field when marshalling and 66 * unmarshalling 67 * by the "creator" class to be something different than the declared type of the member 68 * variable. This is useful if you want to incorporate an object that is not 69 * SafeParcelable (or 70 * a system Parcelable object). Be sure to enter the fully qualified name for the class 71 * (i.e., 72 * android.os.Bundle and not Bundle). For example, 73 * 74 * <pre> 75 * @Class(creator="MyAdvancedCreator") 76 * public class MyAdvancedSafeParcelable implements SafeParcelable { 77 * public static final Parcelable.Creator<MyAdvancedSafeParcelable> CREATOR = 78 * new MyAdvancedCreator(); 79 * 80 * @Field(id=1, getter="getObjectAsBundle", type="android.os.Bundle") 81 * private final MyCustomObject myObject; 82 * 83 * @Constructor 84 * MyAdvancedSafeParcelable( 85 * @Param(id=1) Bundle objectAsBundle) { 86 * myObject = myConvertFromBundleToObject(objectAsBundle); 87 * } 88 * 89 * Bundle getObjectAsBundle() { 90 * // The code here can convert your custom object to one that can be parcelled. 91 * return myConvertFromObjectToBundle(myObject); 92 * } 93 * 94 * ... 95 * } 96 * </pre> 97 */ type()98 String type() default NULL; 99 100 /** 101 * This can be used to specify the default value for primitive types (e.g., boolean, int, 102 * long), 103 * primitive type object wrappers (e.g., Boolean, Integer, Long) and String in the case a 104 * value 105 * for a field was not explicitly set in the marshalled Parcel. This performs compile-time 106 * checks for the type of the field and inserts the appropriate quotes or double quotes 107 * around 108 * strings and chars or removes them completely for booleans and numbers. To insert a 109 * generic 110 * string for initializing field, use {@link #defaultValueUnchecked()}. You can specify 111 * at most 112 * one of {@link #defaultValue()} or {@link #defaultValueUnchecked()}. For example, 113 * 114 * <pre> 115 * @Field(id=2, defaultValue="true") 116 * boolean myBoolean; 117 * 118 * @Field(id=3, defaultValue="13") 119 * Integer myInteger; 120 * 121 * @Field(id=4, defaultValue="foo") 122 * String myString; 123 * </pre> 124 */ defaultValue()125 String defaultValue() default NULL; 126 127 /** 128 * This can be used to specify the default value for any object and the string value is 129 * literally added to the generated creator class code unchecked. You can specify at most 130 * one of 131 * {@link #defaultValue()} or {@link #defaultValueUnchecked()}. You must fully qualify any 132 * classes you reference within the string. For example, 133 * 134 * <pre> 135 * @Field(id=2, defaultValueUnchecked="new android.os.Bundle()") 136 * Bundle myBundle; 137 * </pre> 138 */ defaultValueUnchecked()139 String defaultValueUnchecked() default NULL; 140 } 141 142 /** 143 * There may be exactly one member annotated with VersionField, which represents the version of 144 * this safe parcelable. The attributes are the same as those of {@link Field}. Note you can use 145 * any type you want for your version field, although most people use int's. 146 */ 147 public @interface VersionField { id()148 int id(); 149 getter()150 String getter() default NULL; 151 type()152 String type() default NULL; 153 } 154 155 /** 156 * Use this to indicate the member field that holds whether a field was set or not. The member 157 * field type currently supported is a HashSet<Integer> which is the set of safe 158 * parcelable field id's that have been explicitly set. 159 * 160 * <p>This annotation should also be used to annotate one of the parameters to the constructor 161 * annotated with @Constructor. Note that this annotation should either be present on 162 * exactly 163 * one member field and one constructor parameter or left out completely. 164 */ 165 public @interface Indicator { getter()166 String getter() default NULL; 167 } 168 169 /** 170 * Use this on a parameter passed in to the Constructor to indicate that a removed field 171 * should be 172 * read on construction. If the field is not present when read, the default value will be used 173 * instead. 174 */ 175 public @interface RemovedParam { id()176 int id(); 177 defaultValue()178 String defaultValue() default NULL; 179 defaultValueUnchecked()180 String defaultValueUnchecked() default NULL; 181 } 182 183 /** 184 * Use this to mark tombstones for removed {@link Field Fields} or {@link VersionField 185 * VersionFields}. 186 */ 187 public @interface Reserved { value()188 int[] value(); 189 } 190 191 /** 192 * Use this to indicate the constructor that the creator should use. The constructor annotated 193 * with this must be package or public visibility, so that the generated "creator" class can 194 * invoke this. 195 */ 196 public @interface Constructor { 197 } 198 199 /** 200 * Use this on each parameter passed in to the Constructor to indicate to which field id each 201 * formal parameter corresponds. 202 */ 203 public @interface Param { id()204 int id(); 205 } 206 207 /** 208 * To be implemented by child classes. 209 * 210 * <p>This is purely for code sync purpose. Have {@code writeToParcel} here so we can keep 211 * "@Override" in child classes. 212 */ writeToParcel(@onNull Parcel dest, int flags)213 public void writeToParcel(@NonNull Parcel dest, int flags) { 214 } 215 216 @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) 217 @Override describeContents()218 public final int describeContents() { 219 return 0; 220 } 221 } 222