Update framework from jetpack.

Changes included:
* 25ca4ff: Sync AppSearch with google3 update ag/14473436 (f13a174)
* a1ad7b4: Make GenericDocument#toString print results in a deterministic order.
* bf3051b: Sync AppSearchResult and AppSearchBatchResult to framework.
* dd3c05f: Add more call types
* fb27537: Add API coverage for SearchSpec.getProjections

Bug: 185445694
Bug: 187424629
Bug: 146218515
Bug: 173532925
Bug: 183239965
Test: Presubmit
Change-Id: I5392a10fe03451a895136cdbc75d5bf0df081aa3
This commit is contained in:
Alexander Dorokhine
2021-05-11 12:42:17 -07:00
parent 48df6c6055
commit ffa64b6009
8 changed files with 134 additions and 153 deletions

View File

@@ -19,8 +19,6 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.util.ArrayMap;
import com.android.internal.util.Preconditions;
import java.util.Map;
import java.util.Objects;
@@ -117,30 +115,26 @@ public final class AppSearchBatchResult<KeyType, ValueType> {
/**
* Builder for {@link AppSearchBatchResult} objects.
*
* <p>Once {@link #build} is called, the instance can no longer be used.
*
* @param <KeyType> The type of the keys for which the results will be reported.
* @param <ValueType> The type of the result objects for successful results.
*/
public static final class Builder<KeyType, ValueType> {
private final Map<KeyType, ValueType> mSuccesses = new ArrayMap<>();
private final Map<KeyType, AppSearchResult<ValueType>> mFailures = new ArrayMap<>();
private final Map<KeyType, AppSearchResult<ValueType>> mAll = new ArrayMap<>();
private ArrayMap<KeyType, ValueType> mSuccesses = new ArrayMap<>();
private ArrayMap<KeyType, AppSearchResult<ValueType>> mFailures = new ArrayMap<>();
private ArrayMap<KeyType, AppSearchResult<ValueType>> mAll = new ArrayMap<>();
private boolean mBuilt = false;
/**
* Associates the {@code key} with the provided successful return value.
*
* <p>Any previous mapping for a key, whether success or failure, is deleted.
*
* @throws IllegalStateException if the builder has already been used.
*/
@SuppressWarnings("MissingGetterMatchingBuilder") // See getSuccesses
@NonNull
public Builder<KeyType, ValueType> setSuccess(
@NonNull KeyType key, @Nullable ValueType result) {
Preconditions.checkState(!mBuilt, "Builder has already been used");
Objects.requireNonNull(key);
resetIfBuilt();
return setResult(key, AppSearchResult.newSuccessfulResult(result));
}
@@ -148,8 +142,6 @@ public final class AppSearchBatchResult<KeyType, ValueType> {
* Associates the {@code key} with the provided failure code and error message.
*
* <p>Any previous mapping for a key, whether success or failure, is deleted.
*
* @throws IllegalStateException if the builder has already been used.
*/
@SuppressWarnings("MissingGetterMatchingBuilder") // See getFailures
@NonNull
@@ -157,8 +149,8 @@ public final class AppSearchBatchResult<KeyType, ValueType> {
@NonNull KeyType key,
@AppSearchResult.ResultCode int resultCode,
@Nullable String errorMessage) {
Preconditions.checkState(!mBuilt, "Builder has already been used");
Objects.requireNonNull(key);
resetIfBuilt();
return setResult(key, AppSearchResult.newFailedResult(resultCode, errorMessage));
}
@@ -166,16 +158,14 @@ public final class AppSearchBatchResult<KeyType, ValueType> {
* Associates the {@code key} with the provided {@code result}.
*
* <p>Any previous mapping for a key, whether success or failure, is deleted.
*
* @throws IllegalStateException if the builder has already been used.
*/
@SuppressWarnings("MissingGetterMatchingBuilder") // See getAll
@NonNull
public Builder<KeyType, ValueType> setResult(
@NonNull KeyType key, @NonNull AppSearchResult<ValueType> result) {
Preconditions.checkState(!mBuilt, "Builder has already been used");
Objects.requireNonNull(key);
Objects.requireNonNull(result);
resetIfBuilt();
if (result.isSuccess()) {
mSuccesses.put(key, result.getResultValue());
mFailures.remove(key);
@@ -189,14 +179,21 @@ public final class AppSearchBatchResult<KeyType, ValueType> {
/**
* Builds an {@link AppSearchBatchResult} object from the contents of this {@link Builder}.
*
* @throws IllegalStateException if the builder has already been used.
*/
@NonNull
public AppSearchBatchResult<KeyType, ValueType> build() {
Preconditions.checkState(!mBuilt, "Builder has already been used");
mBuilt = true;
return new AppSearchBatchResult<>(mSuccesses, mFailures, mAll);
return new AppSearchBatchResult<>(
new ArrayMap<>(mSuccesses), new ArrayMap<>(mFailures), new ArrayMap<>(mAll));
}
private void resetIfBuilt() {
if (mBuilt) {
mSuccesses = new ArrayMap<>(mSuccesses);
mFailures = new ArrayMap<>(mFailures);
mAll = new ArrayMap<>(mAll);
mBuilt = false;
}
}
}
}

View File

@@ -892,129 +892,121 @@ public class GenericDocument {
@Override
@NonNull
public String toString() {
return formatGenericDocumentString(this, /*indentLevel=*/ 0);
StringBuilder stringBuilder = new StringBuilder();
appendGenericDocumentString(this, /*indentLevel=*/ 0, stringBuilder);
return stringBuilder.toString();
}
@NonNull
private static String formatGenericDocumentString(
@NonNull GenericDocument document, int indentLevel) {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append(getIndent(indentLevel)).append("{\n");
private static void appendGenericDocumentString(
@NonNull GenericDocument document, int indentLevel, @NonNull StringBuilder builder) {
Objects.requireNonNull(document);
Objects.requireNonNull(builder);
String indentLevelOneString = getIndent(indentLevel + 1);
builder.append(getIndent(indentLevel)).append("{\n");
stringBuilder
.append(indentLevelOneString)
String indent1 = getIndent(indentLevel + 1);
builder.append(indent1)
.append("namespace: \"")
.append(document.getNamespace())
.append("\",\n");
stringBuilder
.append(indentLevelOneString)
.append("id: \"")
.append(document.getId())
.append("\",\n");
builder.append(indent1).append("id: \"").append(document.getId()).append("\",\n");
stringBuilder
.append(indentLevelOneString)
.append("score: " + document.getScore())
.append(",\n");
builder.append(indent1).append("score: ").append(document.getScore()).append(",\n");
stringBuilder
.append(indentLevelOneString)
builder.append(indent1)
.append("schemaType: \"")
.append(document.getSchemaType())
.append("\",\n");
stringBuilder
.append(indentLevelOneString)
.append("creationTimestampMillis: " + document.getCreationTimestampMillis())
builder.append(indent1)
.append("creationTimestampMillis: ")
.append(document.getCreationTimestampMillis())
.append(",\n");
stringBuilder
.append(indentLevelOneString)
.append("timeToLiveMillis: " + document.getTtlMillis())
builder.append(indent1)
.append("timeToLiveMillis: ")
.append(document.getTtlMillis())
.append(",\n");
stringBuilder.append(indentLevelOneString).append("properties: {\n");
builder.append(indent1).append("properties: {\n");
int idx = 0;
for (String propertyName : document.getPropertyNames()) {
Object property = document.getProperty(propertyName);
stringBuilder
.append(getIndent(indentLevel + 2))
String[] sortedProperties = document.getPropertyNames().toArray(new String[0]);
Arrays.sort(sortedProperties);
for (int i = 0; i < sortedProperties.length; i++) {
Object property = document.getProperty(sortedProperties[i]);
builder.append(getIndent(indentLevel + 2))
.append("\"")
.append(propertyName)
.append(sortedProperties[i])
.append("\"")
.append(": ");
stringBuilder.append(getPropertyString(property, indentLevel + 2));
if (idx != document.getPropertyNames().size() - 1) {
stringBuilder.append(",\n");
appendPropertyString(property, indentLevel + 2, builder);
if (i != sortedProperties.length - 1) {
builder.append(",\n");
}
++idx;
}
stringBuilder.append("\n");
stringBuilder.append(indentLevelOneString).append("}");
builder.append("\n");
builder.append(indent1).append("}");
stringBuilder.append("\n");
stringBuilder.append(getIndent(indentLevel)).append("}");
return stringBuilder.toString();
builder.append("\n");
builder.append(getIndent(indentLevel)).append("}");
}
/**
* Creates string for property.
* Appends a string for the given property to the given builder.
*
* @param property property object to create string for.
* @param indentLevel base indent level for property.
* @param builder the builder to append to.
*/
@NonNull
private static String getPropertyString(@NonNull Object property, int indentLevel) {
private static void appendPropertyString(
@NonNull Object property, int indentLevel, @NonNull StringBuilder builder) {
Objects.requireNonNull(property);
Objects.requireNonNull(builder);
StringBuilder str = new StringBuilder("[");
builder.append("[");
if (property instanceof GenericDocument[]) {
GenericDocument[] documentValues = (GenericDocument[]) property;
for (int i = 0; i < documentValues.length; ++i) {
str.append("\n");
str.append(formatGenericDocumentString(documentValues[i], indentLevel + 1));
builder.append("\n");
appendGenericDocumentString(documentValues[i], indentLevel + 1, builder);
if (i != documentValues.length - 1) {
str.append(", ");
builder.append(", ");
}
str.append("\n");
builder.append("\n");
}
str.append(getIndent(indentLevel));
builder.append(getIndent(indentLevel));
} else {
int propertyArrLength = Array.getLength(property);
for (int i = 0; i < propertyArrLength; i++) {
Object propertyElement = Array.get(property, i);
if (propertyElement instanceof String) {
str.append("\"").append(propertyElement).append("\"");
builder.append("\"").append(propertyElement).append("\"");
} else if (propertyElement instanceof byte[]) {
str.append(Arrays.toString((byte[]) propertyElement));
builder.append(Arrays.toString((byte[]) propertyElement));
} else {
str.append(propertyElement);
builder.append(propertyElement);
}
if (i != propertyArrLength - 1) {
str.append(", ");
builder.append(", ");
}
}
}
str.append("]");
return str.toString();
builder.append("]");
}
/** Creates string for given indent level. */
/** Appends a string for given indent level to the given builder. */
@NonNull
private static String getIndent(int indentLevel) {
StringBuilder indentedString = new StringBuilder();
StringBuilder builder = new StringBuilder();
for (int i = 0; i < indentLevel; ++i) {
indentedString.append(" ");
builder.append(" ");
}
return indentedString.toString();
return builder.toString();
}
/**

View File

@@ -128,14 +128,14 @@ public class SearchResultToProtoConverter {
return new SearchResult.MatchInfo.Builder(propertyPath)
.setExactMatchRange(
new SearchResult.MatchRange(
snippetMatchProto.getExactMatchPosition(),
snippetMatchProto.getExactMatchPosition()
+ snippetMatchProto.getExactMatchBytes()))
snippetMatchProto.getExactMatchUtf16Position(),
snippetMatchProto.getExactMatchUtf16Position()
+ snippetMatchProto.getExactMatchUtf16Length()))
.setSnippetRange(
new SearchResult.MatchRange(
snippetMatchProto.getWindowPosition(),
snippetMatchProto.getWindowPosition()
+ snippetMatchProto.getWindowBytes()))
snippetMatchProto.getWindowUtf16Position(),
snippetMatchProto.getWindowUtf16Position()
+ snippetMatchProto.getWindowUtf16Length()))
.build();
}
}

View File

@@ -43,13 +43,16 @@ public class CallStats {
CALL_TYPE_SET_SCHEMA,
CALL_TYPE_PUT_DOCUMENTS,
CALL_TYPE_GET_DOCUMENTS,
CALL_TYPE_REMOVE_DOCUMENTS,
CALL_TYPE_REMOVE_DOCUMENTS_BY_ID,
CALL_TYPE_PUT_DOCUMENT,
CALL_TYPE_GET_DOCUMENT,
CALL_TYPE_REMOVE_DOCUMENT,
CALL_TYPE_QUERY,
CALL_TYPE_REMOVE_DOCUMENT_BY_ID,
CALL_TYPE_SEARCH,
CALL_TYPE_OPTIMIZE,
CALL_TYPE_FLUSH,
CALL_TYPE_GLOBAL_SEARCH,
CALL_TYPE_REMOVE_DOCUMENTS_BY_SEARCH,
CALL_TYPE_REMOVE_DOCUMENT_BY_SEARCH,
})
@Retention(RetentionPolicy.SOURCE)
public @interface CallType {}
@@ -59,13 +62,16 @@ public class CallStats {
public static final int CALL_TYPE_SET_SCHEMA = 2;
public static final int CALL_TYPE_PUT_DOCUMENTS = 3;
public static final int CALL_TYPE_GET_DOCUMENTS = 4;
public static final int CALL_TYPE_REMOVE_DOCUMENTS = 5;
public static final int CALL_TYPE_REMOVE_DOCUMENTS_BY_ID = 5;
public static final int CALL_TYPE_PUT_DOCUMENT = 6;
public static final int CALL_TYPE_GET_DOCUMENT = 7;
public static final int CALL_TYPE_REMOVE_DOCUMENT = 8;
public static final int CALL_TYPE_QUERY = 9;
public static final int CALL_TYPE_REMOVE_DOCUMENT_BY_ID = 8;
public static final int CALL_TYPE_SEARCH = 9;
public static final int CALL_TYPE_OPTIMIZE = 10;
public static final int CALL_TYPE_FLUSH = 11;
public static final int CALL_TYPE_GLOBAL_SEARCH = 12;
public static final int CALL_TYPE_REMOVE_DOCUMENTS_BY_SEARCH = 13;
public static final int CALL_TYPE_REMOVE_DOCUMENT_BY_SEARCH = 14;
@NonNull private final GeneralStats mGeneralStats;
@CallType private final int mCallType;

View File

@@ -1 +1 @@
Ibbf4260deb720ce724be81ee4394ea96181ee0f7
I0216abecc41d020f16ed8947a9f37b710afd331e

View File

@@ -16,18 +16,12 @@
package android.app.appsearch;
import static com.google.common.truth.Truth.assertThat;
import android.os.Bundle;
import com.google.common.collect.ImmutableList;
import org.junit.Test;
import java.util.List;
import java.util.Map;
public class SearchSpecTest {
@Test
@@ -63,32 +57,4 @@ public class SearchSpecTest {
assertThat(bundle.getInt(SearchSpec.RANKING_STRATEGY_FIELD))
.isEqualTo(SearchSpec.RANKING_STRATEGY_DOCUMENT_SCORE);
}
@Test
public void testGetProjectionTypePropertyMasks() {
SearchSpec searchSpec =
new SearchSpec.Builder()
.setTermMatch(SearchSpec.TERM_MATCH_PREFIX)
.addProjection("TypeA", ImmutableList.of("field1", "field2.subfield2"))
.addProjection("TypeB", ImmutableList.of("field7"))
.addProjection("TypeC", ImmutableList.of())
.build();
Map<String, List<String>> typePropertyPathMap = searchSpec.getProjections();
assertThat(typePropertyPathMap.keySet()).containsExactly("TypeA", "TypeB", "TypeC");
assertThat(typePropertyPathMap.get("TypeA")).containsExactly("field1", "field2.subfield2");
assertThat(typePropertyPathMap.get("TypeB")).containsExactly("field7");
assertThat(typePropertyPathMap.get("TypeC")).isEmpty();
}
@Test
public void testGetRankingStrategy() {
SearchSpec searchSpec =
new SearchSpec.Builder()
.setTermMatch(SearchSpec.TERM_MATCH_PREFIX)
.setRankingStrategy(SearchSpec.RANKING_STRATEGY_RELEVANCE_SCORE)
.build();
assertThat(searchSpec.getRankingStrategy())
.isEqualTo(SearchSpec.RANKING_STRATEGY_RELEVANCE_SCORE);
}
}

View File

@@ -75,10 +75,14 @@ public class SnippetTest {
.setPropertyName(propertyKeyString)
.addSnippetMatches(
SnippetMatchProto.newBuilder()
.setExactMatchPosition(29)
.setExactMatchBytes(3)
.setWindowPosition(26)
.setWindowBytes(6)))
.setExactMatchBytePosition(29)
.setExactMatchByteLength(3)
.setExactMatchUtf16Position(29)
.setExactMatchUtf16Length(3)
.setWindowBytePosition(26)
.setWindowByteLength(6)
.setWindowUtf16Position(26)
.setWindowUtf16Length(6)))
.build();
SearchResultProto searchResultProto =
SearchResultProto.newBuilder()
@@ -168,19 +172,27 @@ public class SnippetTest {
.setPropertyName("senderName")
.addSnippetMatches(
SnippetMatchProto.newBuilder()
.setExactMatchPosition(0)
.setExactMatchBytes(4)
.setWindowPosition(0)
.setWindowBytes(9)))
.setExactMatchBytePosition(0)
.setExactMatchByteLength(4)
.setExactMatchUtf16Position(0)
.setExactMatchUtf16Length(4)
.setWindowBytePosition(0)
.setWindowByteLength(9)
.setWindowUtf16Position(0)
.setWindowUtf16Length(9)))
.addEntries(
SnippetProto.EntryProto.newBuilder()
.setPropertyName("senderEmail")
.addSnippetMatches(
SnippetMatchProto.newBuilder()
.setExactMatchPosition(0)
.setExactMatchBytes(20)
.setWindowPosition(0)
.setWindowBytes(20)))
.setExactMatchBytePosition(0)
.setExactMatchByteLength(20)
.setExactMatchUtf16Position(0)
.setExactMatchUtf16Length(20)
.setWindowBytePosition(0)
.setWindowByteLength(20)
.setWindowUtf16Position(0)
.setWindowUtf16Length(20)))
.build();
SearchResultProto searchResultProto =
SearchResultProto.newBuilder()
@@ -251,19 +263,27 @@ public class SnippetTest {
.setPropertyName("sender.name")
.addSnippetMatches(
SnippetMatchProto.newBuilder()
.setExactMatchPosition(0)
.setExactMatchBytes(4)
.setWindowPosition(0)
.setWindowBytes(9)))
.setExactMatchBytePosition(0)
.setExactMatchByteLength(4)
.setExactMatchUtf16Position(0)
.setExactMatchUtf16Length(4)
.setWindowBytePosition(0)
.setWindowByteLength(9)
.setWindowUtf16Position(0)
.setWindowUtf16Length(9)))
.addEntries(
SnippetProto.EntryProto.newBuilder()
.setPropertyName("sender.email[1]")
.addSnippetMatches(
SnippetMatchProto.newBuilder()
.setExactMatchPosition(0)
.setExactMatchBytes(21)
.setWindowPosition(0)
.setWindowBytes(21)))
.setExactMatchBytePosition(0)
.setExactMatchByteLength(21)
.setExactMatchUtf16Position(0)
.setExactMatchUtf16Length(21)
.setWindowBytePosition(0)
.setWindowByteLength(21)
.setWindowUtf16Position(0)
.setWindowUtf16Length(21)))
.build();
SearchResultProto searchResultProto =
SearchResultProto.newBuilder()

View File

@@ -89,7 +89,7 @@ public class PlatformLoggerTest {
CallStats.CALL_TYPE_INITIALIZE).mSamplingRatio).isEqualTo(
TEST_DEFAULT_SAMPLING_RATIO);
assertThat(logger.createExtraStatsLocked(TEST_PACKAGE_NAME,
CallStats.CALL_TYPE_QUERY).mSamplingRatio).isEqualTo(
CallStats.CALL_TYPE_SEARCH).mSamplingRatio).isEqualTo(
TEST_DEFAULT_SAMPLING_RATIO);
assertThat(logger.createExtraStatsLocked(TEST_PACKAGE_NAME,
CallStats.CALL_TYPE_FLUSH).mSamplingRatio).isEqualTo(
@@ -103,7 +103,7 @@ public class PlatformLoggerTest {
int querySamplingRatio = 2;
final SparseIntArray samplingRatios = new SparseIntArray();
samplingRatios.put(CallStats.CALL_TYPE_PUT_DOCUMENT, putDocumentSamplingRatio);
samplingRatios.put(CallStats.CALL_TYPE_QUERY, querySamplingRatio);
samplingRatios.put(CallStats.CALL_TYPE_SEARCH, querySamplingRatio);
PlatformLogger logger = new PlatformLogger(
ApplicationProvider.getApplicationContext(),
UserHandle.USER_NULL,
@@ -127,7 +127,7 @@ public class PlatformLoggerTest {
CallStats.CALL_TYPE_PUT_DOCUMENT).mSamplingRatio).isEqualTo(
putDocumentSamplingRatio);
assertThat(logger.createExtraStatsLocked(TEST_PACKAGE_NAME,
CallStats.CALL_TYPE_QUERY).mSamplingRatio).isEqualTo(
CallStats.CALL_TYPE_SEARCH).mSamplingRatio).isEqualTo(
querySamplingRatio);
}