Loading core/java/android/view/translation/UiTranslationController.java +82 −2 Original line number Original line Diff line number Diff line Loading @@ -25,6 +25,7 @@ import android.annotation.NonNull; import android.annotation.WorkerThread; import android.annotation.WorkerThread; import android.app.Activity; import android.app.Activity; import android.content.Context; import android.content.Context; import android.os.Build; import android.os.Handler; import android.os.Handler; import android.os.HandlerThread; import android.os.HandlerThread; import android.os.Process; import android.os.Process; Loading Loading @@ -54,6 +55,11 @@ import java.util.function.Consumer; */ */ public class UiTranslationController { public class UiTranslationController { // TODO(b/182433547): remove Build.IS_DEBUGGABLE before ship. Enable the logging in debug build // to help the debug during the development phase public static final boolean DEBUG = Log.isLoggable(UiTranslationManager.LOG_TAG, Log.DEBUG) || Build.IS_DEBUGGABLE; private static final String TAG = "UiTranslationController"; private static final String TAG = "UiTranslationController"; @NonNull @NonNull private final Activity mActivity; private final Activity mActivity; Loading Loading @@ -93,6 +99,8 @@ public class UiTranslationController { if (!mActivity.isResumed()) { if (!mActivity.isResumed()) { return; return; } } Log.i(TAG, "updateUiTranslationState state: " + stateToString(state) + (DEBUG ? ", views: " + views : "")); switch (state) { switch (state) { case STATE_UI_TRANSLATION_STARTED: case STATE_UI_TRANSLATION_STARTED: final Pair<TranslationSpec, TranslationSpec> specs = final Pair<TranslationSpec, TranslationSpec> specs = Loading Loading @@ -149,7 +157,68 @@ public class UiTranslationController { translator.dump(outerPrefix, pw); translator.dump(outerPrefix, pw); pw.println(); pw.println(); } } synchronized (mLock) { final int viewSize = mViews.size(); pw.print(outerPrefix); pw.print("number views: "); pw.println(viewSize); for (int i = 0; i < viewSize; i++) { pw.print(outerPrefix); pw.print("#"); pw.println(i); final AutofillId autofillId = mViews.keyAt(i); final View view = mViews.valueAt(i).get(); pw.print(pfx); pw.print("autofillId: "); pw.println(autofillId); pw.print(pfx); pw.print("view:"); pw.println(view); } } // TODO(b/182433547): we will remove debug rom condition before S release then we change // change this back to "DEBUG" if (Log.isLoggable(UiTranslationManager.LOG_TAG, Log.DEBUG)) { dumpViewByTraversal(outerPrefix, pw); } } private void dumpViewByTraversal(String outerPrefix, PrintWriter pw) { final ArrayList<ViewRootImpl> roots = WindowManagerGlobal.getInstance().getRootViews(mActivity.getActivityToken()); pw.print(outerPrefix); pw.println("Dump views:"); for (int rootNum = 0; rootNum < roots.size(); rootNum++) { final View rootView = roots.get(rootNum).getView(); if (rootView instanceof ViewGroup) { dumpChildren((ViewGroup) rootView, outerPrefix, pw); } else { dumpViewInfo(rootView, outerPrefix, pw); } } } private void dumpChildren(ViewGroup viewGroup, String outerPrefix, PrintWriter pw) { final int childCount = viewGroup.getChildCount(); for (int i = 0; i < childCount; ++i) { final View child = viewGroup.getChildAt(i); if (child instanceof ViewGroup) { pw.print(outerPrefix); pw.println("Children: "); pw.print(outerPrefix); pw.print(outerPrefix); pw.println(child); dumpChildren((ViewGroup) child, outerPrefix, pw); } else { pw.print(outerPrefix); pw.println("End Children: "); pw.print(outerPrefix); pw.print(outerPrefix); pw.print(child); dumpViewInfo(child, outerPrefix, pw); } } } private void dumpViewInfo(View view, String outerPrefix, PrintWriter pw) { final AutofillId autofillId = view.getAutofillId(); pw.print(outerPrefix); pw.print("autofillId: "); pw.print(autofillId); // TODO: print TranslationTransformation boolean isContainsView = false; synchronized (mLock) { final WeakReference<View> viewRef = mViews.get(autofillId); if (viewRef != null && viewRef.get() != null) { isContainsView = true; } } } 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 * The method is used by {@link Translator}, it will be called when the translation is done. The Loading @@ -171,6 +240,9 @@ public class UiTranslationController { return; return; } } final int resultCount = translatedResult.size(); final int resultCount = translatedResult.size(); if (DEBUG) { Log.v(TAG, "onTranslationCompleted: receive " + resultCount + " responses."); } synchronized (mLock) { synchronized (mLock) { for (int i = 0; i < resultCount; i++) { for (int i = 0; i < resultCount; i++) { final ViewTranslationResponse response = translatedResult.get(i); final ViewTranslationResponse response = translatedResult.get(i); Loading @@ -180,7 +252,7 @@ public class UiTranslationController { } } final View view = mViews.get(autofillId).get(); final View view = mViews.get(autofillId).get(); if (view == null) { if (view == null) { Log.w(TAG, "onTranslationCompleted: the Veiew for autofill id " + autofillId Log.w(TAG, "onTranslationCompleted: the view for autofill id " + autofillId + " may be gone."); + " may be gone."); continue; continue; } } Loading Loading @@ -208,6 +280,10 @@ public class UiTranslationController { @WorkerThread @WorkerThread private void sendTranslationRequest(Translator translator, private void sendTranslationRequest(Translator translator, List<ViewTranslationRequest> requests) { List<ViewTranslationRequest> requests) { if (requests.size() == 0) { Log.wtf(TAG, "No ViewTranslationRequest was collected."); return; } final TranslationRequest request = new TranslationRequest.Builder() final TranslationRequest request = new TranslationRequest.Builder() .setViewTranslationRequests(requests) .setViewTranslationRequests(requests) .build(); .build(); Loading @@ -233,7 +309,8 @@ public class UiTranslationController { requests.add(request); requests.add(request); } } if (currentCount == (foundViews.size() - 1)) { if (currentCount == (foundViews.size() - 1)) { Log.v(TAG, "onUiTranslationStarted: send " + requests.size() + " request."); Log.v(TAG, "onUiTranslationStarted: collect " + requests.size() + " requests."); mWorkerHandler.sendMessage(PooledLambda.obtainMessage( mWorkerHandler.sendMessage(PooledLambda.obtainMessage( UiTranslationController::sendTranslationRequest, UiTranslationController::sendTranslationRequest, UiTranslationController.this, translator, requests)); UiTranslationController.this, translator, requests)); Loading Loading @@ -287,6 +364,9 @@ public class UiTranslationController { for (int i = 0; i < viewCounts; i++) { for (int i = 0; i < viewCounts; i++) { final View view = views.valueAt(i).get(); final View view = views.valueAt(i).get(); if (view == null) { if (view == null) { if (DEBUG) { Log.d(TAG, "View was gone for autofillid = " + views.keyAt(i)); } continue; continue; } } action.accept(view); action.accept(view); Loading core/java/android/view/translation/UiTranslationManager.java +8 −0 Original line number Original line Diff line number Diff line Loading @@ -42,6 +42,14 @@ public final class UiTranslationManager { private static final String TAG = "UiTranslationManager"; private static final String TAG = "UiTranslationManager"; /** * The tag which uses for enabling debug log dump. To enable it, we can use command "adb shell * setprop log.tag.UiTranslation DEBUG". * * @hide */ public static final String LOG_TAG = "UiTranslation"; /** /** * The state caller request to disable utranslation,, it is no longer need to ui translation. * The state caller request to disable utranslation,, it is no longer need to ui translation. * * Loading core/java/android/widget/TextView.java +18 −1 Original line number Original line Diff line number Diff line Loading @@ -195,6 +195,7 @@ import android.view.textclassifier.TextLinks; import android.view.textservice.SpellCheckerSubtype; import android.view.textservice.SpellCheckerSubtype; import android.view.textservice.TextServicesManager; import android.view.textservice.TextServicesManager; import android.view.translation.TranslationRequestValue; import android.view.translation.TranslationRequestValue; import android.view.translation.UiTranslationController; import android.view.translation.ViewTranslationRequest; import android.view.translation.ViewTranslationRequest; import android.view.translation.ViewTranslationResponse; import android.view.translation.ViewTranslationResponse; import android.widget.RemoteViews.RemoteView; import android.widget.RemoteViews.RemoteView; Loading Loading @@ -13835,6 +13836,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener @Override @Override public ViewTranslationRequest onCreateTranslationRequest() { public ViewTranslationRequest onCreateTranslationRequest() { if (mText == null || mText.length() == 0) { if (mText == null || mText.length() == 0) { // TODO(b/182433547): remove before S release if (UiTranslationController.DEBUG) { Log.w(LOG_TAG, "Cannot create translation request for the empty text."); } return null; return null; } } // Not translate password, editable text and not important for translation // Not translate password, editable text and not important for translation Loading @@ -13842,6 +13847,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener // text selection apis, not support in S. // text selection apis, not support in S. boolean isPassword = isAnyPasswordInputType() || hasPasswordTransformationMethod(); boolean isPassword = isAnyPasswordInputType() || hasPasswordTransformationMethod(); if (isTextEditable() || isPassword || isTextSelectable()) { if (isTextEditable() || isPassword || isTextSelectable()) { // TODO(b/182433547): remove before S release if (UiTranslationController.DEBUG) { Log.w(LOG_TAG, "Cannot create translation request. editable = " + isTextEditable() + ", isPassword = " + isPassword + ", selectable = " + isTextSelectable()); } return null; return null; } } // TODO(b/176488462): apply the view's important for translation property // TODO(b/176488462): apply the view's important for translation property Loading Loading @@ -13870,6 +13880,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener // Restore to original text content. // Restore to original text content. if (mTranslationTransformation != null) { if (mTranslationTransformation != null) { setTransformationMethod(mTranslationTransformation.getOriginalTransformationMethod()); setTransformationMethod(mTranslationTransformation.getOriginalTransformationMethod()); } else { // TODO(b/182433547): remove before S release Log.w(LOG_TAG, "onPauseUiTranslation(): no translated text."); } } } } Loading @@ -13889,7 +13902,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener if (mTranslationTransformation != null) { if (mTranslationTransformation != null) { setTransformationMethod(mTranslationTransformation); setTransformationMethod(mTranslationTransformation); } else { } else { Log.w(LOG_TAG, "onResumeTranslatedText(): no translated text."); // TODO(b/182433547): remove before S release Log.w(LOG_TAG, "onRestoreUiTranslation(): no translated text."); } } } } Loading @@ -13910,6 +13924,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener if (mTranslationTransformation != null) { if (mTranslationTransformation != null) { setTransformationMethod(mTranslationTransformation.getOriginalTransformationMethod()); setTransformationMethod(mTranslationTransformation.getOriginalTransformationMethod()); mTranslationTransformation = null; mTranslationTransformation = null; } else { // TODO(b/182433547): remove before S release Log.w(LOG_TAG, "onFinishUiTranslation(): no translated text."); } } } } Loading
core/java/android/view/translation/UiTranslationController.java +82 −2 Original line number Original line Diff line number Diff line Loading @@ -25,6 +25,7 @@ import android.annotation.NonNull; import android.annotation.WorkerThread; import android.annotation.WorkerThread; import android.app.Activity; import android.app.Activity; import android.content.Context; import android.content.Context; import android.os.Build; import android.os.Handler; import android.os.Handler; import android.os.HandlerThread; import android.os.HandlerThread; import android.os.Process; import android.os.Process; Loading Loading @@ -54,6 +55,11 @@ import java.util.function.Consumer; */ */ public class UiTranslationController { public class UiTranslationController { // TODO(b/182433547): remove Build.IS_DEBUGGABLE before ship. Enable the logging in debug build // to help the debug during the development phase public static final boolean DEBUG = Log.isLoggable(UiTranslationManager.LOG_TAG, Log.DEBUG) || Build.IS_DEBUGGABLE; private static final String TAG = "UiTranslationController"; private static final String TAG = "UiTranslationController"; @NonNull @NonNull private final Activity mActivity; private final Activity mActivity; Loading Loading @@ -93,6 +99,8 @@ public class UiTranslationController { if (!mActivity.isResumed()) { if (!mActivity.isResumed()) { return; return; } } Log.i(TAG, "updateUiTranslationState state: " + stateToString(state) + (DEBUG ? ", views: " + views : "")); switch (state) { switch (state) { case STATE_UI_TRANSLATION_STARTED: case STATE_UI_TRANSLATION_STARTED: final Pair<TranslationSpec, TranslationSpec> specs = final Pair<TranslationSpec, TranslationSpec> specs = Loading Loading @@ -149,7 +157,68 @@ public class UiTranslationController { translator.dump(outerPrefix, pw); translator.dump(outerPrefix, pw); pw.println(); pw.println(); } } synchronized (mLock) { final int viewSize = mViews.size(); pw.print(outerPrefix); pw.print("number views: "); pw.println(viewSize); for (int i = 0; i < viewSize; i++) { pw.print(outerPrefix); pw.print("#"); pw.println(i); final AutofillId autofillId = mViews.keyAt(i); final View view = mViews.valueAt(i).get(); pw.print(pfx); pw.print("autofillId: "); pw.println(autofillId); pw.print(pfx); pw.print("view:"); pw.println(view); } } // TODO(b/182433547): we will remove debug rom condition before S release then we change // change this back to "DEBUG" if (Log.isLoggable(UiTranslationManager.LOG_TAG, Log.DEBUG)) { dumpViewByTraversal(outerPrefix, pw); } } private void dumpViewByTraversal(String outerPrefix, PrintWriter pw) { final ArrayList<ViewRootImpl> roots = WindowManagerGlobal.getInstance().getRootViews(mActivity.getActivityToken()); pw.print(outerPrefix); pw.println("Dump views:"); for (int rootNum = 0; rootNum < roots.size(); rootNum++) { final View rootView = roots.get(rootNum).getView(); if (rootView instanceof ViewGroup) { dumpChildren((ViewGroup) rootView, outerPrefix, pw); } else { dumpViewInfo(rootView, outerPrefix, pw); } } } private void dumpChildren(ViewGroup viewGroup, String outerPrefix, PrintWriter pw) { final int childCount = viewGroup.getChildCount(); for (int i = 0; i < childCount; ++i) { final View child = viewGroup.getChildAt(i); if (child instanceof ViewGroup) { pw.print(outerPrefix); pw.println("Children: "); pw.print(outerPrefix); pw.print(outerPrefix); pw.println(child); dumpChildren((ViewGroup) child, outerPrefix, pw); } else { pw.print(outerPrefix); pw.println("End Children: "); pw.print(outerPrefix); pw.print(outerPrefix); pw.print(child); dumpViewInfo(child, outerPrefix, pw); } } } private void dumpViewInfo(View view, String outerPrefix, PrintWriter pw) { final AutofillId autofillId = view.getAutofillId(); pw.print(outerPrefix); pw.print("autofillId: "); pw.print(autofillId); // TODO: print TranslationTransformation boolean isContainsView = false; synchronized (mLock) { final WeakReference<View> viewRef = mViews.get(autofillId); if (viewRef != null && viewRef.get() != null) { isContainsView = true; } } } 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 * The method is used by {@link Translator}, it will be called when the translation is done. The Loading @@ -171,6 +240,9 @@ public class UiTranslationController { return; return; } } final int resultCount = translatedResult.size(); final int resultCount = translatedResult.size(); if (DEBUG) { Log.v(TAG, "onTranslationCompleted: receive " + resultCount + " responses."); } synchronized (mLock) { synchronized (mLock) { for (int i = 0; i < resultCount; i++) { for (int i = 0; i < resultCount; i++) { final ViewTranslationResponse response = translatedResult.get(i); final ViewTranslationResponse response = translatedResult.get(i); Loading @@ -180,7 +252,7 @@ public class UiTranslationController { } } final View view = mViews.get(autofillId).get(); final View view = mViews.get(autofillId).get(); if (view == null) { if (view == null) { Log.w(TAG, "onTranslationCompleted: the Veiew for autofill id " + autofillId Log.w(TAG, "onTranslationCompleted: the view for autofill id " + autofillId + " may be gone."); + " may be gone."); continue; continue; } } Loading Loading @@ -208,6 +280,10 @@ public class UiTranslationController { @WorkerThread @WorkerThread private void sendTranslationRequest(Translator translator, private void sendTranslationRequest(Translator translator, List<ViewTranslationRequest> requests) { List<ViewTranslationRequest> requests) { if (requests.size() == 0) { Log.wtf(TAG, "No ViewTranslationRequest was collected."); return; } final TranslationRequest request = new TranslationRequest.Builder() final TranslationRequest request = new TranslationRequest.Builder() .setViewTranslationRequests(requests) .setViewTranslationRequests(requests) .build(); .build(); Loading @@ -233,7 +309,8 @@ public class UiTranslationController { requests.add(request); requests.add(request); } } if (currentCount == (foundViews.size() - 1)) { if (currentCount == (foundViews.size() - 1)) { Log.v(TAG, "onUiTranslationStarted: send " + requests.size() + " request."); Log.v(TAG, "onUiTranslationStarted: collect " + requests.size() + " requests."); mWorkerHandler.sendMessage(PooledLambda.obtainMessage( mWorkerHandler.sendMessage(PooledLambda.obtainMessage( UiTranslationController::sendTranslationRequest, UiTranslationController::sendTranslationRequest, UiTranslationController.this, translator, requests)); UiTranslationController.this, translator, requests)); Loading Loading @@ -287,6 +364,9 @@ public class UiTranslationController { for (int i = 0; i < viewCounts; i++) { for (int i = 0; i < viewCounts; i++) { final View view = views.valueAt(i).get(); final View view = views.valueAt(i).get(); if (view == null) { if (view == null) { if (DEBUG) { Log.d(TAG, "View was gone for autofillid = " + views.keyAt(i)); } continue; continue; } } action.accept(view); action.accept(view); Loading
core/java/android/view/translation/UiTranslationManager.java +8 −0 Original line number Original line Diff line number Diff line Loading @@ -42,6 +42,14 @@ public final class UiTranslationManager { private static final String TAG = "UiTranslationManager"; private static final String TAG = "UiTranslationManager"; /** * The tag which uses for enabling debug log dump. To enable it, we can use command "adb shell * setprop log.tag.UiTranslation DEBUG". * * @hide */ public static final String LOG_TAG = "UiTranslation"; /** /** * The state caller request to disable utranslation,, it is no longer need to ui translation. * The state caller request to disable utranslation,, it is no longer need to ui translation. * * Loading
core/java/android/widget/TextView.java +18 −1 Original line number Original line Diff line number Diff line Loading @@ -195,6 +195,7 @@ import android.view.textclassifier.TextLinks; import android.view.textservice.SpellCheckerSubtype; import android.view.textservice.SpellCheckerSubtype; import android.view.textservice.TextServicesManager; import android.view.textservice.TextServicesManager; import android.view.translation.TranslationRequestValue; import android.view.translation.TranslationRequestValue; import android.view.translation.UiTranslationController; import android.view.translation.ViewTranslationRequest; import android.view.translation.ViewTranslationRequest; import android.view.translation.ViewTranslationResponse; import android.view.translation.ViewTranslationResponse; import android.widget.RemoteViews.RemoteView; import android.widget.RemoteViews.RemoteView; Loading Loading @@ -13835,6 +13836,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener @Override @Override public ViewTranslationRequest onCreateTranslationRequest() { public ViewTranslationRequest onCreateTranslationRequest() { if (mText == null || mText.length() == 0) { if (mText == null || mText.length() == 0) { // TODO(b/182433547): remove before S release if (UiTranslationController.DEBUG) { Log.w(LOG_TAG, "Cannot create translation request for the empty text."); } return null; return null; } } // Not translate password, editable text and not important for translation // Not translate password, editable text and not important for translation Loading @@ -13842,6 +13847,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener // text selection apis, not support in S. // text selection apis, not support in S. boolean isPassword = isAnyPasswordInputType() || hasPasswordTransformationMethod(); boolean isPassword = isAnyPasswordInputType() || hasPasswordTransformationMethod(); if (isTextEditable() || isPassword || isTextSelectable()) { if (isTextEditable() || isPassword || isTextSelectable()) { // TODO(b/182433547): remove before S release if (UiTranslationController.DEBUG) { Log.w(LOG_TAG, "Cannot create translation request. editable = " + isTextEditable() + ", isPassword = " + isPassword + ", selectable = " + isTextSelectable()); } return null; return null; } } // TODO(b/176488462): apply the view's important for translation property // TODO(b/176488462): apply the view's important for translation property Loading Loading @@ -13870,6 +13880,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener // Restore to original text content. // Restore to original text content. if (mTranslationTransformation != null) { if (mTranslationTransformation != null) { setTransformationMethod(mTranslationTransformation.getOriginalTransformationMethod()); setTransformationMethod(mTranslationTransformation.getOriginalTransformationMethod()); } else { // TODO(b/182433547): remove before S release Log.w(LOG_TAG, "onPauseUiTranslation(): no translated text."); } } } } Loading @@ -13889,7 +13902,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener if (mTranslationTransformation != null) { if (mTranslationTransformation != null) { setTransformationMethod(mTranslationTransformation); setTransformationMethod(mTranslationTransformation); } else { } else { Log.w(LOG_TAG, "onResumeTranslatedText(): no translated text."); // TODO(b/182433547): remove before S release Log.w(LOG_TAG, "onRestoreUiTranslation(): no translated text."); } } } } Loading @@ -13910,6 +13924,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener if (mTranslationTransformation != null) { if (mTranslationTransformation != null) { setTransformationMethod(mTranslationTransformation.getOriginalTransformationMethod()); setTransformationMethod(mTranslationTransformation.getOriginalTransformationMethod()); mTranslationTransformation = null; mTranslationTransformation = null; } else { // TODO(b/182433547): remove before S release Log.w(LOG_TAG, "onFinishUiTranslation(): no translated text."); } } } }