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 */ 16 17 package android.app.appsearch; 18 19 import android.annotation.FlaggedApi; 20 import android.annotation.IntRange; 21 import android.annotation.NonNull; 22 import android.annotation.Nullable; 23 import android.annotation.SuppressLint; 24 import android.app.appsearch.annotation.CanIgnoreReturnValue; 25 import android.app.appsearch.safeparcel.AbstractSafeParcelable; 26 import android.app.appsearch.safeparcel.SafeParcelable; 27 import android.os.Parcel; 28 import android.os.Parcelable; 29 import android.util.ArrayMap; 30 import android.util.ArraySet; 31 32 import com.android.appsearch.flags.Flags; 33 34 import java.util.ArrayList; 35 import java.util.Collections; 36 import java.util.List; 37 import java.util.Map; 38 import java.util.Objects; 39 import java.util.Set; 40 41 /** The response class of {@link AppSearchSession#getSchema} */ 42 @SafeParcelable.Class(creator = "GetSchemaResponseCreator") 43 @SuppressWarnings("HiddenSuperclass") 44 public final class GetSchemaResponse extends AbstractSafeParcelable { 45 46 @FlaggedApi(Flags.FLAG_ENABLE_SAFE_PARCELABLE_2) 47 @NonNull 48 public static final Parcelable.Creator<GetSchemaResponse> CREATOR = 49 new GetSchemaResponseCreator(); 50 51 @Field(id = 1, getter = "getVersion") 52 private final int mVersion; 53 54 @Field(id = 2) 55 final List<AppSearchSchema> mSchemas; 56 57 /** 58 * List of VisibilityConfigs for the current schema. May be {@code null} if retrieving the 59 * visibility settings is not possible on the current backend. 60 */ 61 @Field(id = 3) 62 @Nullable 63 final List<InternalVisibilityConfig> mVisibilityConfigs; 64 65 /** 66 * This set contains all schemas most recently successfully provided to {@link 67 * AppSearchSession#setSchema}. We do lazy fetch, the object will be created when you first time 68 * fetch it. 69 */ 70 @Nullable private Set<AppSearchSchema> mSchemasCached; 71 72 /** 73 * This Set contains all schemas that are not displayed by the system. All values in the set are 74 * prefixed with the package-database prefix. We do lazy fetch, the object will be created when 75 * you first time fetch it. 76 */ 77 @Nullable private Set<String> mSchemasNotDisplayedBySystemCached; 78 79 /** 80 * This map contains all schemas and {@link PackageIdentifier} that has access to the schema. 81 * All keys in the map are prefixed with the package-database prefix. We do lazy fetch, the 82 * object will be created when you first time fetch it. 83 */ 84 @Nullable private Map<String, Set<PackageIdentifier>> mSchemasVisibleToPackagesCached; 85 86 /** 87 * This map contains all schemas and Android Permissions combinations that are required to 88 * access the schema. All keys in the map are prefixed with the package-database prefix. We do 89 * lazy fetch, the object will be created when you first time fetch it. The Map is constructed 90 * in ANY-ALL cases. The querier could read the {@link GenericDocument} objects under the {@code 91 * schemaType} if they hold ALL required permissions of ANY combinations. 92 * 93 * @see SetSchemaRequest.Builder#addRequiredPermissionsForSchemaTypeVisibility(String, Set) 94 */ 95 @Nullable private Map<String, Set<Set<Integer>>> mSchemasVisibleToPermissionsCached; 96 97 /** 98 * This map contains all publicly visible schemas and the {@link PackageIdentifier} specifying 99 * the package that the schemas are from. 100 */ 101 @Nullable private Map<String, PackageIdentifier> mPubliclyVisibleSchemasCached; 102 103 /** 104 * This map contains all {@link SchemaVisibilityConfig}s that has access to the schema. All keys 105 * in the map are prefixed with the package-database prefix. We do lazy fetch, the object will 106 * be created when you first time fetch it. 107 */ 108 @Nullable private Map<String, Set<SchemaVisibilityConfig>> mSchemasVisibleToConfigsCached; 109 110 @Constructor GetSchemaResponse( @aramid = 1) int version, @Param(id = 2) @NonNull List<AppSearchSchema> schemas, @Param(id = 3) @Nullable List<InternalVisibilityConfig> visibilityConfigs)111 GetSchemaResponse( 112 @Param(id = 1) int version, 113 @Param(id = 2) @NonNull List<AppSearchSchema> schemas, 114 @Param(id = 3) @Nullable List<InternalVisibilityConfig> visibilityConfigs) { 115 mVersion = version; 116 mSchemas = Objects.requireNonNull(schemas); 117 mVisibilityConfigs = visibilityConfigs; 118 } 119 120 /** 121 * Returns the overall database schema version. 122 * 123 * <p>If the database is empty, 0 will be returned. 124 */ 125 @IntRange(from = 0) getVersion()126 public int getVersion() { 127 return mVersion; 128 } 129 130 /** 131 * Return the schemas most recently successfully provided to {@link AppSearchSession#setSchema}. 132 */ 133 @NonNull getSchemas()134 public Set<AppSearchSchema> getSchemas() { 135 if (mSchemasCached == null) { 136 mSchemasCached = Collections.unmodifiableSet(new ArraySet<>(mSchemas)); 137 } 138 return mSchemasCached; 139 } 140 141 /** 142 * Returns all the schema types that are opted out of being displayed and visible on any system 143 * UI surface. 144 */ 145 @NonNull getSchemaTypesNotDisplayedBySystem()146 public Set<String> getSchemaTypesNotDisplayedBySystem() { 147 List<InternalVisibilityConfig> visibilityConfigs = getVisibilityConfigsOrThrow(); 148 if (mSchemasNotDisplayedBySystemCached == null) { 149 Set<String> copy = new ArraySet<>(); 150 for (int i = 0; i < visibilityConfigs.size(); i++) { 151 if (visibilityConfigs.get(i).isNotDisplayedBySystem()) { 152 copy.add(visibilityConfigs.get(i).getSchemaType()); 153 } 154 } 155 mSchemasNotDisplayedBySystemCached = Collections.unmodifiableSet(copy); 156 } 157 return mSchemasNotDisplayedBySystemCached; 158 } 159 160 /** 161 * Returns a mapping of schema types to the set of packages that have access to that schema 162 * type. 163 */ 164 @NonNull getSchemaTypesVisibleToPackages()165 public Map<String, Set<PackageIdentifier>> getSchemaTypesVisibleToPackages() { 166 List<InternalVisibilityConfig> visibilityConfigs = getVisibilityConfigsOrThrow(); 167 if (mSchemasVisibleToPackagesCached == null) { 168 Map<String, Set<PackageIdentifier>> copy = new ArrayMap<>(); 169 for (int i = 0; i < visibilityConfigs.size(); i++) { 170 InternalVisibilityConfig visibilityConfig = visibilityConfigs.get(i); 171 List<PackageIdentifier> visibleToPackages = 172 visibilityConfig.getVisibilityConfig().getAllowedPackages(); 173 if (!visibleToPackages.isEmpty()) { 174 copy.put( 175 visibilityConfig.getSchemaType(), 176 Collections.unmodifiableSet(new ArraySet<>(visibleToPackages))); 177 } 178 } 179 mSchemasVisibleToPackagesCached = Collections.unmodifiableMap(copy); 180 } 181 return mSchemasVisibleToPackagesCached; 182 } 183 184 /** 185 * Returns a mapping of schema types to the set of {@link android.Manifest.permission} 186 * combination sets that querier must hold to access that schema type. 187 * 188 * <p>The querier could read the {@link GenericDocument} objects under the {@code schemaType} if 189 * they holds ALL required permissions of ANY of the individual value sets. 190 * 191 * <p>For example, if the Map contains {@code {% verbatim %}{{permissionA, PermissionB}, { 192 * PermissionC, PermissionD}, {PermissionE}}{% endverbatim %}}. 193 * 194 * <ul> 195 * <li>A querier holding both PermissionA and PermissionB has access. 196 * <li>A querier holding both PermissionC and PermissionD has access. 197 * <li>A querier holding only PermissionE has access. 198 * <li>A querier holding both PermissionA and PermissionE has access. 199 * <li>A querier holding only PermissionA doesn't have access. 200 * <li>A querier holding only PermissionA and PermissionC doesn't have access. 201 * </ul> 202 * 203 * @return The map contains schema type and all combinations of required permission for querier 204 * to access it. The supported Permission are {@link SetSchemaRequest#READ_SMS}, {@link 205 * SetSchemaRequest#READ_CALENDAR}, {@link SetSchemaRequest#READ_CONTACTS}, {@link 206 * SetSchemaRequest#READ_EXTERNAL_STORAGE}, {@link 207 * SetSchemaRequest#READ_HOME_APP_SEARCH_DATA} and {@link 208 * SetSchemaRequest#READ_ASSISTANT_APP_SEARCH_DATA}. 209 */ 210 // TODO(b/237388235): add enterprise permissions to javadocs after they're unhidden 211 212 @NonNull getRequiredPermissionsForSchemaTypeVisibility()213 public Map<String, Set<Set<Integer>>> getRequiredPermissionsForSchemaTypeVisibility() { 214 List<InternalVisibilityConfig> visibilityConfigs = getVisibilityConfigsOrThrow(); 215 if (mSchemasVisibleToPermissionsCached == null) { 216 Map<String, Set<Set<Integer>>> copy = new ArrayMap<>(); 217 for (int i = 0; i < visibilityConfigs.size(); i++) { 218 InternalVisibilityConfig visibilityConfig = visibilityConfigs.get(i); 219 Set<Set<Integer>> visibleToPermissions = 220 visibilityConfig.getVisibilityConfig().getRequiredPermissions(); 221 if (!visibleToPermissions.isEmpty()) { 222 copy.put( 223 visibilityConfig.getSchemaType(), 224 Collections.unmodifiableSet(visibleToPermissions)); 225 } 226 } 227 mSchemasVisibleToPermissionsCached = Collections.unmodifiableMap(copy); 228 } 229 return mSchemasVisibleToPermissionsCached; 230 } 231 232 /** 233 * Returns a mapping of publicly visible schemas to the {@link PackageIdentifier} specifying the 234 * package the schemas are from. 235 * 236 * <p>If no schemas have been set as publicly visible, an empty set will be returned. 237 */ 238 @FlaggedApi(Flags.FLAG_ENABLE_SET_PUBLICLY_VISIBLE_SCHEMA) 239 @NonNull getPubliclyVisibleSchemas()240 public Map<String, PackageIdentifier> getPubliclyVisibleSchemas() { 241 List<InternalVisibilityConfig> visibilityConfigs = getVisibilityConfigsOrThrow(); 242 if (mPubliclyVisibleSchemasCached == null) { 243 Map<String, PackageIdentifier> copy = new ArrayMap<>(); 244 for (int i = 0; i < visibilityConfigs.size(); i++) { 245 InternalVisibilityConfig visibilityConfig = visibilityConfigs.get(i); 246 PackageIdentifier publiclyVisibleTargetPackage = 247 visibilityConfig.getVisibilityConfig().getPubliclyVisibleTargetPackage(); 248 if (publiclyVisibleTargetPackage != null) { 249 copy.put(visibilityConfig.getSchemaType(), publiclyVisibleTargetPackage); 250 } 251 } 252 mPubliclyVisibleSchemasCached = Collections.unmodifiableMap(copy); 253 } 254 return mPubliclyVisibleSchemasCached; 255 } 256 257 /** 258 * Returns a mapping of schema types to the set of {@link SchemaVisibilityConfig} that have 259 * access to that schema type. 260 * 261 * @see SetSchemaRequest.Builder#addSchemaTypeVisibleToConfig 262 */ 263 @FlaggedApi(Flags.FLAG_ENABLE_SET_SCHEMA_VISIBLE_TO_CONFIGS) 264 @NonNull getSchemaTypesVisibleToConfigs()265 public Map<String, Set<SchemaVisibilityConfig>> getSchemaTypesVisibleToConfigs() { 266 List<InternalVisibilityConfig> visibilityConfigs = getVisibilityConfigsOrThrow(); 267 if (mSchemasVisibleToConfigsCached == null) { 268 Map<String, Set<SchemaVisibilityConfig>> copy = new ArrayMap<>(); 269 for (int i = 0; i < visibilityConfigs.size(); i++) { 270 InternalVisibilityConfig visibilityConfig = visibilityConfigs.get(i); 271 Set<SchemaVisibilityConfig> nestedVisibilityConfigs = 272 visibilityConfig.getVisibleToConfigs(); 273 if (!nestedVisibilityConfigs.isEmpty()) { 274 copy.put( 275 visibilityConfig.getSchemaType(), 276 Collections.unmodifiableSet(nestedVisibilityConfigs)); 277 } 278 } 279 mSchemasVisibleToConfigsCached = Collections.unmodifiableMap(copy); 280 } 281 return mSchemasVisibleToConfigsCached; 282 } 283 284 @NonNull getVisibilityConfigsOrThrow()285 private List<InternalVisibilityConfig> getVisibilityConfigsOrThrow() { 286 List<InternalVisibilityConfig> visibilityConfigs = mVisibilityConfigs; 287 if (visibilityConfigs == null) { 288 throw new UnsupportedOperationException( 289 "Get visibility setting is not supported with " 290 + "this backend/Android API level combination."); 291 } 292 return visibilityConfigs; 293 } 294 295 @FlaggedApi(Flags.FLAG_ENABLE_SAFE_PARCELABLE_2) 296 @Override writeToParcel(@onNull Parcel dest, int flags)297 public void writeToParcel(@NonNull Parcel dest, int flags) { 298 GetSchemaResponseCreator.writeToParcel(this, dest, flags); 299 } 300 301 /** Builder for {@link GetSchemaResponse} objects. */ 302 public static final class Builder { 303 private int mVersion = 0; 304 private ArrayList<AppSearchSchema> mSchemas = new ArrayList<>(); 305 306 /** 307 * Creates the object when we actually set them. If we never set visibility settings, we 308 * should throw {@link UnsupportedOperationException} in the visibility getters. 309 */ 310 @Nullable private Map<String, InternalVisibilityConfig.Builder> mVisibilityConfigBuilders; 311 312 private boolean mBuilt = false; 313 314 /** Create a {@link Builder} object} */ Builder()315 public Builder() { 316 setVisibilitySettingSupported(true); 317 } 318 319 /** 320 * Sets the database overall schema version. 321 * 322 * <p>Default version is 0 323 */ 324 @CanIgnoreReturnValue 325 @NonNull setVersion(@ntRangefrom = 0) int version)326 public Builder setVersion(@IntRange(from = 0) int version) { 327 resetIfBuilt(); 328 mVersion = version; 329 return this; 330 } 331 332 /** Adds one {@link AppSearchSchema} to the schema list. */ 333 @CanIgnoreReturnValue 334 @NonNull addSchema(@onNull AppSearchSchema schema)335 public Builder addSchema(@NonNull AppSearchSchema schema) { 336 Objects.requireNonNull(schema); 337 resetIfBuilt(); 338 mSchemas.add(schema); 339 return this; 340 } 341 342 /** 343 * Sets whether or not documents from the provided {@code schemaType} will be displayed and 344 * visible on any system UI surface. 345 * 346 * @param schemaType The name of an {@link AppSearchSchema} within the same {@link 347 * GetSchemaResponse}, which won't be displayed by system. 348 */ 349 // Getter getSchemaTypesNotDisplayedBySystem returns plural objects. 350 @CanIgnoreReturnValue 351 @SuppressLint("MissingGetterMatchingBuilder") 352 @NonNull addSchemaTypeNotDisplayedBySystem(@onNull String schemaType)353 public Builder addSchemaTypeNotDisplayedBySystem(@NonNull String schemaType) { 354 Objects.requireNonNull(schemaType); 355 resetIfBuilt(); 356 InternalVisibilityConfig.Builder visibilityConfigBuilder = 357 getOrCreateVisibilityConfigBuilder(schemaType); 358 visibilityConfigBuilder.setNotDisplayedBySystem(true); 359 return this; 360 } 361 362 /** 363 * Sets whether or not documents from the provided {@code schemaType} can be read by the 364 * specified package. 365 * 366 * <p>Each package is represented by a {@link PackageIdentifier}, containing a package name 367 * and a byte array of type {@link android.content.pm.PackageManager#CERT_INPUT_SHA256}. 368 * 369 * <p>To opt into one-way data sharing with another application, the developer will need to 370 * explicitly grant the other application’s package name and certificate Read access to its 371 * data. 372 * 373 * <p>For two-way data sharing, both applications need to explicitly grant Read access to 374 * one another. 375 * 376 * @param schemaType The schema type to set visibility on. 377 * @param packageIdentifiers Represents the package that has access to the given schema 378 * type. 379 */ 380 // Getter getSchemaTypesVisibleToPackages returns a map contains all schema types. 381 @CanIgnoreReturnValue 382 @SuppressLint("MissingGetterMatchingBuilder") 383 @NonNull setSchemaTypeVisibleToPackages( @onNull String schemaType, @NonNull Set<PackageIdentifier> packageIdentifiers)384 public Builder setSchemaTypeVisibleToPackages( 385 @NonNull String schemaType, @NonNull Set<PackageIdentifier> packageIdentifiers) { 386 Objects.requireNonNull(schemaType); 387 Objects.requireNonNull(packageIdentifiers); 388 resetIfBuilt(); 389 InternalVisibilityConfig.Builder visibilityConfigBuilder = 390 getOrCreateVisibilityConfigBuilder(schemaType); 391 for (PackageIdentifier packageIdentifier : packageIdentifiers) { 392 visibilityConfigBuilder.addVisibleToPackage(packageIdentifier); 393 } 394 return this; 395 } 396 397 /** 398 * Sets a set of required {@link android.Manifest.permission} combinations to the given 399 * schema type. 400 * 401 * <p>The querier could read the {@link GenericDocument} objects under the {@code 402 * schemaType} if they holds ALL required permissions of ANY of the individual value sets. 403 * 404 * <p>For example, if the Map contains {@code {% verbatim %}{{permissionA, PermissionB}, 405 * {PermissionC, PermissionD}, {PermissionE}}{% endverbatim %}}. 406 * 407 * <ul> 408 * <li>A querier holds both PermissionA and PermissionB has access. 409 * <li>A querier holds both PermissionC and PermissionD has access. 410 * <li>A querier holds only PermissionE has access. 411 * <li>A querier holds both PermissionA and PermissionE has access. 412 * <li>A querier holds only PermissionA doesn't have access. 413 * <li>A querier holds both PermissionA and PermissionC doesn't have access. 414 * </ul> 415 * 416 * @param schemaType The schema type to set visibility on. 417 * @param visibleToPermissionSets The Sets of Android permissions that will be required to 418 * access the given schema. 419 * @see android.Manifest.permission#READ_SMS 420 * @see android.Manifest.permission#READ_CALENDAR 421 * @see android.Manifest.permission#READ_CONTACTS 422 * @see android.Manifest.permission#READ_EXTERNAL_STORAGE 423 * @see android.Manifest.permission#READ_HOME_APP_SEARCH_DATA 424 * @see android.Manifest.permission#READ_ASSISTANT_APP_SEARCH_DATA 425 */ 426 // TODO(b/237388235): add enterprise permissions to javadocs after they're unhidden 427 // Getter getRequiredPermissionsForSchemaTypeVisibility returns a map for all schemaTypes. 428 @CanIgnoreReturnValue 429 @SuppressLint("MissingGetterMatchingBuilder") 430 // @SetSchemaRequest is an IntDef annotation applied to Set<Set<Integer>>. 431 @SuppressWarnings("SupportAnnotationUsage") 432 @NonNull setRequiredPermissionsForSchemaTypeVisibility( @onNull String schemaType, @SetSchemaRequest.AppSearchSupportedPermission @NonNull Set<Set<Integer>> visibleToPermissionSets)433 public Builder setRequiredPermissionsForSchemaTypeVisibility( 434 @NonNull String schemaType, 435 @SetSchemaRequest.AppSearchSupportedPermission @NonNull 436 Set<Set<Integer>> visibleToPermissionSets) { 437 Objects.requireNonNull(schemaType); 438 Objects.requireNonNull(visibleToPermissionSets); 439 resetIfBuilt(); 440 InternalVisibilityConfig.Builder visibilityConfigBuilder = 441 getOrCreateVisibilityConfigBuilder(schemaType); 442 for (Set<Integer> visibleToPermissions : visibleToPermissionSets) { 443 visibilityConfigBuilder.addVisibleToPermissions(visibleToPermissions); 444 } 445 return this; 446 } 447 448 /** 449 * Specify that the schema should be publicly available, to packages which already have 450 * visibility to {@code packageIdentifier}. 451 * 452 * @param schemaType the schema to make publicly accessible. 453 * @param packageIdentifier the package from which the document schema is from. 454 * @see SetSchemaRequest.Builder#setPubliclyVisibleSchema 455 */ 456 // Merged list available from getPubliclyVisibleSchemas 457 @CanIgnoreReturnValue 458 @SuppressLint("MissingGetterMatchingBuilder") 459 @FlaggedApi(Flags.FLAG_ENABLE_SET_PUBLICLY_VISIBLE_SCHEMA) 460 @NonNull setPubliclyVisibleSchema( @onNull String schemaType, @NonNull PackageIdentifier packageIdentifier)461 public Builder setPubliclyVisibleSchema( 462 @NonNull String schemaType, @NonNull PackageIdentifier packageIdentifier) { 463 Objects.requireNonNull(schemaType); 464 Objects.requireNonNull(packageIdentifier); 465 resetIfBuilt(); 466 InternalVisibilityConfig.Builder visibilityConfigBuilder = 467 getOrCreateVisibilityConfigBuilder(schemaType); 468 visibilityConfigBuilder.setPubliclyVisibleTargetPackage(packageIdentifier); 469 return this; 470 } 471 472 /** 473 * Sets the documents from the provided {@code schemaType} can be read by the caller if they 474 * match the ALL visibility requirements set in {@link SchemaVisibilityConfig}. 475 * 476 * <p>The requirements in a {@link SchemaVisibilityConfig} is "AND" relationship. A caller 477 * must match ALL requirements to access the schema. For example, a caller must hold 478 * required permissions AND it is a specified package. 479 * 480 * <p>The querier could have access if they match ALL requirements in ANY of the given 481 * {@link SchemaVisibilityConfig}s 482 * 483 * <p>For example, if the Set contains {@code {% verbatim %}{{PackageA and Permission1}, 484 * {PackageB and Permission2}}{% endverbatim %}}. 485 * 486 * <ul> 487 * <li>A querier from packageA could read if they holds Permission1. 488 * <li>A querier from packageA could NOT read if they only holds Permission2 instead of 489 * Permission1. 490 * <li>A querier from packageB could read if they holds Permission2. 491 * <li>A querier from packageC could never read. 492 * <li>A querier holds both PermissionA and PermissionE has access. 493 * </ul> 494 * 495 * @param schemaType The schema type to set visibility on. 496 * @param visibleToConfigs The {@link SchemaVisibilityConfig}s hold all requirements that a 497 * call must to match to access the schema. 498 */ 499 // Merged map available from getSchemasVisibleToConfigs 500 @CanIgnoreReturnValue 501 @SuppressLint("MissingGetterMatchingBuilder") 502 @FlaggedApi(Flags.FLAG_ENABLE_SET_SCHEMA_VISIBLE_TO_CONFIGS) 503 @NonNull setSchemaTypeVisibleToConfigs( @onNull String schemaType, @NonNull Set<SchemaVisibilityConfig> visibleToConfigs)504 public Builder setSchemaTypeVisibleToConfigs( 505 @NonNull String schemaType, @NonNull Set<SchemaVisibilityConfig> visibleToConfigs) { 506 Objects.requireNonNull(schemaType); 507 Objects.requireNonNull(visibleToConfigs); 508 resetIfBuilt(); 509 InternalVisibilityConfig.Builder visibilityConfigBuilder = 510 getOrCreateVisibilityConfigBuilder(schemaType); 511 for (SchemaVisibilityConfig visibleToConfig : visibleToConfigs) { 512 visibilityConfigBuilder.addVisibleToConfig(visibleToConfig); 513 } 514 return this; 515 } 516 517 /** 518 * Method to set visibility setting. If this is called with false, {@link 519 * #getRequiredPermissionsForSchemaTypeVisibility()}, {@link 520 * #getSchemaTypesNotDisplayedBySystem()}}, and {@link #getSchemaTypesVisibleToPackages()} 521 * calls will throw an {@link UnsupportedOperationException}. If called with true, 522 * visibility information for all schemas will be cleared. 523 * 524 * @param visibilitySettingSupported whether supported {@link 525 * Features#ADD_PERMISSIONS_AND_GET_VISIBILITY} by this backend/Android API level. 526 * @hide 527 */ 528 // Visibility setting is determined by SDK version, so it won't be needed in framework 529 @CanIgnoreReturnValue 530 @SuppressLint("MissingGetterMatchingBuilder") 531 @NonNull setVisibilitySettingSupported(boolean visibilitySettingSupported)532 public Builder setVisibilitySettingSupported(boolean visibilitySettingSupported) { 533 if (visibilitySettingSupported) { 534 mVisibilityConfigBuilders = new ArrayMap<>(); 535 } else { 536 mVisibilityConfigBuilders = null; 537 } 538 return this; 539 } 540 541 /** Builds a {@link GetSchemaResponse} object. */ 542 @NonNull build()543 public GetSchemaResponse build() { 544 List<InternalVisibilityConfig> visibilityConfigs = null; 545 if (mVisibilityConfigBuilders != null) { 546 visibilityConfigs = new ArrayList<>(); 547 for (InternalVisibilityConfig.Builder builder : 548 mVisibilityConfigBuilders.values()) { 549 visibilityConfigs.add(builder.build()); 550 } 551 } 552 mBuilt = true; 553 return new GetSchemaResponse(mVersion, mSchemas, visibilityConfigs); 554 } 555 556 @NonNull getOrCreateVisibilityConfigBuilder( @onNull String schemaType)557 private InternalVisibilityConfig.Builder getOrCreateVisibilityConfigBuilder( 558 @NonNull String schemaType) { 559 if (mVisibilityConfigBuilders == null) { 560 throw new IllegalStateException( 561 "GetSchemaResponse is not configured with" + "visibility setting support"); 562 } 563 InternalVisibilityConfig.Builder builder = mVisibilityConfigBuilders.get(schemaType); 564 if (builder == null) { 565 builder = new InternalVisibilityConfig.Builder(schemaType); 566 mVisibilityConfigBuilders.put(schemaType, builder); 567 } 568 return builder; 569 } 570 resetIfBuilt()571 private void resetIfBuilt() { 572 if (mBuilt) { 573 // No need to copy mVisibilityConfigBuilders -- it gets copied during build(). 574 mSchemas = new ArrayList<>(mSchemas); 575 mBuilt = false; 576 } 577 } 578 } 579 } 580