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