From c35960c314af0db1d3cd8a8e70dd8393184045b2 Mon Sep 17 00:00:00 2001 From: Mark Punzalan Date: Wed, 27 Apr 2022 22:39:54 +0000 Subject: [PATCH] Reset translation state when views disappear. Views may be re-used (e.g., as in ListView and RecyclerView) so we need to ensure they don't have the translated text when they appear again. RecyclerView seems to recycle translated views even when `hasTransientState() == true` which is the case when views are translated. This should be fixed separately. Bug: 223700458 Test: atest CtsTranslationTestCases Test: atest CtsContentCaptureServiceTestCases Test: atest CtsAutoFillServiceTestCases Test: manual - New messages are translated correctly even if views are re-used. Messages are translated correctly when scrolled onto the screen and stay translated while on-screen. Change-Id: I97cc418a801c006c857e971110ab811ad383343e --- core/java/android/view/View.java | 22 ++++++++++++++++++- .../translation/UiTranslationController.java | 7 +----- 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 8901d86e1f2a5..c86639cd164e2 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -9921,7 +9921,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, *
    *
  1. It should only be called when content capture is enabled for the view. *
  2. It must call viewAppeared() before viewDisappeared() - *
  3. viewAppearead() can only be called when the view is visible and laidout + *
  4. viewAppeared() can only be called when the view is visible and laid out *
  5. It should not call the same event twice. *
*/ @@ -9998,6 +9998,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Log.v(CONTENT_CAPTURE_LOG_TAG, "no AttachInfo on disappeared for " + this); } } + + // We reset any translation state as views may be re-used (e.g., as in ListView and + // RecyclerView). We only need to do this for views important for content capture since + // views unimportant for content capture won't be translated anyway. + clearTranslationState(); } } @@ -12717,6 +12722,21 @@ public class View implements Drawable.Callback, KeyEvent.Callback, == PFLAG4_HAS_TRANSLATION_TRANSIENT_STATE; } + /** + * @hide + */ + public void clearTranslationState() { + if (mViewTranslationCallback != null) { + mViewTranslationCallback.onClearTranslation(this); + } + clearViewTranslationCallback(); + clearViewTranslationResponse(); + if (hasTranslationTransientState()) { + setHasTransientState(false); + setHasTranslationTransientState(false); + } + } + /** * Returns true if this view is currently attached to a window. */ diff --git a/core/java/android/view/translation/UiTranslationController.java b/core/java/android/view/translation/UiTranslationController.java index 8cf032bc03cb0..6bf2474beb173 100644 --- a/core/java/android/view/translation/UiTranslationController.java +++ b/core/java/android/view/translation/UiTranslationController.java @@ -158,12 +158,7 @@ public class UiTranslationController implements Dumpable { case STATE_UI_TRANSLATION_FINISHED: destroyTranslators(); runForEachView((view, callback) -> { - callback.onClearTranslation(view); - view.clearViewTranslationResponse(); - if (view.hasTranslationTransientState()) { - view.setHasTransientState(false); - view.setHasTranslationTransientState(false); - } + view.clearTranslationState(); }); notifyTranslationFinished(/* activityDestroyed= */ false); synchronized (mLock) {