Merge "Sync framework from jetpack." into sc-dev

This commit is contained in:
Alexander Dorokhine
2021-06-24 02:16:24 +00:00
committed by Android (Google) Code Review
6 changed files with 414 additions and 77 deletions

View File

@@ -96,17 +96,6 @@ public final class AppSearchBatchResult<KeyType, ValueType> {
return Collections.unmodifiableMap(mAll);
}
/**
* Asserts that this {@link AppSearchBatchResult} has no failures.
*
* @hide
*/
public void checkSuccess() {
if (!isSuccess()) {
throw new IllegalStateException("AppSearchBatchResult has failures: " + this);
}
}
@Override
@NonNull
public String toString() {

View File

@@ -21,6 +21,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.appsearch.exceptions.IllegalSchemaException;
import android.app.appsearch.util.BundleUtil;
import android.app.appsearch.util.IndentingStringBuilder;
import android.compat.annotation.UnsupportedAppUsage;
import android.os.Bundle;
import android.util.ArraySet;
@@ -30,6 +31,7 @@ import com.android.internal.util.Preconditions;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
@@ -67,8 +69,45 @@ public final class AppSearchSchema {
}
@Override
@NonNull
public String toString() {
return mBundle.toString();
IndentingStringBuilder stringBuilder = new IndentingStringBuilder();
appendAppSearchSchemaString(stringBuilder);
return stringBuilder.toString();
}
/**
* Appends a debugging string for the {@link AppSearchSchema} instance to the given string
* builder.
*
* @param builder the builder to append to.
*/
private void appendAppSearchSchemaString(@NonNull IndentingStringBuilder builder) {
Objects.requireNonNull(builder);
builder.append("{\n");
builder.increaseIndentLevel();
builder.append("schemaType: \"").append(getSchemaType()).append("\",\n");
builder.append("properties: [\n");
AppSearchSchema.PropertyConfig[] sortedProperties =
getProperties().toArray(new AppSearchSchema.PropertyConfig[0]);
Arrays.sort(sortedProperties, (o1, o2) -> o1.getName().compareTo(o2.getName()));
for (int i = 0; i < sortedProperties.length; i++) {
AppSearchSchema.PropertyConfig propertyConfig = sortedProperties[i];
builder.increaseIndentLevel();
propertyConfig.appendPropertyConfigString(builder);
if (i != sortedProperties.length - 1) {
builder.append(",\n");
}
builder.decreaseIndentLevel();
}
builder.append("\n");
builder.append("]\n");
builder.decreaseIndentLevel();
builder.append("}");
}
/** Returns the name of this schema type, e.g. Email. */
@@ -255,7 +294,68 @@ public final class AppSearchSchema {
@Override
@NonNull
public String toString() {
return mBundle.toString();
IndentingStringBuilder stringBuilder = new IndentingStringBuilder();
appendPropertyConfigString(stringBuilder);
return stringBuilder.toString();
}
/**
* Appends a debug string for the {@link AppSearchSchema.PropertyConfig} instance to the
* given string builder.
*
* @param builder the builder to append to.
*/
void appendPropertyConfigString(@NonNull IndentingStringBuilder builder) {
Objects.requireNonNull(builder);
builder.append("{\n");
builder.increaseIndentLevel();
builder.append("name: \"").append(getName()).append("\",\n");
if (this instanceof AppSearchSchema.StringPropertyConfig) {
((StringPropertyConfig) this).appendStringPropertyConfigFields(builder);
} else if (this instanceof AppSearchSchema.DocumentPropertyConfig) {
((DocumentPropertyConfig) this).appendDocumentPropertyConfigFields(builder);
}
switch (getCardinality()) {
case AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED:
builder.append("cardinality: CARDINALITY_REPEATED,\n");
break;
case AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL:
builder.append("cardinality: CARDINALITY_OPTIONAL,\n");
break;
case AppSearchSchema.PropertyConfig.CARDINALITY_REQUIRED:
builder.append("cardinality: CARDINALITY_REQUIRED,\n");
break;
default:
builder.append("cardinality: CARDINALITY_UNKNOWN,\n");
}
switch (getDataType()) {
case AppSearchSchema.PropertyConfig.DATA_TYPE_STRING:
builder.append("dataType: DATA_TYPE_STRING,\n");
break;
case AppSearchSchema.PropertyConfig.DATA_TYPE_LONG:
builder.append("dataType: DATA_TYPE_LONG,\n");
break;
case AppSearchSchema.PropertyConfig.DATA_TYPE_DOUBLE:
builder.append("dataType: DATA_TYPE_DOUBLE,\n");
break;
case AppSearchSchema.PropertyConfig.DATA_TYPE_BOOLEAN:
builder.append("dataType: DATA_TYPE_BOOLEAN,\n");
break;
case AppSearchSchema.PropertyConfig.DATA_TYPE_BYTES:
builder.append("dataType: DATA_TYPE_BYTES,\n");
break;
case AppSearchSchema.PropertyConfig.DATA_TYPE_DOCUMENT:
builder.append("dataType: DATA_TYPE_DOCUMENT,\n");
break;
default:
builder.append("dataType: DATA_TYPE_UNKNOWN,\n");
}
builder.decreaseIndentLevel();
builder.append("}");
}
/** Returns the name of this property. */
@@ -506,6 +606,41 @@ public final class AppSearchSchema {
return new StringPropertyConfig(bundle);
}
}
/**
* Appends a debug string for the {@link StringPropertyConfig} instance to the given string
* builder.
*
* <p>This appends fields specific to a {@link StringPropertyConfig} instance.
*
* @param builder the builder to append to.
*/
void appendStringPropertyConfigFields(@NonNull IndentingStringBuilder builder) {
switch (getIndexingType()) {
case AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_NONE:
builder.append("indexingType: INDEXING_TYPE_NONE,\n");
break;
case AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_EXACT_TERMS:
builder.append("indexingType: INDEXING_TYPE_EXACT_TERMS,\n");
break;
case AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_PREFIXES:
builder.append("indexingType: INDEXING_TYPE_PREFIXES,\n");
break;
default:
builder.append("indexingType: INDEXING_TYPE_UNKNOWN,\n");
}
switch (getTokenizerType()) {
case AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_NONE:
builder.append("tokenizerType: TOKENIZER_TYPE_NONE,\n");
break;
case AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_PLAIN:
builder.append("tokenizerType: TOKENIZER_TYPE_PLAIN,\n");
break;
default:
builder.append("tokenizerType: TOKENIZER_TYPE_UNKNOWN,\n");
}
}
}
/**
@@ -858,5 +993,21 @@ public final class AppSearchSchema {
return new DocumentPropertyConfig(bundle);
}
}
/**
* Appends a debug string for the {@link DocumentPropertyConfig} instance to the given
* string builder.
*
* <p>This appends fields specific to a {@link DocumentPropertyConfig} instance.
*
* @param builder the builder to append to.
*/
void appendDocumentPropertyConfigFields(@NonNull IndentingStringBuilder builder) {
builder.append("shouldIndexNestedProperties: ")
.append(shouldIndexNestedProperties())
.append(",\n");
builder.append("schemaType: \"").append(getSchemaType()).append("\",\n");
}
}
}

