1 /* 2 * Copyright (C) 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 com.android.server.appsearch.transformer; 18 19 import android.annotation.NonNull; 20 import android.app.appsearch.GenericDocument; 21 import android.app.appsearch.SearchResult; 22 import android.app.appsearch.SearchResultPage; 23 24 import com.android.internal.annotations.VisibleForTesting; 25 26 import java.util.ArrayList; 27 import java.util.List; 28 import java.util.Objects; 29 30 /** Transforms the retrieved documents in {@link SearchResult} for enterprise access. */ 31 public final class EnterpriseSearchResultPageTransformer { 32 EnterpriseSearchResultPageTransformer()33 private EnterpriseSearchResultPageTransformer() {} 34 35 /** 36 * Transforms a {@link SearchResultPage}, applying enterprise document transformations in the 37 * {@link SearchResult}s where necessary. 38 */ 39 @NonNull transformSearchResultPage( @onNull SearchResultPage searchResultPage)40 public static SearchResultPage transformSearchResultPage( 41 @NonNull SearchResultPage searchResultPage) { 42 Objects.requireNonNull(searchResultPage); 43 if (!shouldTransformSearchResultPage(searchResultPage)) { 44 return searchResultPage; 45 } 46 List<SearchResult> results = searchResultPage.getResults(); 47 List<SearchResult> transformedResults = new ArrayList<>(); 48 for (int i = 0; i < results.size(); i++) { 49 transformedResults.add(transformSearchResult(results.get(i))); 50 } 51 return new SearchResultPage(searchResultPage.getNextPageToken(), transformedResults); 52 } 53 54 /** 55 * Transforms a {@link SearchResult} and nested joined {@link SearchResult}s, applying 56 * enterprise document transformations where necessary. 57 */ 58 @VisibleForTesting 59 @NonNull transformSearchResult(@onNull SearchResult originalResult)60 static SearchResult transformSearchResult(@NonNull SearchResult originalResult) { 61 Objects.requireNonNull(originalResult); 62 boolean shouldTransformDocument = 63 shouldTransformDocument( 64 originalResult.getPackageName(), 65 originalResult.getDatabaseName(), 66 originalResult.getGenericDocument()); 67 boolean shouldTransformJoinedResults = 68 shouldTransformSearchResults(originalResult.getJoinedResults()); 69 // Split the transform check so we can avoid transforming both the original and joined 70 // results when only one actually needs to be transformed. 71 if (!shouldTransformDocument && !shouldTransformJoinedResults) { 72 return originalResult; 73 } 74 SearchResult.Builder builder = new SearchResult.Builder(originalResult); 75 if (shouldTransformDocument) { 76 GenericDocument transformedDocument = 77 transformDocument( 78 originalResult.getPackageName(), 79 originalResult.getDatabaseName(), 80 originalResult.getGenericDocument()); 81 builder.setGenericDocument(transformedDocument); 82 } 83 if (shouldTransformJoinedResults) { 84 List<SearchResult> joinedResults = originalResult.getJoinedResults(); 85 builder.clearJoinedResults(); 86 for (int i = 0; i < joinedResults.size(); i++) { 87 SearchResult transformedResult = transformSearchResult(joinedResults.get(i)); 88 builder.addJoinedResult(transformedResult); 89 } 90 } 91 return builder.build(); 92 } 93 94 /** 95 * Transforms the given document specific to its schema type, package, and database or returns 96 * the original document if the combination is not recognized. 97 */ 98 @NonNull transformDocument( @onNull String packageName, @NonNull String databaseName, @NonNull GenericDocument originalDocument)99 public static GenericDocument transformDocument( 100 @NonNull String packageName, 101 @NonNull String databaseName, 102 @NonNull GenericDocument originalDocument) { 103 if (PersonEnterpriseTransformer.shouldTransform( 104 packageName, databaseName, originalDocument.getSchemaType())) { 105 return PersonEnterpriseTransformer.transformDocument(originalDocument); 106 } 107 return originalDocument; 108 } 109 110 /** Checks if we need to transform the {@link SearchResultPage}. */ shouldTransformSearchResultPage( @onNull SearchResultPage searchResultPage)111 private static boolean shouldTransformSearchResultPage( 112 @NonNull SearchResultPage searchResultPage) { 113 List<SearchResult> results = searchResultPage.getResults(); 114 for (int i = 0; i < results.size(); i++) { 115 if (shouldTransformSearchResult(results.get(i))) { 116 return true; 117 } 118 } 119 return false; 120 } 121 122 /** Checks if we need to transform the {@link SearchResult}. */ shouldTransformSearchResult(@onNull SearchResult searchResult)123 private static boolean shouldTransformSearchResult(@NonNull SearchResult searchResult) { 124 return shouldTransformDocument( 125 searchResult.getPackageName(), 126 searchResult.getDatabaseName(), 127 searchResult.getGenericDocument()) 128 || shouldTransformSearchResults(searchResult.getJoinedResults()); 129 } 130 131 /** Checks if we need to transform the {@link SearchResult}s. */ shouldTransformSearchResults(@onNull List<SearchResult> searchResults)132 private static boolean shouldTransformSearchResults(@NonNull List<SearchResult> searchResults) { 133 for (int i = 0; i < searchResults.size(); i++) { 134 if (shouldTransformSearchResult(searchResults.get(i))) { 135 return true; 136 } 137 } 138 return false; 139 } 140 141 /** Checks if we need to transform the {@link GenericDocument}. */ shouldTransformDocument( @onNull String packageName, @NonNull String databaseName, @NonNull GenericDocument document)142 private static boolean shouldTransformDocument( 143 @NonNull String packageName, 144 @NonNull String databaseName, 145 @NonNull GenericDocument document) { 146 return PersonEnterpriseTransformer.shouldTransform( 147 packageName, databaseName, document.getSchemaType()); 148 } 149 } 150