Merge "AutoTranslate: Pad view text for compatibility reasons." into sc-dev

This commit is contained in:
Ahaan Ugale
2021-04-19 05:19:53 +00:00
committed by Android (Google) Code Review
5 changed files with 93 additions and 20 deletions

View File

@@ -78,24 +78,11 @@ public class TranslationTransformationMethod implements TransformationMethod2 {
if (TextUtils.isEmpty(translatedText) || isWhitespace(translatedText.toString())) {
return source;
} else {
// TODO(b/179693024): Remove this once we have the fix to pad the view text instead.
translatedText = ellipsize(translatedText, ((TextView) view).getText().length());
// TODO(b/174283799): apply the spans to the text
return translatedText;
}
}
private static CharSequence ellipsize(CharSequence text, int newLength) {
if (text.length() <= newLength) {
return text;
}
String ellipsis = String.valueOf('\u2026');
if (newLength == 1) {
return ellipsis;
}
return TextUtils.concat(TextUtils.trimToSize(text, newLength - 1), ellipsis);
}
@Override
public void onFocusChanged(View view, CharSequence sourceText,
boolean focused, int direction,

View File

@@ -362,17 +362,20 @@ public class UiTranslationController {
continue;
}
mActivity.runOnUiThread(() -> {
if (view.getViewTranslationCallback() == null) {
final ViewTranslationCallback callback = view.getViewTranslationCallback();
if (callback == null) {
if (DEBUG) {
Log.d(TAG, view + " doesn't support showing translation because of "
+ "null ViewTranslationCallback.");
}
return;
}
// TODO: Do this for specific views on request only.
callback.enableContentPadding();
view.onTranslationResponse(response);
if (view.getViewTranslationCallback() != null) {
view.getViewTranslationCallback().onShowTranslation(view);
}
callback.onShowTranslation(view);
});
}
}

View File

@@ -48,4 +48,16 @@ public interface ViewTranslationCallback {
* @return {@code true} if the View handles clearing the translation.
*/
boolean onClearTranslation(@NonNull View view);
/**
* Enables padding on the view's original content.
* <p>
* This is useful when we do not modify the content directly, rather use a mechanism like
* {@link android.text.method.TransformationMethod}. If the app misbehaves when the displayed
* translation and the underlying content have different sizes, the platform intelligence can
* request that the original content be padded to make the sizes match.
*
* @hide
*/
default void enableContentPadding() {}
}

View File

@@ -770,6 +770,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
private final boolean mUseInternationalizedInput;
// True if fallback fonts that end up getting used should be allowed to affect line spacing.
/* package */ boolean mUseFallbackLineSpacing;
// True if the view text can be padded for compat reasons, when the view is translated.
private final boolean mUseTextPaddingForUiTranslation;
@ViewDebug.ExportedProperty(category = "text")
@UnsupportedAppUsage
@@ -1480,6 +1482,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
final int targetSdkVersion = context.getApplicationInfo().targetSdkVersion;
mUseInternationalizedInput = targetSdkVersion >= VERSION_CODES.O;
mUseFallbackLineSpacing = targetSdkVersion >= VERSION_CODES.P;
// TODO(b/179693024): Use a ChangeId instead.
mUseTextPaddingForUiTranslation = targetSdkVersion <= Build.VERSION_CODES.R;
if (inputMethod != null) {
Class<?> c;
@@ -2372,6 +2376,12 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
@ViewDebug.CapturedViewProperty
@InspectableProperty
public CharSequence getText() {
if (mUseTextPaddingForUiTranslation
&& mDefaultTranslationCallback != null
&& mDefaultTranslationCallback.isTextPaddingEnabled()
&& mDefaultTranslationCallback.isShowingTranslation()) {
return mDefaultTranslationCallback.getPaddedText(mText, mTransformed);
}
return mText;
}

View File

@@ -17,6 +17,7 @@
package android.widget;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.Build;
import android.text.method.TranslationTransformationMethod;
import android.util.Log;
@@ -33,7 +34,7 @@ import android.view.translation.ViewTranslationResponse;
*/
public class TextViewTranslationCallback implements ViewTranslationCallback {
private static final String TAG = "TextViewTranslationCallback";
private static final String TAG = "TextViewTranslationCb";
// TODO(b/182433547): remove Build.IS_DEBUGGABLE before ship. Enable the logging in debug build
// to help the debug during the development phase
@@ -41,6 +42,9 @@ public class TextViewTranslationCallback implements ViewTranslationCallback {
|| Build.IS_DEBUGGABLE;
private TranslationTransformationMethod mTranslationTransformation;
private boolean mIsShowingTranslation = false;
private boolean mIsTextPaddingEnabled = false;
private CharSequence mPaddedText;
/**
* Invoked by the platform when receiving the successful {@link ViewTranslationResponse} for the
@@ -74,6 +78,7 @@ public class TextViewTranslationCallback implements ViewTranslationCallback {
*/
@Override
public boolean onShowTranslation(@NonNull View view) {
mIsShowingTranslation = true;
if (mTranslationTransformation != null) {
((TextView) view).setTransformationMethod(mTranslationTransformation);
} else {
@@ -90,6 +95,7 @@ public class TextViewTranslationCallback implements ViewTranslationCallback {
*/
@Override
public boolean onHideTranslation(@NonNull View view) {
mIsShowingTranslation = false;
// Restore to original text content.
if (mTranslationTransformation != null) {
((TextView) view).setTransformationMethod(
@@ -110,9 +116,9 @@ public class TextViewTranslationCallback implements ViewTranslationCallback {
public boolean onClearTranslation(@NonNull View view) {
// Restore to original text content and clear TranslationTransformation
if (mTranslationTransformation != null) {
((TextView) view).setTransformationMethod(
mTranslationTransformation.getOriginalTransformationMethod());
onHideTranslation(view);
clearTranslationTransformation();
mPaddedText = null;
} else {
if (DEBUG) {
// TODO(b/182433547): remove before S release
@@ -121,4 +127,59 @@ public class TextViewTranslationCallback implements ViewTranslationCallback {
}
return true;
}
boolean isShowingTranslation() {
return mIsShowingTranslation;
}
@Override
public void enableContentPadding() {
mIsTextPaddingEnabled = true;
}
/**
* Returns whether readers of the view text should receive padded text for compatibility
* reasons. The view's original text will be padded to match the length of the translated text.
*/
boolean isTextPaddingEnabled() {
return mIsTextPaddingEnabled;
}
/**
* Returns the view's original text with padding added. If the translated text isn't longer than
* the original text, returns the original text itself.
*
* @param text the view's original text
* @param translatedText the view's translated text
* @see #isTextPaddingEnabled()
*/
@Nullable
CharSequence getPaddedText(CharSequence text, CharSequence translatedText) {
if (text == null) {
return null;
}
if (mPaddedText == null) {
mPaddedText = computePaddedText(text, translatedText);
}
return mPaddedText;
}
@NonNull
private CharSequence computePaddedText(CharSequence text, CharSequence translatedText) {
if (translatedText == null) {
return text;
}
int newLength = translatedText.length();
if (newLength <= text.length()) {
return text;
}
StringBuilder sb = new StringBuilder(newLength);
sb.append(text);
for (int i = text.length(); i < newLength; i++) {
sb.append(COMPAT_PAD_CHARACTER);
}
return sb;
}
private static final char COMPAT_PAD_CHARACTER = '\u2002';
}