View File

@@ -22,6 +22,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SuppressLint;
import android.app.appsearch.util.BundleUtil;
import android.app.appsearch.util.IndentingStringBuilder;
import android.compat.annotation.UnsupportedAppUsage;
import android.os.Bundle;
import android.os.Parcelable;
@@ -858,6 +859,7 @@ public class GenericDocument {
*
* @hide
*/
// TODO(b/171882200): Expose this API in Android T
@NonNull
public GenericDocument.Builder<GenericDocument.Builder<?>> toBuilder() {
Bundle clonedBundle = BundleUtil.deepCopy(mBundle);
@@ -887,121 +889,101 @@ public class GenericDocument {
@Override
@NonNull
public String toString() {
StringBuilder stringBuilder = new StringBuilder();
appendGenericDocumentString(this, /*indentLevel=*/ 0, stringBuilder);
IndentingStringBuilder stringBuilder = new IndentingStringBuilder();
appendGenericDocumentString(stringBuilder);
return stringBuilder.toString();
}
private static void appendGenericDocumentString(
@NonNull GenericDocument document, int indentLevel, @NonNull StringBuilder builder) {
Objects.requireNonNull(document);
/**
* Appends a debug string for the {@link GenericDocument} instance to the given string builder.
*
* @param builder the builder to append to.
*/
void appendGenericDocumentString(@NonNull IndentingStringBuilder builder) {
Objects.requireNonNull(builder);
builder.append(getIndent(indentLevel)).append("{\n");
builder.append("{\n");
builder.increaseIndentLevel();
String indent1 = getIndent(indentLevel + 1);
builder.append(indent1)
.append("namespace: \"")
.append(document.getNamespace())
.append("\",\n");
builder.append(indent1).append("id: \"").append(document.getId()).append("\",\n");
builder.append(indent1).append("score: ").append(document.getScore()).append(",\n");
builder.append(indent1)
.append("schemaType: \"")
.append(document.getSchemaType())
.append("\",\n");
builder.append(indent1)
.append("creationTimestampMillis: ")
.append(document.getCreationTimestampMillis())
builder.append("namespace: \"").append(getNamespace()).append("\",\n");
builder.append("id: \"").append(getId()).append("\",\n");
builder.append("score: ").append(getScore()).append(",\n");
builder.append("schemaType: \"").append(getSchemaType()).append("\",\n");
builder.append("creationTimestampMillis: ")
.append(getCreationTimestampMillis())
.append(",\n");
builder.append("timeToLiveMillis: ").append(getTtlMillis()).append(",\n");
builder.append(indent1)
.append("timeToLiveMillis: ")
.append(document.getTtlMillis())
.append(",\n");
builder.append("properties: {\n");
builder.append(indent1).append("properties: {\n");
String[] sortedProperties = document.getPropertyNames().toArray(new String[0]);
String[] sortedProperties = 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(sortedProperties[i])
.append("\"")
.append(": ");
appendPropertyString(property, indentLevel + 2, builder);
Object property = getProperty(sortedProperties[i]);
builder.increaseIndentLevel();
appendPropertyString(sortedProperties[i], property, builder);
if (i != sortedProperties.length - 1) {
builder.append(",\n");
}
builder.decreaseIndentLevel();
}
builder.append("\n");
builder.append(indent1).append("}");
builder.append("}");
builder.decreaseIndentLevel();
builder.append("\n");
builder.append(getIndent(indentLevel)).append("}");
builder.append("}");
}
/**
* Appends a string for the given property to the given builder.
* Appends a debug string for the given document property to the given string builder.
*
* @param propertyName name of property to create string for.
* @param property property object to create string for.
* @param indentLevel base indent level for property.
* @param builder the builder to append to.
*/
private static void appendPropertyString(
@NonNull Object property, int indentLevel, @NonNull StringBuilder builder) {
private void appendPropertyString(
@NonNull String propertyName,
@NonNull Object property,
@NonNull IndentingStringBuilder builder) {
Objects.requireNonNull(propertyName);
Objects.requireNonNull(property);
Objects.requireNonNull(builder);
builder.append("[");
builder.append("\"").append(propertyName).append("\": [");
if (property instanceof GenericDocument[]) {
GenericDocument[] documentValues = (GenericDocument[]) property;
for (int i = 0; i < documentValues.length; ++i) {
builder.append("\n");
appendGenericDocumentString(documentValues[i], indentLevel + 1, builder);
builder.increaseIndentLevel();
documentValues[i].appendGenericDocumentString(builder);
if (i != documentValues.length - 1) {
builder.append(", ");
builder.append(",");
}
builder.append("\n");
builder.decreaseIndentLevel();
}
builder.append(getIndent(indentLevel));
builder.append("]");
} else {
int propertyArrLength = Array.getLength(property);
for (int i = 0; i < propertyArrLength; i++) {
Object propertyElement = Array.get(property, i);
if (propertyElement instanceof String) {
builder.append("\"").append(propertyElement).append("\"");
builder.append("\"").append((String) propertyElement).append("\"");
} else if (propertyElement instanceof byte[]) {
builder.append(Arrays.toString((byte[]) propertyElement));
} else {
builder.append(propertyElement);
builder.append(propertyElement.toString());
}
if (i != propertyArrLength - 1) {
builder.append(", ");
} else {
builder.append("]");
}
}
}
builder.append("]");
}
/** Appends a string for given indent level to the given builder. */
@NonNull
private static String getIndent(int indentLevel) {
StringBuilder builder = new StringBuilder();
for (int i = 0; i < indentLevel; ++i) {
builder.append(" ");
}
return builder.toString();
}
/**

View File

@@ -0,0 +1,126 @@
/*
* Copyright 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.app.appsearch.util;
import android.annotation.NonNull;
/**
* Utility for building indented strings.
*
* <p>This is a wrapper for {@link StringBuilder} for appending strings with indentation. The
* indentation level can be increased by calling {@link #increaseIndentLevel()} and decreased by
* calling {@link #decreaseIndentLevel()}.
*
* <p>Indentation is applied after each newline character for the given indent level.
*
* @hide
*/
public class IndentingStringBuilder {
private final StringBuilder mStringBuilder = new StringBuilder();
// Indicates whether next non-newline character should have an indent applied before it.
private boolean mIndentNext = false;
private int mIndentLevel = 0;
/** Increases the indent level by one for appended strings. */
@NonNull
public IndentingStringBuilder increaseIndentLevel() {
mIndentLevel++;
return this;
}
/** Decreases the indent level by one for appended strings. */
@NonNull
public IndentingStringBuilder decreaseIndentLevel() throws IllegalStateException {
if (mIndentLevel == 0) {
throw new IllegalStateException("Cannot set indent level below 0.");
}
mIndentLevel--;
return this;
}
/**
* Appends provided {@code String} at the current indentation level.
*
* <p>Indentation is applied after each newline character.
*/
@NonNull
public IndentingStringBuilder append(@NonNull String str) {
applyIndentToString(str);
return this;
}
/**
* Appends provided {@code Object}, represented as a {@code String}, at the current indentation
* level.
*
* <p>Indentation is applied after each newline character.
*/
@NonNull
public IndentingStringBuilder append(@NonNull Object obj) {
applyIndentToString(obj.toString());
return this;
}
@Override
@NonNull
public String toString() {
return mStringBuilder.toString();
}
/** Adds indent string to the {@link StringBuilder} instance for current indent level. */
private void applyIndent() {
for (int i = 0; i < mIndentLevel; i++) {
mStringBuilder.append(" ");
}
}
/**
* Applies indent, for current indent level, after each newline character.
*
* <p>Consecutive newline characters are not indented.
*/
private void applyIndentToString(@NonNull String str) {
int index = str.indexOf("\n");
if (index == 0) {
// String begins with new line character: append newline and slide past newline.
mStringBuilder.append("\n");
mIndentNext = true;
if (str.length() > 1) {
applyIndentToString(str.substring(index + 1));
}
} else if (index >= 1) {
// String contains new line character: divide string between newline, append new line,
// and recurse on each string.
String beforeIndentString = str.substring(0, index);
applyIndentToString(beforeIndentString);
mStringBuilder.append("\n");
mIndentNext = true;
if (str.length() > index + 1) {
String afterIndentString = str.substring(index + 1);
applyIndentToString(afterIndentString);
}
} else {
// String does not contain newline character: append string.
if (mIndentNext) {
applyIndent();
mIndentNext = false;
}
mStringBuilder.append(str);
}
}
}

View File

@@ -1 +1 @@
a11281766f66aa4919e9bbe70da95919ce054c35
c7387d9b58726a23a0608a9365fb3a1b57b7b8a1

View File

@@ -0,0 +1,89 @@
/*
* Copyright 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.app.appsearch.util;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertThrows;
import org.junit.Test;
public class IndentingStringBuilderTest {
@Test
public void testAppendIndentedStrings() {
IndentingStringBuilder stringBuilder = new IndentingStringBuilder();
stringBuilder
.increaseIndentLevel()
.append("\nIndentLevel1\nIndentLevel1\n")
.decreaseIndentLevel()
.append("IndentLevel0,\n");
String str = stringBuilder.toString();
String expectedString = "\n IndentLevel1\n IndentLevel1\nIndentLevel0,\n";
assertThat(str).isEqualTo(expectedString);
}
@Test
public void testDecreaseIndentLevel_throwsException() {
IndentingStringBuilder stringBuilder = new IndentingStringBuilder();
Exception e =
assertThrows(
IllegalStateException.class, () -> stringBuilder.decreaseIndentLevel());
assertThat(e).hasMessageThat().contains("Cannot set indent level below 0.");
}
@Test
public void testAppendIndentedObjects() {
IndentingStringBuilder stringBuilder = new IndentingStringBuilder();
Object stringProperty = "String";
Object longProperty = 1L;
Object booleanProperty = true;
stringBuilder
.append(stringProperty)
.append("\n")
.increaseIndentLevel()
.append(longProperty)
.append("\n")
.decreaseIndentLevel()
.append(booleanProperty);
String str = stringBuilder.toString();
String expectedString = "String\n 1\ntrue";
assertThat(str).isEqualTo(expectedString);
}
@Test
public void testAppendIndentedStrings_doesNotIndentLineBreak() {
IndentingStringBuilder stringBuilder = new IndentingStringBuilder();
stringBuilder
.append("\n")
.increaseIndentLevel()
.append("\n\n")
.decreaseIndentLevel()
.append("\n");
String str = stringBuilder.toString();
String expectedString = "\n\n\n\n";
assertThat(str).isEqualTo(expectedString);
}
}