• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.app.appsearch.safeparcel.AbstractSafeParcelable;
20 import android.app.appsearch.safeparcel.SafeParcelable;
21 import android.os.Parcel;
22 import android.os.Parcelable;
23 import android.util.ArraySet;
24 
25 import org.jspecify.annotations.NonNull;
26 import org.jspecify.annotations.Nullable;
27 
28 import java.util.Arrays;
29 import java.util.Objects;
30 import java.util.Set;
31 
32 /**
33  * The config class that holds all required permissions for a caller need to hold to access the
34  * schema which the outer {@link SchemaVisibilityConfig} represents.
35  *
36  * @hide
37  */
38 @SafeParcelable.Class(creator = "VisibilityPermissionConfigCreator")
39 public final class VisibilityPermissionConfig extends AbstractSafeParcelable {
40     public static final Parcelable.@NonNull Creator<VisibilityPermissionConfig> CREATOR =
41             new VisibilityPermissionConfigCreator();
42 
43     /**
44      * The Schema type for documents that hold AppSearch's metadata, such as visibility settings.
45      */
46     public static final String SCHEMA_TYPE = "VisibilityPermissionType";
47 
48     /** Property that holds the required permissions to access the schema. */
49     public static final String ALL_REQUIRED_PERMISSIONS_PROPERTY = "allRequiredPermissions";
50 
51     /**
52      * Schema for the VisibilityStore's documents.
53      *
54      * <p>NOTE: If you update this, also update schema version number in
55      * VisibilityToDocumentConverter
56      */
57     public static final AppSearchSchema SCHEMA =
58             new AppSearchSchema.Builder(SCHEMA_TYPE)
59                     .addProperty(
60                             new AppSearchSchema.LongPropertyConfig.Builder(
61                                             ALL_REQUIRED_PERMISSIONS_PROPERTY)
62                                     .setCardinality(
63                                             AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
64                                     .build())
65                     .build();
66 
67     @Field(id = 1)
68     final int @Nullable [] mAllRequiredPermissions;
69 
70     // We still need to convert this class to a GenericDocument until we completely treat it
71     // differently in AppSearchImpl.
72     // TODO(b/298118943) Remove this once internally we don't use GenericDocument to store
73     //  visibility information.
74     private @Nullable GenericDocument mGenericDocument;
75 
76     private @Nullable Integer mHashCode;
77 
78     @Constructor
VisibilityPermissionConfig(@aramid = 1) int @Nullable [] allRequiredPermissions)79     VisibilityPermissionConfig(@Param(id = 1) int @Nullable [] allRequiredPermissions) {
80         mAllRequiredPermissions = allRequiredPermissions;
81     }
82 
83     /**
84      * Sets a set of Android Permissions that caller must hold to access the schema that the outer
85      * {@link SchemaVisibilityConfig} represents.
86      */
VisibilityPermissionConfig(@onNull Set<Integer> allRequiredPermissions)87     public VisibilityPermissionConfig(@NonNull Set<Integer> allRequiredPermissions) {
88         mAllRequiredPermissions = toInts(Objects.requireNonNull(allRequiredPermissions));
89     }
90 
91     /**
92      * Returns an array of Android Permissions that caller mush hold to access the schema that the
93      * outer {@link SchemaVisibilityConfig} represents.
94      */
getAllRequiredPermissions()95     public @Nullable Set<Integer> getAllRequiredPermissions() {
96         return toIntegerSet(mAllRequiredPermissions);
97     }
98 
toInts(@onNull Set<Integer> properties)99     private static int @NonNull [] toInts(@NonNull Set<Integer> properties) {
100         int[] outputs = new int[properties.size()];
101         int i = 0;
102         for (int property : properties) {
103             outputs[i++] = property;
104         }
105         return outputs;
106     }
107 
toIntegerSet(int @Nullable [] properties)108     private static @Nullable Set<Integer> toIntegerSet(int @Nullable [] properties) {
109         if (properties == null) {
110             return null;
111         }
112         Set<Integer> outputs = new ArraySet<>(properties.length);
113         for (int property : properties) {
114             outputs.add(property);
115         }
116         return outputs;
117     }
118 
119     /**
120      * Generates a {@link GenericDocument} from the current class.
121      *
122      * <p>This conversion is needed until we don't treat Visibility related documents as {@link
123      * GenericDocument}s internally.
124      */
toGenericDocument()125     public @NonNull GenericDocument toGenericDocument() {
126         if (mGenericDocument == null) {
127             // This is used as a nested document, we do not need a namespace or id.
128             GenericDocument.Builder<?> builder =
129                     new GenericDocument.Builder<>(/* namespace= */ "", /* id= */ "", SCHEMA_TYPE);
130 
131             if (mAllRequiredPermissions != null) {
132                 // GenericDocument only supports long, so int[] needs to be converted to
133                 // long[] here.
134                 long[] longs = new long[mAllRequiredPermissions.length];
135                 for (int i = 0; i < mAllRequiredPermissions.length; ++i) {
136                     longs[i] = mAllRequiredPermissions[i];
137                 }
138                 builder.setPropertyLong(ALL_REQUIRED_PERMISSIONS_PROPERTY, longs);
139             }
140 
141             // The creationTimestamp doesn't matter for Visibility documents.
142             // But to make tests pass, we set it 0 so two GenericDocuments generated from
143             // the same VisibilityPermissionConfig can be same.
144             builder.setCreationTimestampMillis(0L);
145 
146             mGenericDocument = builder.build();
147         }
148         return mGenericDocument;
149     }
150 
151     @Override
hashCode()152     public int hashCode() {
153         if (mHashCode == null) {
154             mHashCode = Arrays.hashCode(mAllRequiredPermissions);
155         }
156         return mHashCode;
157     }
158 
159     @Override
equals(@ullable Object other)160     public boolean equals(@Nullable Object other) {
161         if (this == other) {
162             return true;
163         }
164         if (!(other instanceof VisibilityPermissionConfig)) {
165             return false;
166         }
167         VisibilityPermissionConfig otherVisibilityPermissionConfig =
168                 (VisibilityPermissionConfig) other;
169         return Arrays.equals(
170                 mAllRequiredPermissions, otherVisibilityPermissionConfig.mAllRequiredPermissions);
171     }
172 
173     @Override
writeToParcel(@onNull Parcel dest, int flags)174     public void writeToParcel(@NonNull Parcel dest, int flags) {
175         VisibilityPermissionConfigCreator.writeToParcel(this, dest, flags);
176     }
177 }
178