• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 import com.android.internal.util.Preconditions;
34 
35 import java.util.ArrayList;
36 import java.util.Collections;
37 import java.util.List;
38 import java.util.Map;
39 import java.util.Objects;
40 import java.util.Set;
41 
42 /** The response class of {@link AppSearchSession#getSchema} */
43 @SafeParcelable.Class(creator = "GetSchemaResponseCreator")
44 // TODO(b/384721898): Switch to JSpecify annotations
45 @SuppressWarnings({"HiddenSuperclass", "JSpecifyNullness"})
46 public final class GetSchemaResponse extends AbstractSafeParcelable {
47 
48     @FlaggedApi(Flags.FLAG_ENABLE_SAFE_PARCELABLE_2)
49     public static final @NonNull Parcelable.Creator<GetSchemaResponse> CREATOR =
50             new GetSchemaResponseCreator();
51 
52     @Field(id = 1, getter = "getVersion")
53     private final int mVersion;
54 
55     @Field(id = 2)
56     final List<AppSearchSchema> mSchemas;
57 
58     /**
59      * List of VisibilityConfigs for the current schema. May be {@code null} if retrieving the
60      * visibility settings is not possible on the current backend.
61      */
62     @Field(id = 3)
63     final @Nullable 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     private @Nullable 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     private @Nullable 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     private @Nullable 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     private @Nullable 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     private @Nullable 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     private @Nullable 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      */
getSchemas()133     public @NonNull Set<AppSearchSchema> getSchemas() {
134         if (mSchemasCached == null) {
135             mSchemasCached = Collections.unmodifiableSet(new ArraySet<>(mSchemas));
136         }
137         return mSchemasCached;
138     }
139 
140     /**
141      * Returns all the schema types that are opted out of being displayed and visible on any system
142      * UI surface.
143      */
getSchemaTypesNotDisplayedBySystem()144     public @NonNull Set<String> getSchemaTypesNotDisplayedBySystem() {
145         List<InternalVisibilityConfig> visibilityConfigs = getVisibilityConfigsOrThrow();
146         if (mSchemasNotDisplayedBySystemCached == null) {
147             Set<String> copy = new ArraySet<>();
148             for (int i = 0; i < visibilityConfigs.size(); i++) {
149                 if (visibilityConfigs.get(i).isNotDisplayedBySystem()) {
150                     copy.add(visibilityConfigs.get(i).getSchemaType());
151                 }
152             }
153             mSchemasNotDisplayedBySystemCached = Collections.unmodifiableSet(copy);
154         }
155         return mSchemasNotDisplayedBySystemCached;
156     }
157 
158     /**
159      * Returns a mapping of schema types to the set of packages that have access to that schema
160      * type.
161      */
getSchemaTypesVisibleToPackages()162     public @NonNull Map<String, Set<PackageIdentifier>> getSchemaTypesVisibleToPackages() {
163         List<InternalVisibilityConfig> visibilityConfigs = getVisibilityConfigsOrThrow();
164         if (mSchemasVisibleToPackagesCached == null) {
165             Map<String, Set<PackageIdentifier>> copy = new ArrayMap<>();
166             for (int i = 0; i < visibilityConfigs.size(); i++) {
167                 InternalVisibilityConfig visibilityConfig = visibilityConfigs.get(i);
168                 List<PackageIdentifier> visibleToPackages =
169                         visibilityConfig.getVisibilityConfig().getAllowedPackages();
170                 if (!visibleToPackages.isEmpty()) {
171                     copy.put(
172                             visibilityConfig.getSchemaType(),
173                             Collections.unmodifiableSet(new ArraySet<>(visibleToPackages)));
174                 }
175             }
176             mSchemasVisibleToPackagesCached = Collections.unmodifiableMap(copy);
177         }
178         return mSchemasVisibleToPackagesCached;
179     }
180 
181     /**
182      * Returns a mapping of schema types to the set of {@link android.Manifest.permission}
183      * combination sets that querier must hold to access that schema type.
184      *
185      * <p>The querier could read the {@link GenericDocument} objects under the {@code schemaType} if
186      * they holds ALL required permissions of ANY of the individual value sets.
187      *
188      * <p>For example, if the Map contains {@code {% verbatim %}{{permissionA, PermissionB}, {
189      * PermissionC, PermissionD}, {PermissionE}}{% endverbatim %}}.
190      *
191      * <ul>
192      *   <li>A querier holding both PermissionA and PermissionB has access.
193      *   <li>A querier holding both PermissionC and PermissionD has access.
194      *   <li>A querier holding only PermissionE has access.
195      *   <li>A querier holding both PermissionA and PermissionE has access.
196      *   <li>A querier holding only PermissionA doesn't have access.
197      *   <li>A querier holding only PermissionA and PermissionC doesn't have access.
198      * </ul>
199      *
200      * @return The map contains schema type and all combinations of required permission for querier
201      *     to access it. The supported Permission are {@link SetSchemaRequest#READ_SMS}, {@link
202      *     SetSchemaRequest#READ_CALENDAR}, {@link SetSchemaRequest#READ_CONTACTS}, {@link
203      *     SetSchemaRequest#READ_EXTERNAL_STORAGE}, {@link
204      *     SetSchemaRequest#READ_HOME_APP_SEARCH_DATA} and {@link
205      *     SetSchemaRequest#READ_ASSISTANT_APP_SEARCH_DATA}.
206      */
207     // TODO(b/237388235): add enterprise permissions to javadocs after they're unhidden
208     // Annotation is here to suppress lint error. Lint error is erroneous since the method does not
209     // require the caller to hold any permission for the method to function.
210     @SuppressLint("RequiresPermission")
getRequiredPermissionsForSchemaTypeVisibility()211     public @NonNull Map<String, Set<Set<Integer>>> getRequiredPermissionsForSchemaTypeVisibility() {
212         List<InternalVisibilityConfig> visibilityConfigs = getVisibilityConfigsOrThrow();
213         if (mSchemasVisibleToPermissionsCached == null) {
214             Map<String, Set<Set<Integer>>> copy = new ArrayMap<>();
215             for (int i = 0; i < visibilityConfigs.size(); i++) {
216                 InternalVisibilityConfig visibilityConfig = visibilityConfigs.get(i);
217                 Set<Set<Integer>> visibleToPermissions =
218                         visibilityConfig.getVisibilityConfig().getRequiredPermissions();
219                 if (!visibleToPermissions.isEmpty()) {
220                     copy.put(
221                             visibilityConfig.getSchemaType(),
222                             Collections.unmodifiableSet(visibleToPermissions));
223                 }
224             }
225             mSchemasVisibleToPermissionsCached = Collections.unmodifiableMap(copy);
226         }
227         return mSchemasVisibleToPermissionsCached;
228     }
229 
230     /**
231      * Returns a mapping of publicly visible schemas to the {@link PackageIdentifier} specifying the
232      * package the schemas are from.
233      *
234      * <p>If no schemas have been set as publicly visible, an empty set will be returned.
235      */
236     @FlaggedApi(Flags.FLAG_ENABLE_SET_PUBLICLY_VISIBLE_SCHEMA)
getPubliclyVisibleSchemas()237     public @NonNull Map<String, PackageIdentifier> getPubliclyVisibleSchemas() {
238         List<InternalVisibilityConfig> visibilityConfigs = getVisibilityConfigsOrThrow();
239         if (mPubliclyVisibleSchemasCached == null) {
240             Map<String, PackageIdentifier> copy = new ArrayMap<>();
241             for (int i = 0; i < visibilityConfigs.size(); i++) {
242                 InternalVisibilityConfig visibilityConfig = visibilityConfigs.get(i);
243                 PackageIdentifier publiclyVisibleTargetPackage =
244                         visibilityConfig.getVisibilityConfig().getPubliclyVisibleTargetPackage();
245                 if (publiclyVisibleTargetPackage != null) {
246                     copy.put(visibilityConfig.getSchemaType(), publiclyVisibleTargetPackage);
247                 }
248             }
249             mPubliclyVisibleSchemasCached = Collections.unmodifiableMap(copy);
250         }
251         return mPubliclyVisibleSchemasCached;
252     }
253 
254     /**
255      * Returns a mapping of schema types to the set of {@link SchemaVisibilityConfig} that have
256      * access to that schema type.
257      *
258      * @see SetSchemaRequest.Builder#addSchemaTypeVisibleToConfig
259      */
260     @FlaggedApi(Flags.FLAG_ENABLE_SET_SCHEMA_VISIBLE_TO_CONFIGS)
getSchemaTypesVisibleToConfigs()261     public @NonNull Map<String, Set<SchemaVisibilityConfig>> getSchemaTypesVisibleToConfigs() {
262         List<InternalVisibilityConfig> visibilityConfigs = getVisibilityConfigsOrThrow();
263         if (mSchemasVisibleToConfigsCached == null) {
264             Map<String, Set<SchemaVisibilityConfig>> copy = new ArrayMap<>();
265             for (int i = 0; i < visibilityConfigs.size(); i++) {
266                 InternalVisibilityConfig visibilityConfig = visibilityConfigs.get(i);
267                 Set<SchemaVisibilityConfig> nestedVisibilityConfigs =
268                         visibilityConfig.getVisibleToConfigs();
269                 if (!nestedVisibilityConfigs.isEmpty()) {
270                     copy.put(
271                             visibilityConfig.getSchemaType(),
272                             Collections.unmodifiableSet(nestedVisibilityConfigs));
273                 }
274             }
275             mSchemasVisibleToConfigsCached = Collections.unmodifiableMap(copy);
276         }
277         return mSchemasVisibleToConfigsCached;
278     }
279 
getVisibilityConfigsOrThrow()280     private @NonNull List<InternalVisibilityConfig> getVisibilityConfigsOrThrow() {
281         List<InternalVisibilityConfig> visibilityConfigs = mVisibilityConfigs;
282         if (visibilityConfigs == null) {
283             throw new UnsupportedOperationException(
284                     "Get visibility setting is not supported with "
285                             + "this backend/Android API level combination.");
286         }
287         return visibilityConfigs;
288     }
289 
290     @FlaggedApi(Flags.FLAG_ENABLE_SAFE_PARCELABLE_2)
291     @Override
writeToParcel(@onNull Parcel dest, int flags)292     public void writeToParcel(@NonNull Parcel dest, int flags) {
293         GetSchemaResponseCreator.writeToParcel(this, dest, flags);
294     }
295 
296     /** Builder for {@link GetSchemaResponse} objects. */
297     public static final class Builder {
298         private int mVersion = 0;
299         private ArrayList<AppSearchSchema> mSchemas = new ArrayList<>();
300 
301         /**
302          * Creates the object when we actually set them. If we never set visibility settings, we
303          * should throw {@link UnsupportedOperationException} in the visibility getters.
304          */
305         private @Nullable Map<String, InternalVisibilityConfig.Builder> mVisibilityConfigBuilders;
306 
307         private boolean mBuilt = false;
308 
309         /** Creates a new {@link Builder} */
Builder()310         public Builder() {
311             setVisibilitySettingSupported(true);
312         }
313 
314         /** Creates a new {@link Builder} from the given {@link GetSchemaResponse}. */
315         @FlaggedApi(Flags.FLAG_ENABLE_ADDITIONAL_BUILDER_COPY_CONSTRUCTORS)
Builder(@onNull GetSchemaResponse getSchemaResponse)316         public Builder(@NonNull GetSchemaResponse getSchemaResponse) {
317             setVisibilitySettingSupported(true);
318             mVersion = getSchemaResponse.mVersion;
319             mSchemas.addAll(getSchemaResponse.mSchemas);
320             if (getSchemaResponse.mVisibilityConfigs != null) {
321                 int count = getSchemaResponse.mVisibilityConfigs.size();
322                 for (int i = 0; i < count; i++) {
323                     InternalVisibilityConfig config = getSchemaResponse.mVisibilityConfigs.get(i);
324                     mVisibilityConfigBuilders.put(
325                             config.getSchemaType(), new InternalVisibilityConfig.Builder(config));
326                 }
327             }
328         }
329 
330         /**
331          * Sets the database overall schema version.
332          *
333          * <p>Default version is 0
334          */
335         @CanIgnoreReturnValue
setVersion(@ntRangefrom = 0) int version)336         public @NonNull Builder setVersion(@IntRange(from = 0) int version) {
337             Preconditions.checkArgument(version >= 0, "Version must be a non-negative number.");
338             resetIfBuilt();
339             mVersion = version;
340             return this;
341         }
342 
343         /** Adds one {@link AppSearchSchema} to the schema list. */
344         @CanIgnoreReturnValue
addSchema(@onNull AppSearchSchema schema)345         public @NonNull Builder addSchema(@NonNull AppSearchSchema schema) {
346             Objects.requireNonNull(schema);
347             resetIfBuilt();
348             mSchemas.add(schema);
349             return this;
350         }
351 
352         /** Clears all {@link AppSearchSchema}s from the list of schemas. */
353         @FlaggedApi(Flags.FLAG_ENABLE_ADDITIONAL_BUILDER_COPY_CONSTRUCTORS)
354         @CanIgnoreReturnValue
clearSchemas()355         public @NonNull Builder clearSchemas() {
356             resetIfBuilt();
357             mSchemas.clear();
358             return this;
359         }
360 
361         /**
362          * Sets whether or not documents from the provided {@code schemaType} will be displayed and
363          * visible on any system UI surface.
364          *
365          * @param schemaType The name of an {@link AppSearchSchema} within the same {@link
366          *     GetSchemaResponse}, which won't be displayed by system.
367          */
368         // Getter getSchemaTypesNotDisplayedBySystem returns plural objects.
369         @CanIgnoreReturnValue
370         @SuppressLint("MissingGetterMatchingBuilder")
addSchemaTypeNotDisplayedBySystem(@onNull String schemaType)371         public @NonNull Builder addSchemaTypeNotDisplayedBySystem(@NonNull String schemaType) {
372             Objects.requireNonNull(schemaType);
373             resetIfBuilt();
374             InternalVisibilityConfig.Builder visibilityConfigBuilder =
375                     getOrCreateVisibilityConfigBuilder(schemaType);
376             visibilityConfigBuilder.setNotDisplayedBySystem(true);
377             return this;
378         }
379 
380         /**
381          * Clears the visibility setting for the given schema type that prevents the schema from
382          * being displayed and visible on any system UI surface.
383          *
384          * @see Builder#addSchemaTypeNotDisplayedBySystem
385          */
386         @FlaggedApi(Flags.FLAG_ENABLE_ADDITIONAL_BUILDER_COPY_CONSTRUCTORS)
387         @CanIgnoreReturnValue
clearSchemaTypeNotDisplayedBySystem(@onNull String schemaType)388         public @NonNull Builder clearSchemaTypeNotDisplayedBySystem(@NonNull String schemaType) {
389             Objects.requireNonNull(schemaType);
390             resetIfBuilt();
391             InternalVisibilityConfig.Builder visibilityConfigBuilder =
392                     getVisibilityConfigBuilder(schemaType);
393             if (visibilityConfigBuilder != null) {
394                 visibilityConfigBuilder.setNotDisplayedBySystem(false);
395             }
396             return this;
397         }
398 
399         /**
400          * Sets whether or not documents from the provided {@code schemaType} can be read by the
401          * specified package.
402          *
403          * <p>Each package is represented by a {@link PackageIdentifier}, containing a package name
404          * and a byte array of type {@link android.content.pm.PackageManager#CERT_INPUT_SHA256}.
405          *
406          * <p>To opt into one-way data sharing with another application, the developer will need to
407          * explicitly grant the other application’s package name and certificate Read access to its
408          * data.
409          *
410          * <p>For two-way data sharing, both applications need to explicitly grant Read access to
411          * one another.
412          *
413          * @param schemaType The schema type to set visibility on.
414          * @param packageIdentifiers Represents the package that has access to the given schema
415          *     type.
416          */
417         // Getter getSchemaTypesVisibleToPackages returns a map contains all schema types.
418         @CanIgnoreReturnValue
419         @SuppressLint("MissingGetterMatchingBuilder")
setSchemaTypeVisibleToPackages( @onNull String schemaType, @NonNull Set<PackageIdentifier> packageIdentifiers)420         public @NonNull Builder setSchemaTypeVisibleToPackages(
421                 @NonNull String schemaType, @NonNull Set<PackageIdentifier> packageIdentifiers) {
422             Objects.requireNonNull(schemaType);
423             Objects.requireNonNull(packageIdentifiers);
424             resetIfBuilt();
425             InternalVisibilityConfig.Builder visibilityConfigBuilder =
426                     getOrCreateVisibilityConfigBuilder(schemaType);
427             for (PackageIdentifier packageIdentifier : packageIdentifiers) {
428                 visibilityConfigBuilder.addVisibleToPackage(packageIdentifier);
429             }
430             return this;
431         }
432 
433         /**
434          * Clears the set of packages that can read the given schema type.
435          *
436          * @see Builder#setSchemaTypeVisibleToPackages
437          */
438         @FlaggedApi(Flags.FLAG_ENABLE_ADDITIONAL_BUILDER_COPY_CONSTRUCTORS)
439         @CanIgnoreReturnValue
clearSchemaTypeVisibleToPackages(@onNull String schemaType)440         public @NonNull Builder clearSchemaTypeVisibleToPackages(@NonNull String schemaType) {
441             Objects.requireNonNull(schemaType);
442             resetIfBuilt();
443             InternalVisibilityConfig.Builder visibilityConfigBuilder =
444                     getVisibilityConfigBuilder(schemaType);
445             if (visibilityConfigBuilder != null) {
446                 visibilityConfigBuilder.clearVisibleToPackages();
447             }
448             return this;
449         }
450 
451         /**
452          * Sets a set of required {@link android.Manifest.permission} combinations to the given
453          * schema type.
454          *
455          * <p>The querier could read the {@link GenericDocument} objects under the {@code
456          * schemaType} if they holds ALL required permissions of ANY of the individual value sets.
457          *
458          * <p>For example, if the Map contains {@code {% verbatim %}{{permissionA, PermissionB},
459          * {PermissionC, PermissionD}, {PermissionE}}{% endverbatim %}}.
460          *
461          * <ul>
462          *   <li>A querier holds both PermissionA and PermissionB has access.
463          *   <li>A querier holds both PermissionC and PermissionD has access.
464          *   <li>A querier holds only PermissionE has access.
465          *   <li>A querier holds both PermissionA and PermissionE has access.
466          *   <li>A querier holds only PermissionA doesn't have access.
467          *   <li>A querier holds both PermissionA and PermissionC doesn't have access.
468          * </ul>
469          *
470          * @param schemaType The schema type to set visibility on.
471          * @param visibleToPermissionSets The Sets of Android permissions that will be required to
472          *     access the given schema.
473          * @see android.Manifest.permission#READ_SMS
474          * @see android.Manifest.permission#READ_CALENDAR
475          * @see android.Manifest.permission#READ_CONTACTS
476          * @see android.Manifest.permission#READ_EXTERNAL_STORAGE
477          * @see android.Manifest.permission#READ_HOME_APP_SEARCH_DATA
478          * @see android.Manifest.permission#READ_ASSISTANT_APP_SEARCH_DATA
479          */
480         // TODO(b/237388235): add enterprise permissions to javadocs after they're unhidden
481         // Getter getRequiredPermissionsForSchemaTypeVisibility returns a map for all schemaTypes.
482         // To use this API doesn't require permissions.
483         @CanIgnoreReturnValue
484         @SuppressLint({"MissingGetterMatchingBuilder", "RequiresPermission"})
485         // @SetSchemaRequest is an IntDef annotation applied to Set<Set<Integer>>.
486         @SuppressWarnings("SupportAnnotationUsage")
setRequiredPermissionsForSchemaTypeVisibility( @onNull String schemaType, @SetSchemaRequest.AppSearchSupportedPermission @NonNull Set<Set<Integer>> visibleToPermissionSets)487         public @NonNull Builder setRequiredPermissionsForSchemaTypeVisibility(
488                 @NonNull String schemaType,
489                 @SetSchemaRequest.AppSearchSupportedPermission @NonNull
490                         Set<Set<Integer>> visibleToPermissionSets) {
491             Objects.requireNonNull(schemaType);
492             Objects.requireNonNull(visibleToPermissionSets);
493             resetIfBuilt();
494             InternalVisibilityConfig.Builder visibilityConfigBuilder =
495                     getOrCreateVisibilityConfigBuilder(schemaType);
496             for (Set<Integer> visibleToPermissions : visibleToPermissionSets) {
497                 visibilityConfigBuilder.addVisibleToPermissions(visibleToPermissions);
498             }
499             return this;
500         }
501 
502         /**
503          * Clears the set of required {@link android.Manifest.permission} combinations to read the
504          * given schema type.
505          *
506          * @see Builder#setRequiredPermissionsForSchemaTypeVisibility
507          */
508         // To use this API doesn't require permissions.
509 
510         @SuppressLint("RequiresPermission")
511         @FlaggedApi(Flags.FLAG_ENABLE_ADDITIONAL_BUILDER_COPY_CONSTRUCTORS)
512         @CanIgnoreReturnValue
clearRequiredPermissionsForSchemaTypeVisibility( @onNull String schemaType)513         public @NonNull Builder clearRequiredPermissionsForSchemaTypeVisibility(
514                 @NonNull String schemaType) {
515             Objects.requireNonNull(schemaType);
516             resetIfBuilt();
517             InternalVisibilityConfig.Builder visibilityConfigBuilder =
518                     getVisibilityConfigBuilder(schemaType);
519             if (visibilityConfigBuilder != null) {
520                 visibilityConfigBuilder.clearVisibleToPermissions();
521             }
522             return this;
523         }
524 
525         /**
526          * Specify that the schema should be publicly available, to packages which already have
527          * visibility to {@code packageIdentifier}.
528          *
529          * @param schemaType the schema to make publicly accessible.
530          * @param packageIdentifier the package from which the document schema is from.
531          * @see SetSchemaRequest.Builder#setPubliclyVisibleSchema
532          */
533         // Merged list available from getPubliclyVisibleSchemas
534         @CanIgnoreReturnValue
535         @SuppressLint("MissingGetterMatchingBuilder")
536         @FlaggedApi(Flags.FLAG_ENABLE_SET_PUBLICLY_VISIBLE_SCHEMA)
setPubliclyVisibleSchema( @onNull String schemaType, @NonNull PackageIdentifier packageIdentifier)537         public @NonNull Builder setPubliclyVisibleSchema(
538                 @NonNull String schemaType, @NonNull PackageIdentifier packageIdentifier) {
539             Objects.requireNonNull(schemaType);
540             Objects.requireNonNull(packageIdentifier);
541             resetIfBuilt();
542             InternalVisibilityConfig.Builder visibilityConfigBuilder =
543                     getOrCreateVisibilityConfigBuilder(schemaType);
544             visibilityConfigBuilder.setPubliclyVisibleTargetPackage(packageIdentifier);
545             return this;
546         }
547 
548         /**
549          * Clears the visibility setting that specifies that the given schema type should be
550          * publicly available to packages which already have visibility to a specified package.
551          *
552          * @see Builder#setPubliclyVisibleSchema
553          */
554         @FlaggedApi(Flags.FLAG_ENABLE_ADDITIONAL_BUILDER_COPY_CONSTRUCTORS)
555         @CanIgnoreReturnValue
clearPubliclyVisibleSchema(@onNull String schemaType)556         public @NonNull Builder clearPubliclyVisibleSchema(@NonNull String schemaType) {
557             Objects.requireNonNull(schemaType);
558             resetIfBuilt();
559             InternalVisibilityConfig.Builder visibilityConfigBuilder =
560                     getVisibilityConfigBuilder(schemaType);
561             if (visibilityConfigBuilder != null) {
562                 visibilityConfigBuilder.setPubliclyVisibleTargetPackage(null);
563             }
564             return this;
565         }
566 
567         /**
568          * Sets the documents from the provided {@code schemaType} can be read by the caller if they
569          * match the ALL visibility requirements set in {@link SchemaVisibilityConfig}.
570          *
571          * <p>The requirements in a {@link SchemaVisibilityConfig} is "AND" relationship. A caller
572          * must match ALL requirements to access the schema. For example, a caller must hold
573          * required permissions AND it is a specified package.
574          *
575          * <p>The querier could have access if they match ALL requirements in ANY of the given
576          * {@link SchemaVisibilityConfig}s
577          *
578          * <p>For example, if the Set contains {@code {% verbatim %}{{PackageA and Permission1},
579          * {PackageB and Permission2}}{% endverbatim %}}.
580          *
581          * <ul>
582          *   <li>A querier from packageA could read if they holds Permission1.
583          *   <li>A querier from packageA could NOT read if they only holds Permission2 instead of
584          *       Permission1.
585          *   <li>A querier from packageB could read if they holds Permission2.
586          *   <li>A querier from packageC could never read.
587          *   <li>A querier holds both PermissionA and PermissionE has access.
588          * </ul>
589          *
590          * @param schemaType The schema type to set visibility on.
591          * @param visibleToConfigs The {@link SchemaVisibilityConfig}s hold all requirements that a
592          *     call must to match to access the schema.
593          */
594         // Merged map available from getSchemasVisibleToConfigs
595         @CanIgnoreReturnValue
596         @SuppressLint("MissingGetterMatchingBuilder")
597         @FlaggedApi(Flags.FLAG_ENABLE_SET_SCHEMA_VISIBLE_TO_CONFIGS)
setSchemaTypeVisibleToConfigs( @onNull String schemaType, @NonNull Set<SchemaVisibilityConfig> visibleToConfigs)598         public @NonNull Builder setSchemaTypeVisibleToConfigs(
599                 @NonNull String schemaType, @NonNull Set<SchemaVisibilityConfig> visibleToConfigs) {
600             Objects.requireNonNull(schemaType);
601             Objects.requireNonNull(visibleToConfigs);
602             resetIfBuilt();
603             InternalVisibilityConfig.Builder visibilityConfigBuilder =
604                     getOrCreateVisibilityConfigBuilder(schemaType);
605             for (SchemaVisibilityConfig visibleToConfig : visibleToConfigs) {
606                 visibilityConfigBuilder.addVisibleToConfig(visibleToConfig);
607             }
608             return this;
609         }
610 
611         /**
612          * Clears the {@link SchemaVisibilityConfig}s for the given schema type which allow
613          * visibility to the schema if the caller matches ALL visibility requirements of ANY {@link
614          * SchemaVisibilityConfig}.
615          *
616          * @see Builder#setSchemaTypeVisibleToConfigs
617          */
618         @FlaggedApi(Flags.FLAG_ENABLE_ADDITIONAL_BUILDER_COPY_CONSTRUCTORS)
619         @CanIgnoreReturnValue
clearSchemaTypeVisibleToConfigs(@onNull String schemaType)620         public @NonNull Builder clearSchemaTypeVisibleToConfigs(@NonNull String schemaType) {
621             Objects.requireNonNull(schemaType);
622             resetIfBuilt();
623             InternalVisibilityConfig.Builder visibilityConfigBuilder =
624                     getVisibilityConfigBuilder(schemaType);
625             if (visibilityConfigBuilder != null) {
626                 visibilityConfigBuilder.clearVisibleToConfig();
627             }
628             return this;
629         }
630 
631         /**
632          * Method to set visibility setting. If this is called with false, {@link
633          * #getRequiredPermissionsForSchemaTypeVisibility()}, {@link
634          * #getSchemaTypesNotDisplayedBySystem()}}, and {@link #getSchemaTypesVisibleToPackages()}
635          * calls will throw an {@link UnsupportedOperationException}. If called with true,
636          * visibility information for all schemas will be cleared.
637          *
638          * @param visibilitySettingSupported whether supported {@link
639          *     Features#ADD_PERMISSIONS_AND_GET_VISIBILITY} by this backend/Android API level.
640          * @hide
641          */
642         // Visibility setting is determined by SDK version, so it won't be needed in framework
643         @CanIgnoreReturnValue
644         @SuppressLint("MissingGetterMatchingBuilder")
setVisibilitySettingSupported(boolean visibilitySettingSupported)645         public @NonNull Builder setVisibilitySettingSupported(boolean visibilitySettingSupported) {
646             if (visibilitySettingSupported) {
647                 mVisibilityConfigBuilders = new ArrayMap<>();
648             } else {
649                 mVisibilityConfigBuilders = null;
650             }
651             return this;
652         }
653 
654         /** Builds a {@link GetSchemaResponse} object. */
build()655         public @NonNull GetSchemaResponse build() {
656             List<InternalVisibilityConfig> visibilityConfigs = null;
657             if (mVisibilityConfigBuilders != null) {
658                 visibilityConfigs = new ArrayList<>();
659                 for (InternalVisibilityConfig.Builder builder :
660                         mVisibilityConfigBuilders.values()) {
661                     visibilityConfigs.add(builder.build());
662                 }
663             }
664             mBuilt = true;
665             return new GetSchemaResponse(mVersion, mSchemas, visibilityConfigs);
666         }
667 
getOrCreateVisibilityConfigBuilder( @onNull String schemaType)668         private @NonNull InternalVisibilityConfig.Builder getOrCreateVisibilityConfigBuilder(
669                 @NonNull String schemaType) {
670             if (mVisibilityConfigBuilders == null) {
671                 throw new IllegalStateException(
672                         "GetSchemaResponse is not configured with" + "visibility setting support");
673             }
674             InternalVisibilityConfig.Builder builder = mVisibilityConfigBuilders.get(schemaType);
675             if (builder == null) {
676                 builder = new InternalVisibilityConfig.Builder(schemaType);
677                 mVisibilityConfigBuilders.put(schemaType, builder);
678             }
679             return builder;
680         }
681 
getVisibilityConfigBuilder( @onNull String schemaType)682         private @Nullable InternalVisibilityConfig.Builder getVisibilityConfigBuilder(
683                 @NonNull String schemaType) {
684             if (mVisibilityConfigBuilders == null) {
685                 throw new IllegalStateException(
686                         "GetSchemaResponse is not configured with" + "visibility setting support");
687             }
688             return mVisibilityConfigBuilders.get(schemaType);
689         }
690 
resetIfBuilt()691         private void resetIfBuilt() {
692             if (mBuilt) {
693                 // No need to copy mVisibilityConfigBuilders -- it gets copied during build().
694                 mSchemas = new ArrayList<>(mSchemas);
695                 mBuilt = false;
696             }
697         }
698     }
699 }
700