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 android.app.appsearch; 18 19 import android.annotation.FlaggedApi; 20 import android.annotation.NonNull; 21 import android.annotation.Nullable; 22 import android.app.appsearch.annotation.CanIgnoreReturnValue; 23 import android.app.appsearch.safeparcel.AbstractSafeParcelable; 24 import android.app.appsearch.safeparcel.SafeParcelable; 25 import android.os.Parcel; 26 import android.os.Parcelable; 27 import android.util.ArraySet; 28 29 import com.android.appsearch.flags.Flags; 30 31 import java.util.ArrayList; 32 import java.util.List; 33 import java.util.Map; 34 import java.util.Objects; 35 import java.util.Set; 36 37 /** 38 * An expanded version of {@link SchemaVisibilityConfig} which includes fields for internal use by 39 * AppSearch. 40 * 41 * @hide 42 */ 43 @SafeParcelable.Class(creator = "InternalVisibilityConfigCreator") 44 public final class InternalVisibilityConfig extends AbstractSafeParcelable { 45 @NonNull 46 public static final Parcelable.Creator<InternalVisibilityConfig> CREATOR = 47 new InternalVisibilityConfigCreator(); 48 49 /** Build the List of {@link InternalVisibilityConfig}s from visibility settings. */ 50 @NonNull toInternalVisibilityConfigs( @onNull SetSchemaRequest setSchemaRequest)51 public static List<InternalVisibilityConfig> toInternalVisibilityConfigs( 52 @NonNull SetSchemaRequest setSchemaRequest) { 53 Set<AppSearchSchema> searchSchemas = setSchemaRequest.getSchemas(); 54 Set<String> schemasNotDisplayedBySystem = setSchemaRequest.getSchemasNotDisplayedBySystem(); 55 Map<String, Set<PackageIdentifier>> schemasVisibleToPackages = 56 setSchemaRequest.getSchemasVisibleToPackages(); 57 Map<String, Set<Set<Integer>>> schemasVisibleToPermissions = 58 setSchemaRequest.getRequiredPermissionsForSchemaTypeVisibility(); 59 Map<String, PackageIdentifier> publiclyVisibleSchemas = 60 setSchemaRequest.getPubliclyVisibleSchemas(); 61 Map<String, Set<SchemaVisibilityConfig>> schemasVisibleToConfigs = 62 setSchemaRequest.getSchemasVisibleToConfigs(); 63 64 List<InternalVisibilityConfig> result = new ArrayList<>(searchSchemas.size()); 65 for (AppSearchSchema searchSchema : searchSchemas) { 66 String schemaType = searchSchema.getSchemaType(); 67 InternalVisibilityConfig.Builder builder = 68 new InternalVisibilityConfig.Builder(schemaType) 69 .setNotDisplayedBySystem( 70 schemasNotDisplayedBySystem.contains(schemaType)); 71 72 Set<PackageIdentifier> visibleToPackages = schemasVisibleToPackages.get(schemaType); 73 if (visibleToPackages != null) { 74 for (PackageIdentifier packageIdentifier : visibleToPackages) { 75 builder.addVisibleToPackage(packageIdentifier); 76 } 77 } 78 79 Set<Set<Integer>> visibleToPermissionSets = schemasVisibleToPermissions.get(schemaType); 80 if (visibleToPermissionSets != null) { 81 for (Set<Integer> visibleToPermissions : visibleToPermissionSets) { 82 builder.addVisibleToPermissions(visibleToPermissions); 83 } 84 } 85 86 PackageIdentifier publiclyVisibleTargetPackage = publiclyVisibleSchemas.get(schemaType); 87 if (publiclyVisibleTargetPackage != null) { 88 builder.setPubliclyVisibleTargetPackage(publiclyVisibleTargetPackage); 89 } 90 91 Set<SchemaVisibilityConfig> visibleToConfigs = schemasVisibleToConfigs.get(schemaType); 92 if (visibleToConfigs != null) { 93 for (SchemaVisibilityConfig schemaVisibilityConfig : visibleToConfigs) { 94 builder.addVisibleToConfig(schemaVisibilityConfig); 95 } 96 } 97 98 result.add(builder.build()); 99 } 100 return result; 101 } 102 103 @NonNull 104 @Field(id = 1, getter = "getSchemaType") 105 private final String mSchemaType; 106 107 @Field(id = 2, getter = "isNotDisplayedBySystem") 108 private final boolean mIsNotDisplayedBySystem; 109 110 /** The public visibility settings available in VisibilityConfig. */ 111 @NonNull 112 @Field(id = 3, getter = "getVisibilityConfig") 113 private final SchemaVisibilityConfig mVisibilityConfig; 114 115 /** Extended visibility settings from {@link SetSchemaRequest#getSchemasVisibleToConfigs()} */ 116 @NonNull 117 @Field(id = 4) 118 final List<SchemaVisibilityConfig> mVisibleToConfigs; 119 120 @Constructor InternalVisibilityConfig( @aramid = 1) @onNull String schemaType, @Param(id = 2) boolean isNotDisplayedBySystem, @Param(id = 3) @NonNull SchemaVisibilityConfig schemaVisibilityConfig, @Param(id = 4) @NonNull List<SchemaVisibilityConfig> visibleToConfigs)121 InternalVisibilityConfig( 122 @Param(id = 1) @NonNull String schemaType, 123 @Param(id = 2) boolean isNotDisplayedBySystem, 124 @Param(id = 3) @NonNull SchemaVisibilityConfig schemaVisibilityConfig, 125 @Param(id = 4) @NonNull List<SchemaVisibilityConfig> visibleToConfigs) { 126 mIsNotDisplayedBySystem = isNotDisplayedBySystem; 127 mSchemaType = Objects.requireNonNull(schemaType); 128 mVisibilityConfig = Objects.requireNonNull(schemaVisibilityConfig); 129 mVisibleToConfigs = Objects.requireNonNull(visibleToConfigs); 130 } 131 132 /** 133 * Gets the schemaType for this VisibilityConfig. 134 * 135 * <p>This is being used as the document id when we convert a {@link InternalVisibilityConfig} 136 * to a {@link GenericDocument}. 137 */ 138 @NonNull getSchemaType()139 public String getSchemaType() { 140 return mSchemaType; 141 } 142 143 /** Returns whether this schema is visible to the system. */ isNotDisplayedBySystem()144 public boolean isNotDisplayedBySystem() { 145 return mIsNotDisplayedBySystem; 146 } 147 148 /** 149 * Returns the visibility settings stored in the public {@link SchemaVisibilityConfig} object. 150 */ 151 @NonNull getVisibilityConfig()152 public SchemaVisibilityConfig getVisibilityConfig() { 153 return mVisibilityConfig; 154 } 155 156 /** 157 * Returns required {@link SchemaVisibilityConfig} sets for a caller need to match to access the 158 * schema this {@link InternalVisibilityConfig} represents. 159 */ 160 @NonNull getVisibleToConfigs()161 public Set<SchemaVisibilityConfig> getVisibleToConfigs() { 162 return new ArraySet<>(mVisibleToConfigs); 163 } 164 165 @Override writeToParcel(@onNull Parcel dest, int flags)166 public void writeToParcel(@NonNull Parcel dest, int flags) { 167 InternalVisibilityConfigCreator.writeToParcel(this, dest, flags); 168 } 169 170 @Override equals(@ullable Object o)171 public boolean equals(@Nullable Object o) { 172 if (this == o) { 173 return true; 174 } 175 if (o == null) { 176 return false; 177 } 178 if (!(o instanceof InternalVisibilityConfig)) { 179 return false; 180 } 181 InternalVisibilityConfig that = (InternalVisibilityConfig) o; 182 return mIsNotDisplayedBySystem == that.mIsNotDisplayedBySystem 183 && Objects.equals(mSchemaType, that.mSchemaType) 184 && Objects.equals(mVisibilityConfig, that.mVisibilityConfig) 185 && Objects.equals(mVisibleToConfigs, that.mVisibleToConfigs); 186 } 187 188 @Override hashCode()189 public int hashCode() { 190 return Objects.hash( 191 mIsNotDisplayedBySystem, mSchemaType, mVisibilityConfig, mVisibleToConfigs); 192 } 193 194 /** The builder class of {@link InternalVisibilityConfig}. */ 195 @FlaggedApi(Flags.FLAG_ENABLE_SET_SCHEMA_VISIBLE_TO_CONFIGS) 196 public static final class Builder { 197 private String mSchemaType; 198 private boolean mIsNotDisplayedBySystem; 199 private SchemaVisibilityConfig.Builder mVisibilityConfigBuilder; 200 private List<SchemaVisibilityConfig> mVisibleToConfigs = new ArrayList<>(); 201 private boolean mBuilt; 202 203 /** 204 * Creates a {@link Builder} for a {@link InternalVisibilityConfig}. 205 * 206 * @param schemaType The SchemaType of the {@link AppSearchSchema} that this {@link 207 * InternalVisibilityConfig} represents. The package and database prefix will be added 208 * in server side. We are using prefixed schema type to be the final id of this {@link 209 * InternalVisibilityConfig}. This will be used as as an AppSearch id. 210 * @see GenericDocument#getId 211 */ Builder(@onNull String schemaType)212 public Builder(@NonNull String schemaType) { 213 mSchemaType = Objects.requireNonNull(schemaType); 214 mVisibilityConfigBuilder = new SchemaVisibilityConfig.Builder(); 215 } 216 217 /** Creates a {@link Builder} from an existing {@link InternalVisibilityConfig} */ Builder(@onNull InternalVisibilityConfig internalVisibilityConfig)218 public Builder(@NonNull InternalVisibilityConfig internalVisibilityConfig) { 219 Objects.requireNonNull(internalVisibilityConfig); 220 mSchemaType = internalVisibilityConfig.mSchemaType; 221 mIsNotDisplayedBySystem = internalVisibilityConfig.mIsNotDisplayedBySystem; 222 mVisibilityConfigBuilder = 223 new SchemaVisibilityConfig.Builder( 224 internalVisibilityConfig.getVisibilityConfig()); 225 mVisibleToConfigs = internalVisibilityConfig.mVisibleToConfigs; 226 } 227 228 /** Sets schemaType, which will be as the id when converting to {@link GenericDocument}. */ 229 @NonNull 230 @CanIgnoreReturnValue setSchemaType(@onNull String schemaType)231 public Builder setSchemaType(@NonNull String schemaType) { 232 resetIfBuilt(); 233 mSchemaType = Objects.requireNonNull(schemaType); 234 return this; 235 } 236 237 /** 238 * Resets all values contained in the VisibilityConfig with the values from the given 239 * VisibiltiyConfig. 240 */ 241 @NonNull 242 @CanIgnoreReturnValue setVisibilityConfig(@onNull SchemaVisibilityConfig schemaVisibilityConfig)243 public Builder setVisibilityConfig(@NonNull SchemaVisibilityConfig schemaVisibilityConfig) { 244 resetIfBuilt(); 245 mVisibilityConfigBuilder = new SchemaVisibilityConfig.Builder(schemaVisibilityConfig); 246 return this; 247 } 248 249 /** Sets whether this schema has opted out of platform surfacing. */ 250 @CanIgnoreReturnValue 251 @NonNull setNotDisplayedBySystem(boolean notDisplayedBySystem)252 public Builder setNotDisplayedBySystem(boolean notDisplayedBySystem) { 253 resetIfBuilt(); 254 mIsNotDisplayedBySystem = notDisplayedBySystem; 255 return this; 256 } 257 258 /** 259 * Add {@link PackageIdentifier} of packages which has access to this schema. 260 * 261 * @see SchemaVisibilityConfig.Builder#addAllowedPackage 262 */ 263 @CanIgnoreReturnValue 264 @NonNull addVisibleToPackage(@onNull PackageIdentifier packageIdentifier)265 public Builder addVisibleToPackage(@NonNull PackageIdentifier packageIdentifier) { 266 resetIfBuilt(); 267 mVisibilityConfigBuilder.addAllowedPackage(packageIdentifier); 268 return this; 269 } 270 271 /** 272 * Clears the list of packages which have access to this schema. 273 * 274 * @see SchemaVisibilityConfig.Builder#clearAllowedPackages 275 */ 276 @CanIgnoreReturnValue 277 @NonNull clearVisibleToPackages()278 public Builder clearVisibleToPackages() { 279 resetIfBuilt(); 280 mVisibilityConfigBuilder.clearAllowedPackages(); 281 return this; 282 } 283 284 /** 285 * Adds a set of required Android {@link android.Manifest.permission} combination a package 286 * needs to hold to access the schema. 287 * 288 * @see SchemaVisibilityConfig.Builder#addRequiredPermissions 289 */ 290 @CanIgnoreReturnValue 291 @NonNull addVisibleToPermissions(@onNull Set<Integer> visibleToPermissions)292 public Builder addVisibleToPermissions(@NonNull Set<Integer> visibleToPermissions) { 293 resetIfBuilt(); 294 mVisibilityConfigBuilder.addRequiredPermissions(visibleToPermissions); 295 return this; 296 } 297 298 /** 299 * Clears all required permissions combinations set to this {@link SchemaVisibilityConfig}. 300 * 301 * @see SchemaVisibilityConfig.Builder#clearRequiredPermissions 302 */ 303 @CanIgnoreReturnValue 304 @NonNull clearVisibleToPermissions()305 public Builder clearVisibleToPermissions() { 306 resetIfBuilt(); 307 mVisibilityConfigBuilder.clearRequiredPermissions(); 308 return this; 309 } 310 311 /** 312 * Specify that this schema should be publicly available, to the same packages that have 313 * visibility to the package passed as a parameter. This visibility is determined by the 314 * result of {@link android.content.pm.PackageManager#canPackageQuery}. 315 * 316 * @see SchemaVisibilityConfig.Builder#setPubliclyVisibleTargetPackage 317 */ 318 @CanIgnoreReturnValue 319 @NonNull setPubliclyVisibleTargetPackage( @ullable PackageIdentifier packageIdentifier)320 public Builder setPubliclyVisibleTargetPackage( 321 @Nullable PackageIdentifier packageIdentifier) { 322 resetIfBuilt(); 323 mVisibilityConfigBuilder.setPubliclyVisibleTargetPackage(packageIdentifier); 324 return this; 325 } 326 327 /** 328 * Add the {@link SchemaVisibilityConfig} for a caller need to match to access the schema 329 * this {@link InternalVisibilityConfig} represents. 330 * 331 * <p>You can call this method repeatedly to add multiple {@link SchemaVisibilityConfig}, 332 * and the querier will have access if they match ANY of the {@link SchemaVisibilityConfig}. 333 * 334 * @param schemaVisibilityConfig The {@link SchemaVisibilityConfig} hold all requirements 335 * that a call must match to access the schema. 336 */ 337 @CanIgnoreReturnValue 338 @NonNull addVisibleToConfig(@onNull SchemaVisibilityConfig schemaVisibilityConfig)339 public Builder addVisibleToConfig(@NonNull SchemaVisibilityConfig schemaVisibilityConfig) { 340 Objects.requireNonNull(schemaVisibilityConfig); 341 resetIfBuilt(); 342 mVisibleToConfigs.add(schemaVisibilityConfig); 343 return this; 344 } 345 346 /** Clears the set of {@link SchemaVisibilityConfig} which have access to this schema. */ 347 @CanIgnoreReturnValue 348 @NonNull clearVisibleToConfig()349 public Builder clearVisibleToConfig() { 350 resetIfBuilt(); 351 mVisibleToConfigs.clear(); 352 return this; 353 } 354 resetIfBuilt()355 private void resetIfBuilt() { 356 if (mBuilt) { 357 mVisibleToConfigs = new ArrayList<>(mVisibleToConfigs); 358 mBuilt = false; 359 } 360 } 361 362 /** Build a {@link InternalVisibilityConfig} */ 363 @NonNull build()364 public InternalVisibilityConfig build() { 365 mBuilt = true; 366 return new InternalVisibilityConfig( 367 mSchemaType, 368 mIsNotDisplayedBySystem, 369 mVisibilityConfigBuilder.build(), 370 mVisibleToConfigs); 371 } 372 } 373 } 374