Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8dc9a795 authored by Ahaan Ugale's avatar Ahaan Ugale
Browse files

Translate: API for content padding.

This allows controlling the content padding behavior needed with some
apps for compatibility reasons.
(see I9d7db5d2bc200e4042baf3267796f00cfc298f19)

The flag is currently the only property in the new UiTranslationSpec
value type, but more properties can be added in the future (such as
animation specifications).

Bug: 179693024
Test: manual
CTS-Coverage-Bug: 182990474
Change-Id: I11052cddb59c928b22ad9ad16e3c9b092da4b907
parent 463493f5
Loading
Loading
Loading
Loading
+15 −1
Original line number Diff line number Diff line
@@ -14454,7 +14454,21 @@ package android.view.translation {
    method @RequiresPermission(android.Manifest.permission.MANAGE_UI_TRANSLATION) public void finishTranslation(@NonNull android.app.assist.ActivityId);
    method @RequiresPermission(android.Manifest.permission.MANAGE_UI_TRANSLATION) public void pauseTranslation(@NonNull android.app.assist.ActivityId);
    method @RequiresPermission(android.Manifest.permission.MANAGE_UI_TRANSLATION) public void resumeTranslation(@NonNull android.app.assist.ActivityId);
    method @RequiresPermission(android.Manifest.permission.MANAGE_UI_TRANSLATION) public void startTranslation(@NonNull android.view.translation.TranslationSpec, @NonNull android.view.translation.TranslationSpec, @NonNull java.util.List<android.view.autofill.AutofillId>, @NonNull android.app.assist.ActivityId);
    method @Deprecated @RequiresPermission(android.Manifest.permission.MANAGE_UI_TRANSLATION) public void startTranslation(@NonNull android.view.translation.TranslationSpec, @NonNull android.view.translation.TranslationSpec, @NonNull java.util.List<android.view.autofill.AutofillId>, @NonNull android.app.assist.ActivityId);
    method @RequiresPermission(android.Manifest.permission.MANAGE_UI_TRANSLATION) public void startTranslation(@NonNull android.view.translation.TranslationSpec, @NonNull android.view.translation.TranslationSpec, @NonNull java.util.List<android.view.autofill.AutofillId>, @NonNull android.app.assist.ActivityId, @NonNull android.view.translation.UiTranslationSpec);
  }
  public final class UiTranslationSpec implements android.os.Parcelable {
    method public int describeContents();
    method public boolean shouldPadContentForCompat();
    method public void writeToParcel(@NonNull android.os.Parcel, int);
    field @NonNull public static final android.os.Parcelable.Creator<android.view.translation.UiTranslationSpec> CREATOR;
  }
  public static final class UiTranslationSpec.Builder {
    ctor public UiTranslationSpec.Builder();
    method @NonNull public android.view.translation.UiTranslationSpec build();
    method @NonNull public android.view.translation.UiTranslationSpec.Builder setShouldPadContentForCompat(boolean);
  }
}
+2 −1
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ import android.os.ResultReceiver;
import android.view.autofill.AutofillId;
import android.view.translation.TranslationContext;
import android.view.translation.TranslationSpec;
import android.view.translation.UiTranslationSpec;
import com.android.internal.os.IResultReceiver;

import java.util.List;
@@ -39,7 +40,7 @@ oneway interface ITranslationManager {

    void updateUiTranslationState(int state, in TranslationSpec sourceSpec,
         in TranslationSpec targetSpec, in List<AutofillId> viewIds, IBinder token, int taskId,
         int userId);
         in UiTranslationSpec uiTranslationSpec, int userId);

    void registerUiTranslationStateCallback(in IRemoteCallback callback, int userId);
    void unregisterUiTranslationStateCallback(in IRemoteCallback callback, int userId);
