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

Commit 1ad35bc9 authored by Joanne Chung's avatar Joanne Chung Committed by Automerger Merge Worker
Browse files

Merge "Update UiTranslationManager APIs to use contentcapture token parameter"...

Merge "Update UiTranslationManager APIs to use contentcapture token parameter" into sc-dev am: 81db998f

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/13451768

MUST ONLY BE SUBMITTED BY AUTOMERGER

Change-Id: I60ea2916c7d7841890151bf9e1ead2643c67aa77
parents be6a9558 81db998f
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -14068,9 +14068,13 @@ package android.view.translation {
  public final class UiTranslationManager {
    method @RequiresPermission(android.Manifest.permission.MANAGE_UI_TRANSLATION) public void finishTranslation(int);
    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(int);
    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(int);
    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>, int);
    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);
  }
}
+5 −1
Original line number Diff line number Diff line
@@ -36,6 +36,10 @@ oneway interface ITranslationManager {
         int sessionId, in IResultReceiver receiver, int userId);

    void updateUiTranslationState(int state, in TranslationSpec sourceSpec,
         in TranslationSpec destSpec, in List<AutofillId> viewIds, in int taskId,
         in TranslationSpec destSpec, in List<AutofillId> viewIds, IBinder token, int taskId,
         int userId);
    // deprecated
    void updateUiTranslationStateByTaskId(int state, in TranslationSpec sourceSpec,
         in TranslationSpec destSpec, in List<AutofillId> viewIds, int taskId,
         int userId);
}
+116 −14
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@ import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.app.assist.ActivityId;
import android.content.Context;
import android.os.RemoteException;
import android.view.View;
@@ -95,26 +96,61 @@ public final class UiTranslationManager {
    /**
     * Request ui translation for a given Views.
     *
     * NOTE: Please use {@code startTranslation(TranslationSpec, TranslationSpec, List<AutofillId>,
     * ActivityId)} instead.
     *
     * @param sourceSpec {@link TranslationSpec} for the data to be translated.
     * @param destSpec {@link TranslationSpec} for the translated data.
     * @param viewIds A list of the {@link View}'s {@link AutofillId} which needs to be translated
     * @param taskId the Activity Task id which needs ui translation
     */
    // TODO, hide the APIs
    @RequiresPermission(android.Manifest.permission.MANAGE_UI_TRANSLATION)
    public void startTranslation(@NonNull TranslationSpec sourceSpec,
            @NonNull TranslationSpec destSpec, @NonNull List<AutofillId> viewIds,
            int taskId) {
        // TODO(b/177789967): Return result code or find a way to notify the status.
        // TODO(b/177394471): The is a temparary API, the expected is requestUiTranslation(
        //  TranslationSpec, TranslationSpec,List<AutofillId>, Binder). We may need more time to
        //  implement it, use task id as initial version for demo.
        Objects.requireNonNull(sourceSpec);
        Objects.requireNonNull(destSpec);
        Objects.requireNonNull(viewIds);
        if (viewIds.size() == 0) {
            throw new IllegalArgumentException("Invalid empty views: " + viewIds);
        }
        try {
            mService.updateUiTranslationStateByTaskId(STATE_UI_TRANSLATION_STARTED, sourceSpec,
                    destSpec, viewIds, taskId, mContext.getUserId());
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    /**
     * Request ui translation for a given Views.
     *
     * @param sourceSpec {@link TranslationSpec} for the data to be translated.
     * @param destSpec {@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
     * @throws IllegalArgumentException if the no {@link View}'s {@link AutofillId} in the list
     * @throws NullPointerException the sourceSpec, destSpec, viewIds, activityId or
     *         {@link android.app.assist.ActivityId#getToken()} is {@code null}
     */
    @RequiresPermission(android.Manifest.permission.MANAGE_UI_TRANSLATION)
    public void startTranslation(@NonNull TranslationSpec sourceSpec,
            @NonNull TranslationSpec destSpec, @NonNull List<AutofillId> viewIds,
            @NonNull ActivityId activityId) {
        // TODO(b/177789967): Return result code or find a way to notify the status.
        Objects.requireNonNull(sourceSpec);
        Objects.requireNonNull(destSpec);
        Objects.requireNonNull(viewIds);
        Objects.requireNonNull(activityId);
        Objects.requireNonNull(activityId.getToken());
        if (viewIds.size() == 0) {
            throw new IllegalArgumentException("Invalid empty views: " + viewIds);
        }
        try {
            mService.updateUiTranslationState(STATE_UI_TRANSLATION_STARTED, sourceSpec,
                    destSpec, viewIds, taskId, mContext.getUserId());
                    destSpec, viewIds, activityId.getToken(), activityId.getTaskId(),
                    mContext.getUserId());
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
@@ -124,14 +160,15 @@ public final class UiTranslationManager {
     * Request to disable the ui translation. It will destroy all the {@link Translator}s and no
     * longer to show to show the translated text.
     *
     * NOTE: Please use {@code finishTranslation(ActivityId)} instead.
     *
     * @param taskId the Activity Task id which needs ui translation
     */
    // TODO, hide the APIs
    @RequiresPermission(android.Manifest.permission.MANAGE_UI_TRANSLATION)
    public void finishTranslation(int taskId) {
        try {
            // TODO(b/177394471): The is a temparary API, the expected is finishUiTranslation(
            //  Binder). We may need more time to implement it, use task id as initial version.
            mService.updateUiTranslationState(STATE_UI_TRANSLATION_FINISHED,
            mService.updateUiTranslationStateByTaskId(STATE_UI_TRANSLATION_FINISHED,
                    null /* sourceSpec */, null /* destSpec*/, null /* viewIds */, taskId,
                    mContext.getUserId());
        } catch (RemoteException e) {
@@ -139,18 +176,40 @@ public final class UiTranslationManager {
        }
    }

    /**
     * Request to disable the ui translation. It will destroy all the {@link Translator}s and no
     * longer to show to show the translated text.
     *
     * @param activityId the identifier for the Activity which needs ui translation
     * @throws NullPointerException the activityId or
     *         {@link android.app.assist.ActivityId#getToken()} is {@code null}
     */
    @RequiresPermission(android.Manifest.permission.MANAGE_UI_TRANSLATION)
    public void finishTranslation(@NonNull ActivityId activityId) {
        try {
            Objects.requireNonNull(activityId);
            Objects.requireNonNull(activityId.getToken());
            mService.updateUiTranslationState(STATE_UI_TRANSLATION_FINISHED,
                    null /* sourceSpec */, null /* destSpec*/, null /* viewIds */,
                    activityId.getToken(), activityId.getTaskId(), mContext.getUserId());
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    /**
     * Request to pause the current ui translation's {@link Translator} which will switch back to
     * the original language.
     *
     * NOTE: Please use {@code pauseTranslation(ActivityId)} instead.
     *
     * @param taskId the Activity Task id which needs ui translation
     */
    // TODO, hide the APIs
    @RequiresPermission(android.Manifest.permission.MANAGE_UI_TRANSLATION)
    public void pauseTranslation(int taskId) {
        try {
            // TODO(b/177394471): The is a temparary API, the expected is pauseUiTranslation(Binder)
            // We may need more time to implement it, use task id as initial version for demo
            mService.updateUiTranslationState(STATE_UI_TRANSLATION_PAUSED,
            mService.updateUiTranslationStateByTaskId(STATE_UI_TRANSLATION_PAUSED,
                    null /* sourceSpec */, null /* destSpec*/, null /* viewIds */, taskId,
                    mContext.getUserId());
        } catch (RemoteException e) {
@@ -158,22 +217,65 @@ public final class UiTranslationManager {
        }
    }

    /**
     * Request to pause the current ui translation's {@link Translator} which will switch back to
     * the original language.
     *
     * @param activityId the identifier for the Activity which needs ui translation
     * @throws NullPointerException the activityId or
     *         {@link android.app.assist.ActivityId#getToken()} is {@code null}
     */
    @RequiresPermission(android.Manifest.permission.MANAGE_UI_TRANSLATION)
    public void pauseTranslation(@NonNull ActivityId activityId) {
        try {
            Objects.requireNonNull(activityId);
            Objects.requireNonNull(activityId.getToken());
            mService.updateUiTranslationState(STATE_UI_TRANSLATION_PAUSED,
                    null /* sourceSpec */, null /* destSpec*/, null /* viewIds */,
                    activityId.getToken(), activityId.getTaskId(), mContext.getUserId());
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    /**
     * Request to resume the paused ui translation's {@link Translator} which will switch to the
     * translated language if the text had been translated.
     *
     * NOTE: Please use {@code resumeTranslation(ActivityId)} instead.
     *
     * @param taskId the Activity Task id which needs ui translation
     */
    // TODO, hide the APIs
    @RequiresPermission(android.Manifest.permission.MANAGE_UI_TRANSLATION)
    public void resumeTranslation(int taskId) {
        try {
            // TODO(b/177394471): The is a temparary API, the expected is resumeUiTranslation(
            //  Binder). We may need more time to implement it, use task id as initial version.
            mService.updateUiTranslationState(STATE_UI_TRANSLATION_RESUMED,
            mService.updateUiTranslationStateByTaskId(STATE_UI_TRANSLATION_RESUMED,
                    null /* sourceSpec */, null /* destSpec*/, null /* viewIds */,
                    taskId, mContext.getUserId());
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    /**
     * Request to resume the paused ui translation's {@link Translator} which will switch to the
     * translated language if the text had been translated.
     *
     * @param activityId the identifier for the Activity which needs ui translation
     * @throws NullPointerException the activityId or
     *         {@link android.app.assist.ActivityId#getToken()} is {@code null}
     */
    @RequiresPermission(android.Manifest.permission.MANAGE_UI_TRANSLATION)
    public void resumeTranslation(@NonNull ActivityId activityId) {
        try {
            Objects.requireNonNull(activityId);
            Objects.requireNonNull(activityId.getToken());
            mService.updateUiTranslationState(STATE_UI_TRANSLATION_RESUMED,
                    null /* sourceSpec */, null /* destSpec*/, null /* viewIds */,
                    activityId.getToken(), activityId.getTaskId(), mContext.getUserId());
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }
}
+21 −3
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.ShellCallback;
@@ -171,20 +172,37 @@ public final class TranslationManagerService
        }

        @Override
        public void updateUiTranslationState(@UiTranslationState int state,
        public void updateUiTranslationStateByTaskId(@UiTranslationState int state,
                TranslationSpec sourceSpec, TranslationSpec destSpec, List<AutofillId> viewIds,
                int taskId, int userId) {
            // deprecated
            enforceCallerHasPermission(MANAGE_UI_TRANSLATION);
            synchronized (mLock) {
                final TranslationManagerServiceImpl service = getServiceForUserLocked(userId);
                if (service != null && (isDefaultServiceLocked(userId)
                        || isCalledByServiceAppLocked(userId, "updateUiTranslationState"))) {
                    service.updateUiTranslationState(state, sourceSpec, destSpec, viewIds,
                        || isCalledByServiceAppLocked(userId,
                        "updateUiTranslationStateByTaskId"))) {
                    service.updateUiTranslationStateLocked(state, sourceSpec, destSpec, viewIds,
                            taskId);
                }
            }
        }

        @Override
        public void updateUiTranslationState(@UiTranslationState int state,
                TranslationSpec sourceSpec, TranslationSpec destSpec, List<AutofillId> viewIds,
                IBinder token, int taskId, int userId) {
            enforceCallerHasPermission(MANAGE_UI_TRANSLATION);
            synchronized (mLock) {
                final TranslationManagerServiceImpl service = getServiceForUserLocked(userId);
                if (service != null && (isDefaultServiceLocked(userId)
                        || isCalledByServiceAppLocked(userId, "updateUiTranslationState"))) {
                    service.updateUiTranslationStateLocked(state, sourceSpec, destSpec, viewIds,
                            token, taskId);
                }
            }
        }

        /**
         * Dump the service state into the given stream. You run "adb shell dumpsys translation".
        */
+30 −7
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@ import android.annotation.Nullable;
import android.content.ComponentName;
import android.content.pm.PackageManager;
import android.content.pm.ServiceInfo;
import android.os.IBinder;
import android.os.RemoteException;
import android.service.translation.TranslationServiceInfo;
import android.util.Slog;
@@ -133,18 +134,40 @@ final class TranslationManagerServiceImpl extends
    }

    @GuardedBy("mLock")
    public void updateUiTranslationState(@UiTranslationState int state,
    public void updateUiTranslationStateLocked(@UiTranslationState int state,
            TranslationSpec sourceSpec, TranslationSpec destSpec, List<AutofillId> viewIds,
            int taskId) {
        // TODO(b/177394471): use taskId as a temporary solution. The solution may use a token to
        //  content capture manager service find the activitytoken. Then we can use this
        //  activitytoken to find the activity to callback. But we need to change cc API so use
        //  temporary solution.
        final ActivityTokens tokens = mActivityTaskManagerInternal.getTopActivityForTask(taskId);
        if (tokens == null) {
        // deprecated
        final ActivityTokens taskTopActivityTokens =
                mActivityTaskManagerInternal.getTopActivityForTask(taskId);
        if (taskTopActivityTokens == null) {
            Slog.w(TAG, "Unknown activity to query for update translation state.");
            return;
        }
        updateUiTranslationStateByActivityTokens(taskTopActivityTokens, state, sourceSpec, destSpec,
                viewIds);
    }

    @GuardedBy("mLock")
    public void updateUiTranslationStateLocked(@UiTranslationState int state,
            TranslationSpec sourceSpec, TranslationSpec destSpec, List<AutofillId> viewIds,
            IBinder token, int taskId) {
        // Get top activity for a given task id
        final ActivityTokens taskTopActivityTokens =
                mActivityTaskManagerInternal.getTopActivityForTask(taskId);
        if (taskTopActivityTokens == null
                || taskTopActivityTokens.getShareableActivityToken() != token) {
            Slog.w(TAG, "Unknown activity or it was finished to query for update "
                    + "translation state for token=" + token + " taskId=" + taskId);
            return;
        }
        updateUiTranslationStateByActivityTokens(taskTopActivityTokens, state, sourceSpec, destSpec,
                viewIds);
    }

    private void updateUiTranslationStateByActivityTokens(ActivityTokens tokens,
            @UiTranslationState int state, TranslationSpec sourceSpec, TranslationSpec destSpec,
            List<AutofillId> viewIds) {
        try {
            tokens.getApplicationThread().updateUiTranslationState(tokens.getActivityToken(), state,
                    sourceSpec, destSpec, viewIds);