Merge "Implement dispatchRequestTranslation for getting translation information." into sc-dev
This commit is contained in:
@@ -48449,7 +48449,6 @@ package android.view {
|
||||
method protected int computeVerticalScrollRange();
|
||||
method public android.view.accessibility.AccessibilityNodeInfo createAccessibilityNodeInfo();
|
||||
method public void createContextMenu(android.view.ContextMenu);
|
||||
method @Nullable public android.view.translation.ViewTranslationRequest createTranslationRequest(@NonNull int[]);
|
||||
method @Deprecated public void destroyDrawingCache();
|
||||
method public android.view.WindowInsets dispatchApplyWindowInsets(android.view.WindowInsets);
|
||||
method public boolean dispatchCapturedPointerEvent(android.view.MotionEvent);
|
||||
@@ -48475,6 +48474,7 @@ package android.view {
|
||||
method public boolean dispatchPopulateAccessibilityEvent(android.view.accessibility.AccessibilityEvent);
|
||||
method public void dispatchProvideAutofillStructure(@NonNull android.view.ViewStructure, int);
|
||||
method public void dispatchProvideStructure(android.view.ViewStructure);
|
||||
method public void dispatchRequestTranslation(@NonNull java.util.Map<android.view.autofill.AutofillId,long[]>, @NonNull int[], @Nullable android.view.translation.TranslationCapability, @NonNull java.util.List<android.view.translation.ViewTranslationRequest>);
|
||||
method protected void dispatchRestoreInstanceState(android.util.SparseArray<android.os.Parcelable>);
|
||||
method protected void dispatchSaveInstanceState(android.util.SparseArray<android.os.Parcelable>);
|
||||
method public void dispatchScrollCaptureSearch(@NonNull android.graphics.Rect, @NonNull android.graphics.Point, @NonNull java.util.function.Consumer<android.view.ScrollCaptureTarget>);
|
||||
@@ -48770,6 +48770,7 @@ package android.view {
|
||||
method protected void onCreateContextMenu(android.view.ContextMenu);
|
||||
method protected int[] onCreateDrawableState(int);
|
||||
method public android.view.inputmethod.InputConnection onCreateInputConnection(android.view.inputmethod.EditorInfo);
|
||||
method @Nullable public android.view.translation.ViewTranslationRequest onCreateTranslationRequest(@NonNull int[]);
|
||||
method @CallSuper protected void onDetachedFromWindow();
|
||||
method protected void onDisplayHint(int);
|
||||
method public boolean onDragEvent(android.view.DragEvent);
|
||||
|
||||
@@ -151,6 +151,7 @@ import android.view.inputmethod.InputConnection;
|
||||
import android.view.inspector.InspectableProperty;
|
||||
import android.view.inspector.InspectableProperty.EnumEntry;
|
||||
import android.view.inspector.InspectableProperty.FlagEntry;
|
||||
import android.view.translation.TranslationCapability;
|
||||
import android.view.translation.TranslationSpec.DataFormat;
|
||||
import android.view.translation.ViewTranslationCallback;
|
||||
import android.view.translation.ViewTranslationRequest;
|
||||
@@ -30722,7 +30723,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
|
||||
}
|
||||
}
|
||||
|
||||
//TODO(b/1960696): update javadoc when dispatchRequestTranslation is ready.
|
||||
/**
|
||||
* Returns a {@link ViewTranslationRequest} which represents the content to be translated.
|
||||
*
|
||||
@@ -30735,7 +30735,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
|
||||
* The {@link AutofillId} must be set on the returned value.
|
||||
*/
|
||||
@Nullable
|
||||
public ViewTranslationRequest createTranslationRequest(
|
||||
public ViewTranslationRequest onCreateTranslationRequest(
|
||||
@NonNull @DataFormat int[] supportedFormats) {
|
||||
return null;
|
||||
}
|
||||
@@ -30769,8 +30769,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the content from {@link #createTranslationRequest} had been translated by the
|
||||
* TranslationService.
|
||||
* Called when the content from {@link View#onCreateTranslationRequest} had been translated by
|
||||
* the TranslationService.
|
||||
*
|
||||
* <p> The default implementation does nothing.</p>
|
||||
*
|
||||
@@ -30781,6 +30781,45 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
|
||||
// no-op
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatch to collect the {@link ViewTranslationRequest}s for translation purpose by traversing
|
||||
* the hierarchy when the app requests ui translation. Typically, this method should only be
|
||||
* overridden by subclasses that provide a view hierarchy (such as {@link ViewGroup}). Other
|
||||
* classes should override {@link View#onCreateTranslationRequest}. When requested to start the
|
||||
* 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 android.view.translation.Translator} to translate the requests.
|
||||
*
|
||||
* <p> The default implementation will call {@link View#onCreateTranslationRequest} to build
|
||||
* {@link ViewTranslationRequest} if the view should be translated. </p>
|
||||
*
|
||||
* @param viewIds a map for the view's {@link AutofillId} and its virtual child ids or
|
||||
* {@code null} if the view doesn't have virtual child that should be translated. The virtual
|
||||
* child ids are the same virtual ids provided by ContentCapture.
|
||||
* @param supportedFormats the supported translation formats. For now, the only possible value
|
||||
* is the {@link android.view.translation.TranslationSpec#DATA_FORMAT_TEXT}.
|
||||
* @param capability a {@link TranslationCapability} that holds translation capability.
|
||||
* information, e.g. source spec, target spec.
|
||||
* @param requests fill in with {@link ViewTranslationRequest}s for translation purpose.
|
||||
*/
|
||||
public void dispatchRequestTranslation(@NonNull Map<AutofillId, long[]> viewIds,
|
||||
@NonNull @DataFormat int[] supportedFormats,
|
||||
@Nullable TranslationCapability capability,
|
||||
@NonNull List<ViewTranslationRequest> requests) {
|
||||
AutofillId autofillId = getAutofillId();
|
||||
if (viewIds.containsKey(autofillId)) {
|
||||
ViewTranslationRequest request = null;
|
||||
if (viewIds.get(autofillId) == null) {
|
||||
request = onCreateTranslationRequest(supportedFormats);
|
||||
if (request != null && request.getKeys().size() > 0) {
|
||||
requests.add(request);
|
||||
}
|
||||
} else {
|
||||
// TODO: handle virtual view
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called to generate a {@link DisplayHash} for this view.
|
||||
*
|
||||
|
||||
@@ -65,9 +65,13 @@ import android.view.animation.Animation;
|
||||
import android.view.animation.AnimationUtils;
|
||||
import android.view.animation.LayoutAnimationController;
|
||||
import android.view.animation.Transformation;
|
||||
import android.view.autofill.AutofillId;
|
||||
import android.view.autofill.Helper;
|
||||
import android.view.inspector.InspectableProperty;
|
||||
import android.view.inspector.InspectableProperty.EnumEntry;
|
||||
import android.view.translation.TranslationCapability;
|
||||
import android.view.translation.TranslationSpec.DataFormat;
|
||||
import android.view.translation.ViewTranslationRequest;
|
||||
|
||||
import com.android.internal.R;
|
||||
|
||||
@@ -9264,4 +9268,25 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
|
||||
mParent.onDescendantUnbufferedRequested();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* The implementation calls {@link #dispatchRequestTranslation} for all the child views.
|
||||
*/
|
||||
@Override
|
||||
public void dispatchRequestTranslation(@NonNull Map<AutofillId, long[]> viewIds,
|
||||
@NonNull @DataFormat int[] supportedFormats,
|
||||
@Nullable TranslationCapability capability,
|
||||
@NonNull List<ViewTranslationRequest> requests) {
|
||||
super.dispatchRequestTranslation(viewIds, supportedFormats, capability, requests);
|
||||
final int childCount = getChildCount();
|
||||
if (childCount == 0) {
|
||||
return;
|
||||
}
|
||||
for (int i = 0; i < childCount; ++i) {
|
||||
final View child = getChildAt(i);
|
||||
child.dispatchRequestTranslation(viewIds, supportedFormats, capability, requests);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@ import android.util.ArrayMap;
|
||||
import android.util.Log;
|
||||
import android.util.Pair;
|
||||
import android.util.SparseArray;
|
||||
import android.util.SparseIntArray;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.ViewRootImpl;
|
||||
@@ -46,6 +47,7 @@ import java.io.PrintWriter;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
/**
|
||||
@@ -223,7 +225,6 @@ public class UiTranslationController {
|
||||
pw.print(outerPrefix); pw.print("isContainsView: "); pw.println(isContainsView);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The method is used by {@link Translator}, it will be called when the translation is done. The
|
||||
* translation result can be get from here.
|
||||
@@ -236,12 +237,30 @@ public class UiTranslationController {
|
||||
}
|
||||
final SparseArray<ViewTranslationResponse> translatedResult =
|
||||
response.getViewTranslationResponses();
|
||||
// TODO(b/177960696): handle virtual views. Check the result if the AutofillId is virtual
|
||||
// AutofillId?
|
||||
onTranslationCompleted(translatedResult);
|
||||
final SparseArray<ViewTranslationResponse> viewsResult = new SparseArray<>();
|
||||
final SparseArray<ViewTranslationResponse> virtualViewsResult = new SparseArray<>();
|
||||
final List<AutofillId> viewIds = new ArrayList<>();
|
||||
for (int i = 0; i < translatedResult.size(); i++) {
|
||||
final ViewTranslationResponse result = translatedResult.valueAt(i);
|
||||
final AutofillId autofillId = result.getAutofillId();
|
||||
if (autofillId.isNonVirtual()) {
|
||||
viewsResult.put(translatedResult.keyAt(i), result);
|
||||
viewIds.add(autofillId);
|
||||
} else {
|
||||
virtualViewsResult.put(translatedResult.keyAt(i), result);
|
||||
}
|
||||
}
|
||||
if (viewsResult.size() > 0) {
|
||||
onTranslationCompleted(viewsResult, viewIds);
|
||||
}
|
||||
//TODO(b/177960696): call virtual views onTranslationCompleted()
|
||||
}
|
||||
|
||||
private void onTranslationCompleted(SparseArray<ViewTranslationResponse> translatedResult) {
|
||||
/**
|
||||
* The method is used to handle the translation result for non-vertual views.
|
||||
*/
|
||||
private void onTranslationCompleted(SparseArray<ViewTranslationResponse> translatedResult,
|
||||
List<AutofillId> viewIds) {
|
||||
if (!mActivity.isResumed()) {
|
||||
if (DEBUG) {
|
||||
Log.v(TAG, "onTranslationCompleted: Activity is not resumed.");
|
||||
@@ -258,8 +277,10 @@ public class UiTranslationController {
|
||||
+ "Skip to show the translated text.");
|
||||
return;
|
||||
}
|
||||
// Traverse tree and get views by the responsed AutofillId
|
||||
findViewsTraversalByAutofillIds(viewIds);
|
||||
for (int i = 0; i < resultCount; i++) {
|
||||
final ViewTranslationResponse response = translatedResult.get(i);
|
||||
final ViewTranslationResponse response = translatedResult.valueAt(i);
|
||||
final AutofillId autofillId = response.getAutofillId();
|
||||
if (autofillId == null) {
|
||||
continue;
|
||||
@@ -319,44 +340,62 @@ public class UiTranslationController {
|
||||
*/
|
||||
private void onUiTranslationStarted(Translator translator, List<AutofillId> views) {
|
||||
synchronized (mLock) {
|
||||
// TODO(b/177960696): handle virtual views. Need to check the requested view list is
|
||||
// virtual AutofillId or not
|
||||
findViewsAndCollectViewTranslationRequest(translator, views);
|
||||
// Filter the request views's AutofillId
|
||||
SparseIntArray virtualViewChildCount = getRequestVirtualViewChildCount(views);
|
||||
Map<AutofillId, long[]> viewIds = new ArrayMap<>();
|
||||
for (int i = 0; i < views.size(); i++) {
|
||||
AutofillId autofillId = views.get(i);
|
||||
if (autofillId.isNonVirtual()) {
|
||||
viewIds.put(autofillId, null);
|
||||
} else {
|
||||
// The virtual id get from content capture is long, see getVirtualChildLongId()
|
||||
// e.g. 1001, 1001:2, 1002:1 -> 1001, <1,2>; 1002, <1>
|
||||
AutofillId virtualViewAutofillId = new AutofillId(autofillId.getViewId());
|
||||
long[] childs;
|
||||
if (viewIds.containsKey(virtualViewAutofillId)) {
|
||||
childs = viewIds.get(virtualViewAutofillId);
|
||||
} else {
|
||||
int childCount = virtualViewChildCount.get(autofillId.getViewId());
|
||||
childs = new long[childCount];
|
||||
viewIds.put(virtualViewAutofillId, childs);
|
||||
}
|
||||
int end = childs.length;
|
||||
childs[end] = autofillId.getVirtualChildLongId();
|
||||
}
|
||||
}
|
||||
ArrayList<ViewTranslationRequest> requests = new ArrayList<>();
|
||||
int[] supportedFormats = getSupportedFormatsLocked();
|
||||
ArrayList<ViewRootImpl> roots =
|
||||
WindowManagerGlobal.getInstance().getRootViews(mActivity.getActivityToken());
|
||||
mActivity.runOnUiThread(() -> {
|
||||
// traverse the hierarchy to collect ViewTranslationRequests
|
||||
for (int rootNum = 0; rootNum < roots.size(); rootNum++) {
|
||||
View rootView = roots.get(rootNum).getView();
|
||||
// TODO(b/183589662): call getTranslationCapabilities() for capability
|
||||
rootView.dispatchRequestTranslation(viewIds, supportedFormats, /* capability */
|
||||
null, requests);
|
||||
}
|
||||
mWorkerHandler.sendMessage(PooledLambda.obtainMessage(
|
||||
UiTranslationController::sendTranslationRequest,
|
||||
UiTranslationController.this, translator, requests));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If the translation requested views are not virtual view, we need to traverse the tree to
|
||||
* find the views and get the View's ViewTranslationRequest.
|
||||
*/
|
||||
private void findViewsAndCollectViewTranslationRequest(Translator translator,
|
||||
List<AutofillId> views) {
|
||||
// Find Views collect the translation data
|
||||
final ArrayList<ViewTranslationRequest> requests = new ArrayList<>();
|
||||
final ArrayList<View> foundViews = new ArrayList<>();
|
||||
findViewsTraversalByAutofillIds(views, foundViews);
|
||||
final int[] supportedFormats = getSupportedFormatsLocked();
|
||||
for (int i = 0; i < foundViews.size(); i++) {
|
||||
final View view = foundViews.get(i);
|
||||
final int currentCount = i;
|
||||
mActivity.runOnUiThread(() -> {
|
||||
final ViewTranslationRequest request =
|
||||
view.createTranslationRequest(supportedFormats);
|
||||
// TODO(b/177960696): handle null case, the developers may want to handle the
|
||||
// translation, call dispatchRequestTranslation() instead.
|
||||
if (request != null
|
||||
&& request.getKeys().size() > 0) {
|
||||
requests.add(request);
|
||||
private SparseIntArray getRequestVirtualViewChildCount(List<AutofillId> views) {
|
||||
SparseIntArray virtualViewCount = new SparseIntArray();
|
||||
for (int i = 0; i < views.size(); i++) {
|
||||
AutofillId autofillId = views.get(i);
|
||||
if (!autofillId.isNonVirtual()) {
|
||||
int virtualViewId = autofillId.getViewId();
|
||||
if (virtualViewCount.indexOfKey(virtualViewId) < 0) {
|
||||
virtualViewCount.put(virtualViewId, 1);
|
||||
} else {
|
||||
virtualViewCount.put(virtualViewId, (virtualViewCount.get(virtualViewId) + 1));
|
||||
}
|
||||
if (currentCount == (foundViews.size() - 1)) {
|
||||
Log.v(TAG, "onUiTranslationStarted: collect " + requests.size()
|
||||
+ " requests.");
|
||||
mWorkerHandler.sendMessage(PooledLambda.obtainMessage(
|
||||
UiTranslationController::sendTranslationRequest,
|
||||
UiTranslationController.this, translator, requests));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
return virtualViewCount;
|
||||
}
|
||||
|
||||
private int[] getSupportedFormatsLocked() {
|
||||
@@ -364,39 +403,36 @@ public class UiTranslationController {
|
||||
return new int[] {TranslationSpec.DATA_FORMAT_TEXT};
|
||||
}
|
||||
|
||||
private void findViewsTraversalByAutofillIds(List<AutofillId> sourceViewIds,
|
||||
ArrayList<View> foundViews) {
|
||||
private void findViewsTraversalByAutofillIds(List<AutofillId> sourceViewIds) {
|
||||
final ArrayList<ViewRootImpl> roots =
|
||||
WindowManagerGlobal.getInstance().getRootViews(mActivity.getActivityToken());
|
||||
for (int rootNum = 0; rootNum < roots.size(); rootNum++) {
|
||||
final View rootView = roots.get(rootNum).getView();
|
||||
if (rootView instanceof ViewGroup) {
|
||||
findViewsTraversalByAutofillIds((ViewGroup) rootView, sourceViewIds, foundViews);
|
||||
findViewsTraversalByAutofillIds((ViewGroup) rootView, sourceViewIds);
|
||||
} else {
|
||||
addViewIfNeeded(sourceViewIds, rootView, foundViews);
|
||||
addViewIfNeeded(sourceViewIds, rootView);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void findViewsTraversalByAutofillIds(ViewGroup viewGroup,
|
||||
List<AutofillId> sourceViewIds, ArrayList<View> foundViews) {
|
||||
List<AutofillId> sourceViewIds) {
|
||||
final int childCount = viewGroup.getChildCount();
|
||||
for (int i = 0; i < childCount; ++i) {
|
||||
final View child = viewGroup.getChildAt(i);
|
||||
if (child instanceof ViewGroup) {
|
||||
findViewsTraversalByAutofillIds((ViewGroup) child, sourceViewIds, foundViews);
|
||||
findViewsTraversalByAutofillIds((ViewGroup) child, sourceViewIds);
|
||||
} else {
|
||||
addViewIfNeeded(sourceViewIds, child, foundViews);
|
||||
addViewIfNeeded(sourceViewIds, child);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void addViewIfNeeded(List<AutofillId> sourceViewIds, View view,
|
||||
ArrayList<View> foundViews) {
|
||||
private void addViewIfNeeded(List<AutofillId> sourceViewIds, View view) {
|
||||
final AutofillId autofillId = view.getAutofillId();
|
||||
if (sourceViewIds.contains(autofillId)) {
|
||||
mViews.put(autofillId, new WeakReference<>(view));
|
||||
foundViews.add(view);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -13872,7 +13872,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
|
||||
*/
|
||||
@Nullable
|
||||
@Override
|
||||
public ViewTranslationRequest createTranslationRequest(@NonNull int[] supportedFormats) {
|
||||
public ViewTranslationRequest onCreateTranslationRequest(@NonNull int[] supportedFormats) {
|
||||
if (supportedFormats == null || supportedFormats.length == 0) {
|
||||
// TODO(b/182433547): remove before S release
|
||||
if (UiTranslationController.DEBUG) {
|
||||
@@ -13938,7 +13938,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
|
||||
|
||||
/**
|
||||
*
|
||||
* Called when the content from {@link #createTranslationRequest} had been translated by the
|
||||
* Called when the content from {@link #onCreateTranslationRequest} had been translated by the
|
||||
* TranslationService. The default implementation will replace the current
|
||||
* {@link TransformationMethod} to transform the original text to the translated text display.
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user