+27 −6
Original line number Diff line number Diff line
@@ -118,6 +118,23 @@ public final class UiTranslationManager {
        mService = service;
    }

    /**
     * @deprecated Use {@link #startTranslation(TranslationSpec, TranslationSpec, List, ActivityId,
     * UiTranslationSpec)} instead.
     *
     * @hide
     */
    @RequiresPermission(android.Manifest.permission.MANAGE_UI_TRANSLATION)
    @Deprecated
    @SystemApi
    public void startTranslation(@NonNull TranslationSpec sourceSpec,
            @NonNull TranslationSpec targetSpec, @NonNull List<AutofillId> viewIds,
            @NonNull ActivityId activityId) {
        startTranslation(
                sourceSpec, targetSpec, viewIds, activityId,
                new UiTranslationSpec.Builder().setShouldPadContentForCompat(true).build());
    }

    /**
     * Request ui translation for a given Views.
     *
@@ -125,9 +142,8 @@ public final class UiTranslationManager {
     * @param targetSpec {@link TranslationSpec} for the translated data.
     * @param viewIds A list of the {@link View}'s {@link AutofillId} which needs to be translated
     * @param activityId the identifier for the Activity which needs ui translation
     * @param uiTranslationSpec configuration for translation of the specified views
     * @throws IllegalArgumentException if the no {@link View}'s {@link AutofillId} in the list
     * @throws NullPointerException the sourceSpec, targetSpec, viewIds, activityId or
     *         {@link android.app.assist.ActivityId#getToken()} is {@code null}
     *
     * @hide
     */
