Merge "Bug fix: allow to create ViewTranslationRequest for virtual AutofillId." into sc-dev

This commit is contained in:
Joanne Chung
2021-03-31 03:41:39 +00:00
committed by Android (Google) Code Review
6 changed files with 104 additions and 86 deletions

View File

@@ -52923,8 +52923,9 @@ package android.view.translation {
public static final class ViewTranslationRequest.Builder { public static final class ViewTranslationRequest.Builder {
ctor public ViewTranslationRequest.Builder(@NonNull android.view.autofill.AutofillId); ctor public ViewTranslationRequest.Builder(@NonNull android.view.autofill.AutofillId);
ctor public ViewTranslationRequest.Builder(@NonNull android.view.autofill.AutofillId, long);
method @NonNull public android.view.translation.ViewTranslationRequest build(); method @NonNull public android.view.translation.ViewTranslationRequest build();
method public android.view.translation.ViewTranslationRequest.Builder setValue(String, android.view.translation.TranslationRequestValue); method @NonNull public android.view.translation.ViewTranslationRequest.Builder setValue(@NonNull String, @NonNull android.view.translation.TranslationRequestValue);
} }
public final class ViewTranslationResponse implements android.os.Parcelable { public final class ViewTranslationResponse implements android.os.Parcelable {

View File

@@ -14752,7 +14752,7 @@ package android.webkit {
method public default boolean onCheckIsTextEditor(); method public default boolean onCheckIsTextEditor();
method public void onConfigurationChanged(android.content.res.Configuration); method public void onConfigurationChanged(android.content.res.Configuration);
method public android.view.inputmethod.InputConnection onCreateInputConnection(android.view.inputmethod.EditorInfo); method public android.view.inputmethod.InputConnection onCreateInputConnection(android.view.inputmethod.EditorInfo);
method @Nullable public default void onCreateTranslationRequests(@NonNull long[], @NonNull int[], @NonNull java.util.function.Consumer<android.view.translation.ViewTranslationRequest>); method public default void onCreateTranslationRequests(@NonNull long[], @NonNull int[], @NonNull java.util.function.Consumer<android.view.translation.ViewTranslationRequest>);
method public void onDetachedFromWindow(); method public void onDetachedFromWindow();
method public boolean onDragEvent(android.view.DragEvent); method public boolean onDragEvent(android.view.DragEvent);
method public void onDraw(android.graphics.Canvas); method public void onDraw(android.graphics.Canvas);

View File

@@ -30759,10 +30759,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* view. * view.
* @param supportedFormats the supported translation formats. For now, the only possible value * @param supportedFormats the supported translation formats. For now, the only possible value
* is the {@link android.view.translation.TranslationSpec#DATA_FORMAT_TEXT}. * is the {@link android.view.translation.TranslationSpec#DATA_FORMAT_TEXT}.
* @param requestsCollector a {@link ViewTranslationRequest} collector that will be called * @param requestsCollector a {@link ViewTranslationRequest} collector that can be called
* multiple times to collect the information to be translated in the virtual view. One * multiple times to collect the information to be translated in the virtual view. One
* {@link ViewTranslationRequest} per virtual child. The {@link ViewTranslationRequest} must * {@link ViewTranslationRequest} per virtual child. The {@link ViewTranslationRequest} must
* contains the {@link AutofillId} corresponding to the virtualChildIds. * contains the {@link AutofillId} corresponding to the virtualChildIds. Do not keep this
* Consumer after the method returns.
*/ */
@SuppressLint("NullableCollection") @SuppressLint("NullableCollection")
public void onCreateTranslationRequests(@NonNull long[] virtualChildIds, public void onCreateTranslationRequests(@NonNull long[] virtualChildIds,
@@ -30835,7 +30836,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* ui translation, the system will call this method to traverse the view hierarchy to call * ui translation, the system will call this method to traverse the view hierarchy to call
* {@link View#onCreateTranslationRequest} to build {@link ViewTranslationRequest}s and create a * {@link View#onCreateTranslationRequest} to build {@link ViewTranslationRequest}s and create a
* {@link android.view.translation.Translator} to translate the requests. All the * {@link android.view.translation.Translator} to translate the requests. All the
* {@link ViewTranslationRequest}s will be added when the traversal is done. * {@link ViewTranslationRequest}s must be added when the traversal is done.
* *
* <p> The default implementation will call {@link View#onCreateTranslationRequest} to build * <p> The default implementation will call {@link View#onCreateTranslationRequest} to build
* {@link ViewTranslationRequest} if the view should be translated. </p> * {@link ViewTranslationRequest} if the view should be translated. </p>

View File

@@ -30,6 +30,7 @@ import android.os.Handler;
import android.os.HandlerThread; import android.os.HandlerThread;
import android.os.Process; import android.os.Process;
import android.util.ArrayMap; import android.util.ArrayMap;
import android.util.IntArray;
import android.util.Log; import android.util.Log;
import android.util.LongSparseArray; import android.util.LongSparseArray;
import android.util.Pair; import android.util.Pair;
@@ -241,13 +242,11 @@ public class UiTranslationController {
final SparseArray<ViewTranslationResponse> viewsResult = new SparseArray<>(); final SparseArray<ViewTranslationResponse> viewsResult = new SparseArray<>();
final SparseArray<LongSparseArray<ViewTranslationResponse>> virtualViewsResult = final SparseArray<LongSparseArray<ViewTranslationResponse>> virtualViewsResult =
new SparseArray<>(); new SparseArray<>();
// TODO: use another structure to prevent autoboxing? final IntArray viewIds = new IntArray(1);
final List<Integer> viewIds = new ArrayList<>();
for (int i = 0; i < translatedResult.size(); i++) { for (int i = 0; i < translatedResult.size(); i++) {
final ViewTranslationResponse result = translatedResult.valueAt(i); final ViewTranslationResponse result = translatedResult.valueAt(i);
final AutofillId autofillId = result.getAutofillId(); final AutofillId autofillId = result.getAutofillId();
if (!viewIds.contains(autofillId.getViewId())) { if (viewIds.indexOf(autofillId.getViewId()) < 0) {
viewIds.add(autofillId.getViewId()); viewIds.add(autofillId.getViewId());
} }
if (autofillId.isNonVirtual()) { if (autofillId.isNonVirtual()) {
@@ -405,23 +404,29 @@ public class UiTranslationController {
// Filter the request views's AutofillId // Filter the request views's AutofillId
SparseIntArray virtualViewChildCount = getRequestVirtualViewChildCount(views); SparseIntArray virtualViewChildCount = getRequestVirtualViewChildCount(views);
Map<AutofillId, long[]> viewIds = new ArrayMap<>(); Map<AutofillId, long[]> viewIds = new ArrayMap<>();
Map<AutofillId, Integer> unusedIndices = null;
for (int i = 0; i < views.size(); i++) { for (int i = 0; i < views.size(); i++) {
AutofillId autofillId = views.get(i); AutofillId autofillId = views.get(i);
if (autofillId.isNonVirtual()) { if (autofillId.isNonVirtual()) {
viewIds.put(autofillId, null); viewIds.put(autofillId, null);
} else { } else {
if (unusedIndices == null) {
unusedIndices = new ArrayMap<>();
}
// The virtual id get from content capture is long, see getVirtualChildLongId() // The virtual id get from content capture is long, see getVirtualChildLongId()
// e.g. 1001, 1001:2, 1002:1 -> 1001, <1,2>; 1002, <1> // e.g. 1001, 1001:2, 1002:1 -> 1001, <1,2>; 1002, <1>
AutofillId virtualViewAutofillId = new AutofillId(autofillId.getViewId()); AutofillId virtualViewAutofillId = new AutofillId(autofillId.getViewId());
long[] childs; long[] childs;
int end = 0;
if (viewIds.containsKey(virtualViewAutofillId)) { if (viewIds.containsKey(virtualViewAutofillId)) {
childs = viewIds.get(virtualViewAutofillId); childs = viewIds.get(virtualViewAutofillId);
end = unusedIndices.get(virtualViewAutofillId);
} else { } else {
int childCount = virtualViewChildCount.get(autofillId.getViewId()); int childCount = virtualViewChildCount.get(autofillId.getViewId());
childs = new long[childCount]; childs = new long[childCount];
viewIds.put(virtualViewAutofillId, childs); viewIds.put(virtualViewAutofillId, childs);
} }
int end = childs.length - 1; unusedIndices.put(virtualViewAutofillId, end + 1);
childs[end] = autofillId.getVirtualChildLongId(); childs[end] = autofillId.getVirtualChildLongId();
} }
} }
@@ -465,7 +470,7 @@ public class UiTranslationController {
return new int[] {TranslationSpec.DATA_FORMAT_TEXT}; return new int[] {TranslationSpec.DATA_FORMAT_TEXT};
} }
private void findViewsTraversalByAutofillIds(List<Integer> sourceViewIds) { private void findViewsTraversalByAutofillIds(IntArray sourceViewIds) {
final ArrayList<ViewRootImpl> roots = final ArrayList<ViewRootImpl> roots =
WindowManagerGlobal.getInstance().getRootViews(mActivity.getActivityToken()); WindowManagerGlobal.getInstance().getRootViews(mActivity.getActivityToken());
for (int rootNum = 0; rootNum < roots.size(); rootNum++) { for (int rootNum = 0; rootNum < roots.size(); rootNum++) {
@@ -479,7 +484,7 @@ public class UiTranslationController {
} }
private void findViewsTraversalByAutofillIds(ViewGroup viewGroup, private void findViewsTraversalByAutofillIds(ViewGroup viewGroup,
List<Integer> sourceViewIds) { IntArray sourceViewIds) {
final int childCount = viewGroup.getChildCount(); final int childCount = viewGroup.getChildCount();
for (int i = 0; i < childCount; ++i) { for (int i = 0; i < childCount; ++i) {
final View child = viewGroup.getChildAt(i); final View child = viewGroup.getChildAt(i);
@@ -491,9 +496,10 @@ public class UiTranslationController {
} }
} }
private void addViewIfNeeded(List<Integer> sourceViewIds, View view) { private void addViewIfNeeded(IntArray sourceViewIds, View view) {
final AutofillId autofillId = view.getAutofillId(); final AutofillId autofillId = view.getAutofillId();
if (sourceViewIds.contains(autofillId.getViewId()) && !mViews.containsKey(autofillId)) { if ((sourceViewIds.indexOf(autofillId.getViewId()) >= 0)
&& !mViews.containsKey(autofillId)) {
mViews.put(autofillId, new WeakReference<>(view)); mViews.put(autofillId, new WeakReference<>(view));
} }
} }

View File

@@ -35,7 +35,8 @@ import java.util.Set;
* Wrapper class representing a translation request associated with a {@link android.view.View} to * Wrapper class representing a translation request associated with a {@link android.view.View} to
* be used by {@link android.service.translation.TranslationService}. * be used by {@link android.service.translation.TranslationService}.
*/ */
@DataClass(genBuilder = true, genToString = true, genEqualsHashCode = true, genGetters = false) @DataClass(genBuilder = false, genToString = true, genEqualsHashCode = true, genGetters = false,
genHiddenConstructor = true)
public final class ViewTranslationRequest implements Parcelable { public final class ViewTranslationRequest implements Parcelable {
/** /**
@@ -91,10 +92,39 @@ public final class ViewTranslationRequest implements Parcelable {
return Collections.emptyMap(); return Collections.emptyMap();
} }
@DataClass.Suppress({"addTranslationRequestValue", "setAutofillId"}) /**
abstract static class BaseBuilder { * A builder for building ViewTranslationRequest.
*/
public static final class Builder {
abstract Builder setTranslationRequestValues(Map<String, TranslationRequestValue> value); private @NonNull AutofillId mAutofillId;
private @NonNull Map<String, TranslationRequestValue> mTranslationRequestValues;
private long mBuilderFieldsSet = 0L;
/**
* Creates a new Builder.
*
* @param autofillId The {@link AutofillId} of the view associated with this request.
*/
public Builder(@NonNull AutofillId autofillId) {
mAutofillId = autofillId;
com.android.internal.util.AnnotationValidations.validate(
NonNull.class, null, mAutofillId);
}
/**
* Creates a new Builder.
*
* @param autofillId the {@link AutofillId} of the non-virtual view hosting the virtual view
* hierarchy associated with this request.
* @param virtualChildId the id of the virtual child, relative to the parent.
*/
public Builder(@NonNull AutofillId autofillId, long virtualChildId) {
mAutofillId = new AutofillId(autofillId, virtualChildId, AutofillId.NO_SESSION);
com.android.internal.util.AnnotationValidations.validate(
NonNull.class, null, mAutofillId);
}
/** /**
* Sets the corresponding {@link TranslationRequestValue} for the provided key. * Sets the corresponding {@link TranslationRequestValue} for the provided key.
@@ -104,20 +134,50 @@ public final class ViewTranslationRequest implements Parcelable {
* @return this builder. * @return this builder.
*/ */
@SuppressLint("MissingGetterMatchingBuilder") @SuppressLint("MissingGetterMatchingBuilder")
public Builder setValue(String key, @NonNull
TranslationRequestValue value) { public Builder setValue(@NonNull String key, @NonNull TranslationRequestValue value) {
final Builder builder = (Builder) this; if (mTranslationRequestValues == null) {
if (builder.mTranslationRequestValues == null) {
setTranslationRequestValues(new ArrayMap<>()); setTranslationRequestValues(new ArrayMap<>());
} }
builder.mTranslationRequestValues.put(key, value); mTranslationRequestValues.put(key, value);
return builder; return this;
}
/**
* Builds the instance. This builder should not be touched after calling this!
*/
@NonNull
public ViewTranslationRequest build() {
checkNotUsed();
mBuilderFieldsSet |= 0x4; // Mark builder used
if ((mBuilderFieldsSet & 0x2) == 0) {
mTranslationRequestValues = defaultTranslationRequestValues();
}
ViewTranslationRequest o = new ViewTranslationRequest(
mAutofillId,
mTranslationRequestValues);
return o;
}
Builder setTranslationRequestValues(@NonNull Map<String, TranslationRequestValue> value) {
checkNotUsed();
mBuilderFieldsSet |= 0x2;
mTranslationRequestValues = value;
return this;
}
private void checkNotUsed() {
if ((mBuilderFieldsSet & 0x4) != 0) {
throw new IllegalStateException(
"This Builder should not be reused. Use a new Builder instance instead");
}
} }
} }
// Code below generated by codegen v1.0.22. // Code below generated by codegen v1.0.23.
// //
// DO NOT MODIFY! // DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code // CHECKSTYLE:OFF Generated code
@@ -130,8 +190,15 @@ public final class ViewTranslationRequest implements Parcelable {
//@formatter:off //@formatter:off
/**
* Creates a new ViewTranslationRequest.
*
* @param autofillId
* The {@link AutofillId} of the view associated with this request.
* @hide
*/
@DataClass.Generated.Member @DataClass.Generated.Member
/* package-private */ ViewTranslationRequest( public ViewTranslationRequest(
@NonNull AutofillId autofillId, @NonNull AutofillId autofillId,
@NonNull Map<String,TranslationRequestValue> translationRequestValues) { @NonNull Map<String,TranslationRequestValue> translationRequestValues) {
this.mAutofillId = autofillId; this.mAutofillId = autofillId;
@@ -234,67 +301,11 @@ public final class ViewTranslationRequest implements Parcelable {
} }
}; };
/**
* A builder for {@link ViewTranslationRequest}
*/
@SuppressWarnings("WeakerAccess")
@DataClass.Generated.Member
public static final class Builder extends BaseBuilder {
private @NonNull AutofillId mAutofillId;
private @NonNull Map<String,TranslationRequestValue> mTranslationRequestValues;
private long mBuilderFieldsSet = 0L;
/**
* Creates a new Builder.
*
* @param autofillId
* The {@link AutofillId} of the view associated with this request.
*/
public Builder(
@NonNull AutofillId autofillId) {
mAutofillId = autofillId;
com.android.internal.util.AnnotationValidations.validate(
NonNull.class, null, mAutofillId);
}
@DataClass.Generated.Member
@Override
@NonNull Builder setTranslationRequestValues(@NonNull Map<String,TranslationRequestValue> value) {
checkNotUsed();
mBuilderFieldsSet |= 0x2;
mTranslationRequestValues = value;
return this;
}
/** Builds the instance. This builder should not be touched after calling this! */
public @NonNull ViewTranslationRequest build() {
checkNotUsed();
mBuilderFieldsSet |= 0x4; // Mark builder used
if ((mBuilderFieldsSet & 0x2) == 0) {
mTranslationRequestValues = defaultTranslationRequestValues();
}
ViewTranslationRequest o = new ViewTranslationRequest(
mAutofillId,
mTranslationRequestValues);
return o;
}
private void checkNotUsed() {
if ((mBuilderFieldsSet & 0x4) != 0) {
throw new IllegalStateException(
"This Builder should not be reused. Use a new Builder instance instead");
}
}
}
@DataClass.Generated( @DataClass.Generated(
time = 1614992269658L, time = 1617119791798L,
codegenVersion = "1.0.22", codegenVersion = "1.0.23",
sourceFile = "frameworks/base/core/java/android/view/translation/ViewTranslationRequest.java", sourceFile = "frameworks/base/core/java/android/view/translation/ViewTranslationRequest.java",
inputSignatures = "public static final java.lang.String ID_TEXT\nprivate final @android.annotation.NonNull android.view.autofill.AutofillId mAutofillId\nprivate final @android.annotation.NonNull @com.android.internal.util.DataClass.PluralOf(\"translationRequestValue\") java.util.Map<java.lang.String,android.view.translation.TranslationRequestValue> mTranslationRequestValues\npublic @android.annotation.NonNull android.view.translation.TranslationRequestValue getValue(java.lang.String)\npublic @android.annotation.NonNull java.util.Set<java.lang.String> getKeys()\npublic @android.annotation.NonNull android.view.autofill.AutofillId getAutofillId()\nprivate static java.util.Map<java.lang.String,android.view.translation.TranslationRequestValue> defaultTranslationRequestValues()\nclass ViewTranslationRequest extends java.lang.Object implements [android.os.Parcelable]\nabstract android.view.translation.ViewTranslationRequest.Builder setTranslationRequestValues(java.util.Map<java.lang.String,android.view.translation.TranslationRequestValue>)\npublic @android.annotation.SuppressLint android.view.translation.ViewTranslationRequest.Builder setValue(java.lang.String,android.view.translation.TranslationRequestValue)\nclass BaseBuilder extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genBuilder=true, genToString=true, genEqualsHashCode=true, genGetters=false)\nabstract android.view.translation.ViewTranslationRequest.Builder setTranslationRequestValues(java.util.Map<java.lang.String,android.view.translation.TranslationRequestValue>)\npublic @android.annotation.SuppressLint android.view.translation.ViewTranslationRequest.Builder setValue(java.lang.String,android.view.translation.TranslationRequestValue)\nclass BaseBuilder extends java.lang.Object implements []") inputSignatures = "public static final java.lang.String ID_TEXT\nprivate final @android.annotation.NonNull android.view.autofill.AutofillId mAutofillId\nprivate final @android.annotation.NonNull @com.android.internal.util.DataClass.PluralOf(\"translationRequestValue\") java.util.Map<java.lang.String,android.view.translation.TranslationRequestValue> mTranslationRequestValues\npublic @android.annotation.NonNull android.view.translation.TranslationRequestValue getValue(java.lang.String)\npublic @android.annotation.NonNull java.util.Set<java.lang.String> getKeys()\npublic @android.annotation.NonNull android.view.autofill.AutofillId getAutofillId()\nprivate static java.util.Map<java.lang.String,android.view.translation.TranslationRequestValue> defaultTranslationRequestValues()\nclass ViewTranslationRequest extends java.lang.Object implements [android.os.Parcelable]\nprivate @android.annotation.NonNull android.view.autofill.AutofillId mAutofillId\nprivate @android.annotation.NonNull java.util.Map<java.lang.String,android.view.translation.TranslationRequestValue> mTranslationRequestValues\nprivate long mBuilderFieldsSet\npublic @android.annotation.SuppressLint @android.annotation.NonNull android.view.translation.ViewTranslationRequest.Builder setValue(java.lang.String,android.view.translation.TranslationRequestValue)\npublic @android.annotation.NonNull android.view.translation.ViewTranslationRequest build()\n android.view.translation.ViewTranslationRequest.Builder setTranslationRequestValues(java.util.Map<java.lang.String,android.view.translation.TranslationRequestValue>)\nprivate void checkNotUsed()\nclass Builder extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genBuilder=false, genToString=true, genEqualsHashCode=true, genGetters=false, genHiddenConstructor=true)")
@Deprecated @Deprecated
private void __metadata() {} private void __metadata() {}

View File

@@ -365,7 +365,6 @@ public interface WebViewProvider {
} }
@SuppressLint("NullableCollection") @SuppressLint("NullableCollection")
@Nullable
default void onCreateTranslationRequests( default void onCreateTranslationRequests(
@NonNull @SuppressWarnings("unused") long[] virtualChildIds, @NonNull @SuppressWarnings("unused") long[] virtualChildIds,
@NonNull @SuppressWarnings("unused") @DataFormat int[] supportedFormats, @NonNull @SuppressWarnings("unused") @DataFormat int[] supportedFormats,