Update UiTranslationManager APIs to use contentcapture token parameter

1. Update UiTranslationManager APIs to use ActivityId parameter
2. Keep old APIs definition until AiAi is ready for new APIs.

Bug: 177789967
Test: manual. Local add test app in allow list, and get token from local
content capture service and use it in UiTranslationManager api.

Change-Id: I96aa5704600fd9b81eff7a2f42eefe78a43112da
This commit is contained in:
Joanne Chung
2021-02-01 22:59:09 +08:00
parent 7e3f7d1061
commit 19006134b3
5 changed files with 178 additions and 27 deletions

View File

@@ -14062,9 +14062,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);
}
}

View File

@@ -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);
}

View File

@@ -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,56 @@ 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.updateUiTranslationStateByTaskId(STATE_UI_TRANSLATION_FINISHED,
null /* sourceSpec */, null /* destSpec*/, null /* viewIds */, taskId,
mContext.getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/**
* 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 {
mService.updateUiTranslationStateByTaskId(STATE_UI_TRANSLATION_PAUSED,
null /* sourceSpec */, null /* destSpec*/, null /* viewIds */, taskId,
mContext.getUserId());
} catch (RemoteException e) {
@@ -143,16 +221,18 @@ public final class UiTranslationManager {
* Request to pause the current ui translation's {@link Translator} which will switch back to
* the original language.
*
* @param taskId the Activity Task id which needs ui translation
* @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(int taskId) {
public void pauseTranslation(@NonNull ActivityId activityId) {
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
Objects.requireNonNull(activityId);
Objects.requireNonNull(activityId.getToken());
mService.updateUiTranslationState(STATE_UI_TRANSLATION_PAUSED,
null /* sourceSpec */, null /* destSpec*/, null /* viewIds */, taskId,
mContext.getUserId());
null /* sourceSpec */, null /* destSpec*/, null /* viewIds */,
activityId.getToken(), activityId.getTaskId(), mContext.getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -162,18 +242,40 @@ public final class UiTranslationManager {
* 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();
}
}
}

View File

@@ -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,16 +172,33 @@ 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,
"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.updateUiTranslationState(state, sourceSpec, destSpec, viewIds,
taskId);
service.updateUiTranslationStateLocked(state, sourceSpec, destSpec, viewIds,
token, taskId);
}
}
}

View File

@@ -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);