@@ -135,19 +151,21 @@ public final class UiTranslationManager {
    @SystemApi
    public void startTranslation(@NonNull TranslationSpec sourceSpec,
            @NonNull TranslationSpec targetSpec, @NonNull List<AutofillId> viewIds,
            @NonNull ActivityId activityId) {
            @NonNull ActivityId activityId, @NonNull UiTranslationSpec uiTranslationSpec) {
        // TODO(b/177789967): Return result code or find a way to notify the status.
        Objects.requireNonNull(sourceSpec);
        Objects.requireNonNull(targetSpec);
        Objects.requireNonNull(viewIds);
        Objects.requireNonNull(activityId);
        Objects.requireNonNull(activityId.getToken());
        Objects.requireNonNull(uiTranslationSpec);
        if (viewIds.size() == 0) {
            throw new IllegalArgumentException("Invalid empty views: " + viewIds);
        }
        try {
            mService.updateUiTranslationState(STATE_UI_TRANSLATION_STARTED, sourceSpec,
                    targetSpec, viewIds, activityId.getToken(), activityId.getTaskId(),
                    uiTranslationSpec,
                    mContext.getUserId());
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
@@ -172,7 +190,8 @@ public final class UiTranslationManager {
            Objects.requireNonNull(activityId.getToken());
            mService.updateUiTranslationState(STATE_UI_TRANSLATION_FINISHED,
                    null /* sourceSpec */, null /* targetSpec */, null /* viewIds */,
                    activityId.getToken(), activityId.getTaskId(), mContext.getUserId());
                    activityId.getToken(), activityId.getTaskId(), null /* uiTranslationSpec */,
                    mContext.getUserId());
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
@@ -196,7 +215,8 @@ public final class UiTranslationManager {
            Objects.requireNonNull(activityId.getToken());
            mService.updateUiTranslationState(STATE_UI_TRANSLATION_PAUSED,
                    null /* sourceSpec */, null /* targetSpec */, null /* viewIds */,
                    activityId.getToken(), activityId.getTaskId(), mContext.getUserId());
                    activityId.getToken(), activityId.getTaskId(), null /* uiTranslationSpec */,
                    mContext.getUserId());
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
@@ -220,7 +240,8 @@ public final class UiTranslationManager {
            Objects.requireNonNull(activityId.getToken());
            mService.updateUiTranslationState(STATE_UI_TRANSLATION_RESUMED,
                    null /* sourceSpec */, null /* targetSpec */, null /* viewIds */,
                    activityId.getToken(), activityId.getTaskId(), mContext.getUserId());
                    activityId.getToken(), activityId.getTaskId(), null /* uiTranslationSpec */,
                    mContext.getUserId());
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
+19 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2021 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.view.translation;

parcelable UiTranslationSpec;
+248 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2021 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.view.translation;

import android.annotation.NonNull;
import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;

import com.android.internal.util.DataClass;

/**
 * Specifications for configuring UI translation.
 *
 * @hide
 */
@DataClass(
        genBuilder = true, genEqualsHashCode = true, genHiddenConstDefs = true, genToString = true)
@DataClass.Suppress("isShouldPadContentForCompat")
@SystemApi
public final class UiTranslationSpec implements Parcelable {

    /**
     * Whether the original content of the view should be directly modified to include padding that
     * makes it the same size as the translated content. Defaults to {@code false}.
     * <p>
     * For {@link android.widget.TextView}, the system does not directly modify the original text,
     * rather changes the displayed content using a
     * {@link android.text.method.TransformationMethod}.
     * This can cause issues in apps that do not account for TransformationMethods. For example, an
     * app using DynamicLayout may use the calculated text offsets to operate on the original text,
     * but this can be problematic when the layout was calculated on translated text with a
     * different length.
     * <p>
     * If this is {@code true}, for a TextView the default implementation will append spaces to the
     * text to make the length the same as the translated text.
     */
    private boolean mShouldPadContentForCompat = false;

    /**
     * Whether the original content of the view should be directly modified to include padding that
     * makes it the same size as the translated content.
     * <p>
     * For {@link android.widget.TextView}, the system does not directly modify the original text,
     * rather changes the displayed content using a
     * {@link android.text.method.TransformationMethod}.
     * This can cause issues in apps that do not account for TransformationMethods. For example, an
     * app using DynamicLayout may use the calculated text offsets to operate on the original text,
     * but this can be problematic when the layout was calculated on translated text with a
     * different length.
     * <p>
     * If this is {@code true}, for a TextView the default implementation will append spaces to the
     * text to make the length the same as the translated text.
     */
    public boolean shouldPadContentForCompat() {
        return mShouldPadContentForCompat;
    }



    // Code below generated by codegen v1.0.23.
    //
    // DO NOT MODIFY!
    // CHECKSTYLE:OFF Generated code
    //
    // To regenerate run:
    // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/view/translation/UiTranslationSpec.java
    //
    // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
    //   Settings > Editor > Code Style > Formatter Control
    //@formatter:off


    @DataClass.Generated.Member
    /* package-private */ UiTranslationSpec(
            boolean shouldPadContentForCompat) {
        this.mShouldPadContentForCompat = shouldPadContentForCompat;

        // onConstructed(); // You can define this method to get a callback
    }

    @Override
    @DataClass.Generated.Member
    public String toString() {
        // You can override field toString logic by defining methods like:
        // String fieldNameToString() { ... }

        return "UiTranslationSpec { " +
                "shouldPadContentForCompat = " + mShouldPadContentForCompat +
        " }";
    }

    @Override
    @DataClass.Generated.Member
    public boolean equals(@android.annotation.Nullable Object o) {
        // You can override field equality logic by defining either of the methods like:
        // boolean fieldNameEquals(UiTranslationSpec other) { ... }
        // boolean fieldNameEquals(FieldType otherValue) { ... }

        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        @SuppressWarnings("unchecked")
        UiTranslationSpec that = (UiTranslationSpec) o;
        //noinspection PointlessBooleanExpression
        return true
                && mShouldPadContentForCompat == that.mShouldPadContentForCompat;
    }

    @Override
    @DataClass.Generated.Member
    public int hashCode() {
        // You can override field hashCode logic by defining methods like:
        // int fieldNameHashCode() { ... }

        int _hash = 1;
        _hash = 31 * _hash + Boolean.hashCode(mShouldPadContentForCompat);
        return _hash;
    }

    @Override
    @DataClass.Generated.Member
    public void writeToParcel(@NonNull Parcel dest, int flags) {
        // You can override field parcelling by defining methods like:
        // void parcelFieldName(Parcel dest, int flags) { ... }

        byte flg = 0;
        if (mShouldPadContentForCompat) flg |= 0x1;
        dest.writeByte(flg);
    }

    @Override
    @DataClass.Generated.Member
    public int describeContents() { return 0; }

    /** @hide */
    @SuppressWarnings({"unchecked", "RedundantCast"})
    @DataClass.Generated.Member
    /* package-private */ UiTranslationSpec(@NonNull Parcel in) {
        // You can override field unparcelling by defining methods like:
        // static FieldType unparcelFieldName(Parcel in) { ... }

        byte flg = in.readByte();
        boolean shouldPadContentForCompat = (flg & 0x1) != 0;

        this.mShouldPadContentForCompat = shouldPadContentForCompat;

        // onConstructed(); // You can define this method to get a callback
    }

    @DataClass.Generated.Member
    public static final @NonNull Parcelable.Creator<UiTranslationSpec> CREATOR
            = new Parcelable.Creator<UiTranslationSpec>() {
        @Override
        public UiTranslationSpec[] newArray(int size) {
            return new UiTranslationSpec[size];
        }

        @Override
        public UiTranslationSpec createFromParcel(@NonNull Parcel in) {
            return new UiTranslationSpec(in);
        }
    };

    /**
     * A builder for {@link UiTranslationSpec}
     */
    @SuppressWarnings("WeakerAccess")
    @DataClass.Generated.Member
    public static final class Builder {

        private boolean mShouldPadContentForCompat;

        private long mBuilderFieldsSet = 0L;

        public Builder() {
        }

        /**
         * Whether the original content of the view should be directly modified to include padding that
         * makes it the same size as the translated content. Defaults to {@code false}.
         * <p>
         * For {@link android.widget.TextView}, the system does not directly modify the original text,
         * rather changes the displayed content using a
         * {@link android.text.method.TransformationMethod}.
         * This can cause issues in apps that do not account for TransformationMethods. For example, an
         * app using DynamicLayout may use the calculated text offsets to operate on the original text,
         * but this can be problematic when the layout was calculated on translated text with a
         * different length.
         * <p>
         * If this is {@code true}, for a TextView the default implementation will append spaces to the
         * text to make the length the same as the translated text.
         */
        @DataClass.Generated.Member
        public @NonNull Builder setShouldPadContentForCompat(boolean value) {
            checkNotUsed();
            mBuilderFieldsSet |= 0x1;
            mShouldPadContentForCompat = value;
            return this;
        }

        /** Builds the instance. This builder should not be touched after calling this! */
        public @NonNull UiTranslationSpec build() {
            checkNotUsed();
            mBuilderFieldsSet |= 0x2; // Mark builder used

            if ((mBuilderFieldsSet & 0x1) == 0) {
                mShouldPadContentForCompat = false;
            }
            UiTranslationSpec o = new UiTranslationSpec(
                    mShouldPadContentForCompat);
            return o;
        }

        private void checkNotUsed() {
            if ((mBuilderFieldsSet & 0x2) != 0) {
                throw new IllegalStateException(
                        "This Builder should not be reused. Use a new Builder instance instead");
            }
        }
    }

    @DataClass.Generated(
            time = 1619034161701L,
            codegenVersion = "1.0.23",
            sourceFile = "frameworks/base/core/java/android/view/translation/UiTranslationSpec.java",
            inputSignatures = "private  boolean mShouldPadContentForCompat\npublic  boolean shouldPadContentForCompat()\nclass UiTranslationSpec extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genBuilder=true, genEqualsHashCode=true, genHiddenConstDefs=true, genToString=true)")
    @Deprecated
    private void __metadata() {}


    //@formatter:on
    // End of generated code

}
Loading