summaryrefslogtreecommitdiff
path: root/core/java/android/widget/TextViewTranslationCallback.java
diff options
context:
space:
mode:
authorAhaan Ugale <augale@google.com>2021-05-19 23:46:14 -0700
committerAhaan Ugale <augale@google.com>2021-05-27 09:34:18 -0700
commitdf75689d4d8ccac618ea4d11ac693d68fe1a8de7 (patch)
tree2380060017eaa846794caa1965837a2598db449e /core/java/android/widget/TextViewTranslationCallback.java
parent02fe90bb4202123bc21489e4f19fb3427b2f5745 (diff)
Translate: Text alpha animation on toggling translated state.
Apply a simple text alpha animation when toggling between original and translated text. The text is fully faded out, then swapped to the new text, then the fading is reversed. Quick toggles are handled by ending the previous animation (which resets the alpha value) when starting a new one. If the toggle is extremely fast (<250ms for the currently defined animation duration), the text stays in it's original state instead of swapping back-and-forth. This is arguably not ideal, but anyway not worth the complexity for fixing. There is an unhandled edge case where if the color is changed by the app during the animation, the app's change would get overridden. It should be rare and doesn't seem very important to fix. Bug: 178651829 Test: atest CtsTranslationTestCases Test: manual - across several apps, while scrolling, concurrently interacting with the app, concurrently closing the app, selecting text during the animation (with animation speed slowed down to see the effect). Change-Id: I08a26de2253bb345f01186a6748b2d0ff6c2a419
Diffstat (limited to 'core/java/android/widget/TextViewTranslationCallback.java')
-rw-r--r--core/java/android/widget/TextViewTranslationCallback.java86
1 files changed, 81 insertions, 5 deletions
diff --git a/core/java/android/widget/TextViewTranslationCallback.java b/core/java/android/widget/TextViewTranslationCallback.java
index 92c9142749df..a7d5ee465299 100644
--- a/core/java/android/widget/TextViewTranslationCallback.java
+++ b/core/java/android/widget/TextViewTranslationCallback.java
@@ -16,10 +16,15 @@
package android.widget;
+import android.animation.Animator;
+import android.animation.ValueAnimator;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.content.res.ColorStateList;
+import android.graphics.Color;
import android.os.Build;
import android.text.TextUtils;
+import android.text.method.TransformationMethod;
import android.text.method.TranslationTransformationMethod;
import android.util.Log;
import android.view.View;
@@ -47,6 +52,7 @@ public class TextViewTranslationCallback implements ViewTranslationCallback {
private boolean mIsShowingTranslation = false;
private boolean mIsTextPaddingEnabled = false;
private CharSequence mPaddedText;
+ private int mAnimationDurationMillis = 250; // default value
private CharSequence mContentDescription;
@@ -82,14 +88,19 @@ public class TextViewTranslationCallback implements ViewTranslationCallback {
*/
@Override
public boolean onShowTranslation(@NonNull View view) {
- mIsShowingTranslation = true;
if (view.getViewTranslationResponse() == null) {
Log.wtf(TAG, "onShowTranslation() shouldn't be called before "
+ "onViewTranslationResponse().");
return false;
}
if (mTranslationTransformation != null) {
- ((TextView) view).setTransformationMethod(mTranslationTransformation);
+ final TransformationMethod transformation = mTranslationTransformation;
+ runWithAnimation(
+ (TextView) view,
+ () -> {
+ mIsShowingTranslation = true;
+ ((TextView) view).setTransformationMethod(transformation);
+ });
ViewTranslationResponse response = view.getViewTranslationResponse();
if (response.getKeys().contains(ViewTranslationRequest.ID_CONTENT_DESCRIPTION)) {
CharSequence translatedContentDescription =
@@ -114,7 +125,6 @@ public class TextViewTranslationCallback implements ViewTranslationCallback {
*/
@Override
public boolean onHideTranslation(@NonNull View view) {
- mIsShowingTranslation = false;
if (view.getViewTranslationResponse() == null) {
Log.wtf(TAG, "onHideTranslation() shouldn't be called before "
+ "onViewTranslationResponse().");
@@ -122,8 +132,14 @@ public class TextViewTranslationCallback implements ViewTranslationCallback {
}
// Restore to original text content.
if (mTranslationTransformation != null) {
- ((TextView) view).setTransformationMethod(
- mTranslationTransformation.getOriginalTransformationMethod());
+ final TransformationMethod transformation =
+ mTranslationTransformation.getOriginalTransformationMethod();
+ runWithAnimation(
+ (TextView) view,
+ () -> {
+ mIsShowingTranslation = false;
+ ((TextView) view).setTransformationMethod(transformation);
+ });
if (!TextUtils.isEmpty(mContentDescription)) {
view.setContentDescription(mContentDescription);
}
@@ -212,4 +228,64 @@ public class TextViewTranslationCallback implements ViewTranslationCallback {
}
private static final char COMPAT_PAD_CHARACTER = '\u2002';
+
+ @Override
+ public void setAnimationDurationMillis(int durationMillis) {
+ mAnimationDurationMillis = durationMillis;
+ }
+
+ /**
+ * Applies a simple text alpha animation when toggling between original and translated text. The
+ * text is fully faded out, then swapped to the new text, then the fading is reversed.
+ *
+ * @param runnable the operation to run on the view after the text is faded out, to change to
+ * displaying the original or translated text.
+ */
+ private void runWithAnimation(TextView view, Runnable runnable) {
+ if (mAnimator != null) {
+ mAnimator.end();
+ // Note: mAnimator is now null; do not use again here.
+ }
+ int fadedOutColor = colorWithAlpha(view.getCurrentTextColor(), 0);
+ mAnimator = ValueAnimator.ofArgb(view.getCurrentTextColor(), fadedOutColor);
+ mAnimator.addUpdateListener(
+ // Note that if the text has a ColorStateList, this replaces it with a single color
+ // for all states. The original ColorStateList is restored when the animation ends
+ // (see below).
+ (valueAnimator) -> view.setTextColor((Integer) valueAnimator.getAnimatedValue()));
+ mAnimator.setRepeatMode(ValueAnimator.REVERSE);
+ mAnimator.setRepeatCount(1);
+ mAnimator.setDuration(mAnimationDurationMillis);
+ final ColorStateList originalColors = view.getTextColors();
+ mAnimator.addListener(new Animator.AnimatorListener() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ view.setTextColor(originalColors);
+ mAnimator = null;
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ }
+
+ @Override
+ public void onAnimationRepeat(Animator animation) {
+ runnable.run();
+ }
+ });
+ mAnimator.start();
+ }
+
+ private ValueAnimator mAnimator;
+
+ /**
+ * Returns {@code color} with alpha changed to {@code newAlpha}
+ */
+ private static int colorWithAlpha(int color, int newAlpha) {
+ return Color.argb(newAlpha, Color.red(color), Color.green(color), Color.blue(color));
+ }
}