• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2022 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 com.android.server.appsearch.external.localstorage.converter;
18 
19 import android.annotation.NonNull;
20 import android.util.ArraySet;
21 
22 import com.google.android.icing.proto.SchemaTypeConfigProto;
23 
24 import java.util.List;
25 import java.util.Map;
26 import java.util.Set;
27 
28 /**
29  * Utilities for working with {@link SearchSpecToProtoConverter} and {@link
30  * SearchSuggestionSpecToProtoConverter}.
31  *
32  * @hide
33  */
34 public class SearchSpecToProtoConverterUtil {
SearchSpecToProtoConverterUtil()35     private SearchSpecToProtoConverterUtil() {}
36 
37     /**
38      * Add prefix to the given namespace filters that user want to search over and find the
39      * intersection set with those prefixed namespace candidates that are stored in AppSearch.
40      *
41      * @param prefixes Set of database prefix which the caller want to access.
42      * @param namespaceMap The cached Map of {@code <Prefix, Set<PrefixedNamespace>>} stores all
43      *     prefixed namespace filters which are stored in AppSearch.
44      * @param inputNamespaceFilters The set contains all desired but un-prefixed namespace filters
45      *     of user. If the inputNamespaceFilters is empty, all existing prefixedCandidates will be
46      *     added to the prefixedTargetFilters.
47      */
generateTargetNamespaceFilters( @onNull Set<String> prefixes, @NonNull Map<String, Set<String>> namespaceMap, @NonNull List<String> inputNamespaceFilters)48     static Set<String> generateTargetNamespaceFilters(
49             @NonNull Set<String> prefixes,
50             @NonNull Map<String, Set<String>> namespaceMap,
51             @NonNull List<String> inputNamespaceFilters) {
52         // Convert namespace filters to prefixed namespace filters
53         Set<String> targetPrefixedNamespaceFilters = new ArraySet<>();
54         for (String prefix : prefixes) {
55             // Step1: find all prefixed namespace candidates that are stored in AppSearch.
56             Set<String> prefixedNamespaceCandidates = namespaceMap.get(prefix);
57             if (prefixedNamespaceCandidates == null) {
58                 // This is should never happen. All prefixes should be verified before reach
59                 // here.
60                 continue;
61             }
62             // Step2: get the intersection of user searching filters and those candidates which are
63             // stored in AppSearch.
64             addIntersectedFilters(
65                     prefix,
66                     prefixedNamespaceCandidates,
67                     inputNamespaceFilters,
68                     targetPrefixedNamespaceFilters);
69         }
70         return targetPrefixedNamespaceFilters;
71     }
72 
73     /**
74      * Add prefix to the given schema filters that user want to search over and find the
75      * intersection set with those prefixed schema candidates that are stored in AppSearch.
76      *
77      * @param prefixes Set of database prefix which the caller want to access.
78      * @param schemaMap The cached Map of {@code <Prefix, Map<PrefixedSchemaType, schemaProto>>}
79      *     stores all prefixed schema filters which are stored in AppSearch.
80      * @param inputSchemaFilters The set contains all desired but un-prefixed namespace filters of
81      *     user. If the inputSchemaFilters is empty, all existing prefixedCandidates will be added
82      *     to the prefixedTargetFilters.
83      */
generateTargetSchemaFilters( @onNull Set<String> prefixes, @NonNull Map<String, Map<String, SchemaTypeConfigProto>> schemaMap, @NonNull List<String> inputSchemaFilters)84     static Set<String> generateTargetSchemaFilters(
85             @NonNull Set<String> prefixes,
86             @NonNull Map<String, Map<String, SchemaTypeConfigProto>> schemaMap,
87             @NonNull List<String> inputSchemaFilters) {
88         Set<String> targetPrefixedSchemaFilters = new ArraySet<>();
89         // Append prefix to input schema filters and get the intersection of existing schema filter.
90         for (String prefix : prefixes) {
91             // Step1: find all prefixed schema candidates that are stored in AppSearch.
92             Map<String, SchemaTypeConfigProto> prefixedSchemaMap = schemaMap.get(prefix);
93             if (prefixedSchemaMap == null) {
94                 // This is should never happen. All prefixes should be verified before reach
95                 // here.
96                 continue;
97             }
98             Set<String> prefixedSchemaCandidates = prefixedSchemaMap.keySet();
99             // Step2: get the intersection of user searching filters and those candidates which are
100             // stored in AppSearch.
101             addIntersectedFilters(
102                     prefix,
103                     prefixedSchemaCandidates,
104                     inputSchemaFilters,
105                     targetPrefixedSchemaFilters);
106         }
107         return targetPrefixedSchemaFilters;
108     }
109 
110     /**
111      * Find the intersection set of candidates existing in AppSearch and user specified filters.
112      *
113      * @param prefix The package and database's identifier.
114      * @param prefixedCandidates The set contains all prefixed candidates which are existing in a
115      *     database.
116      * @param inputFilters The set contains all desired but un-prefixed filters of user. If the
117      *     inputFilters is empty, all prefixedCandidates will be added to the prefixedTargetFilters.
118      * @param prefixedTargetFilters The output set contains all desired prefixed filters which are
119      *     existing in the database.
120      */
addIntersectedFilters( @onNull String prefix, @NonNull Set<String> prefixedCandidates, @NonNull List<String> inputFilters, @NonNull Set<String> prefixedTargetFilters)121     private static void addIntersectedFilters(
122             @NonNull String prefix,
123             @NonNull Set<String> prefixedCandidates,
124             @NonNull List<String> inputFilters,
125             @NonNull Set<String> prefixedTargetFilters) {
126         if (inputFilters.isEmpty()) {
127             // Client didn't specify certain schemas to search over, add all candidates.
128             prefixedTargetFilters.addAll(prefixedCandidates);
129         } else {
130             // Client specified some filters to search over, check and only add those are
131             // existing in the database.
132             for (int i = 0; i < inputFilters.size(); i++) {
133                 String prefixedTargetFilter = prefix + inputFilters.get(i);
134                 if (prefixedCandidates.contains(prefixedTargetFilter)) {
135                     prefixedTargetFilters.add(prefixedTargetFilter);
136                 }
137             }
138         }
139     }
140 }
141