From feb36772c74b0d22d02f8bff04d71f682aaf3c62 Mon Sep 17 00:00:00 2001 From: Ahaan Ugale Date: Fri, 15 Jan 2021 17:37:05 -0800 Subject: [PATCH] Add APIs that can notify client ui translation state. The initial APIs for ui translation. There is no implementation in this change, we will implement it in the next CL. Bug: 172969740 Bug: 176871912 Test: manual. build pass and build success. Change-Id: I4ae0bc7a695076a87bed73e458396312d87f48c5 --- core/api/system-current.txt | 13 ++ .../android/app/SystemServiceRegistry.java | 14 ++ core/java/android/content/Context.java | 9 + .../view/translation/ITranslationManager.aidl | 9 + .../translation/UiTranslationManager.java | 179 ++++++++++++++++++ core/res/AndroidManifest.xml | 9 + .../TranslationManagerService.java | 17 ++ .../TranslationManagerServiceImpl.java | 10 + 8 files changed, 260 insertions(+) create mode 100644 core/java/android/view/translation/UiTranslationManager.java diff --git a/core/api/system-current.txt b/core/api/system-current.txt index 730fce7c049a2..141a78f4d47f1 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -137,6 +137,7 @@ package android { field public static final String MANAGE_SOUND_TRIGGER = "android.permission.MANAGE_SOUND_TRIGGER"; field public static final String MANAGE_SUBSCRIPTION_PLANS = "android.permission.MANAGE_SUBSCRIPTION_PLANS"; field public static final String MANAGE_TIME_AND_ZONE_DETECTION = "android.permission.MANAGE_TIME_AND_ZONE_DETECTION"; + field public static final String MANAGE_UI_TRANSLATION = "android.permission.MANAGE_UI_TRANSLATION"; field public static final String MANAGE_USB = "android.permission.MANAGE_USB"; field public static final String MANAGE_USERS = "android.permission.MANAGE_USERS"; field public static final String MANAGE_USER_OEM_UNLOCK_STATE = "android.permission.MANAGE_USER_OEM_UNLOCK_STATE"; @@ -1943,6 +1944,7 @@ package android.content { field public static final String SYSTEM_UPDATE_SERVICE = "system_update"; field public static final String TETHERING_SERVICE = "tethering"; field public static final String TRANSLATION_MANAGER_SERVICE = "transformer"; + field public static final String UI_TRANSLATION_SERVICE = "ui_translation"; field public static final String VR_SERVICE = "vrmanager"; field public static final String WIFI_NL80211_SERVICE = "wifinl80211"; field @Deprecated public static final String WIFI_RTT_SERVICE = "rttmanager"; @@ -13405,6 +13407,17 @@ package android.view.contentcapture { } +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 pauseTranslation(int); + method @RequiresPermission(android.Manifest.permission.MANAGE_UI_TRANSLATION) public void resumeTranslation(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, int); + } + +} + package android.webkit { public abstract class CookieManager { diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java index dd016a2cf78e3..e62cd4f601866 100644 --- a/core/java/android/app/SystemServiceRegistry.java +++ b/core/java/android/app/SystemServiceRegistry.java @@ -211,6 +211,7 @@ import android.view.textclassifier.TextClassificationManager; import android.view.textservice.TextServicesManager; import android.view.translation.ITranslationManager; import android.view.translation.TranslationManager; +import android.view.translation.UiTranslationManager; import com.android.internal.app.IAppOpsService; import com.android.internal.app.IBatteryStats; @@ -1188,6 +1189,19 @@ public final class SystemServiceRegistry { return null; }}); + registerService(Context.UI_TRANSLATION_SERVICE, UiTranslationManager.class, + new CachedServiceFetcher() { + @Override + public UiTranslationManager createService(ContextImpl ctx) + throws ServiceNotFoundException { + IBinder b = ServiceManager.getService(Context.TRANSLATION_MANAGER_SERVICE); + ITranslationManager service = ITranslationManager.Stub.asInterface(b); + if (service != null) { + return new UiTranslationManager(ctx.getOuterContext(), service); + } + return null; + }}); + registerService(Context.SEARCH_UI_SERVICE, SearchUiManager.class, new CachedServiceFetcher() { @Override diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index 5ccceca9a69dc..5736985b92203 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -4519,6 +4519,15 @@ public abstract class Context { @SuppressLint("ServiceName") public static final String TRANSLATION_MANAGER_SERVICE = "transformer"; + /** + * Official published name of the translation service which supports ui translation function. + * + * @hide + * @see #getSystemService(String) + */ + @SystemApi + public static final String UI_TRANSLATION_SERVICE = "ui_translation"; + /** * Used for getting content selections and classifications for task snapshots. * diff --git a/core/java/android/view/translation/ITranslationManager.aidl b/core/java/android/view/translation/ITranslationManager.aidl index 73addf4d18944..e1754531d761f 100644 --- a/core/java/android/view/translation/ITranslationManager.aidl +++ b/core/java/android/view/translation/ITranslationManager.aidl @@ -16,10 +16,15 @@ package android.view.translation; +import android.content.ComponentName; +import android.os.IBinder; import android.service.translation.TranslationRequest; +import android.view.autofill.AutofillId; import android.view.translation.TranslationSpec; import com.android.internal.os.IResultReceiver; +import java.util.List; + /** * Mediator between apps being translated and translation service implementation. * @@ -29,4 +34,8 @@ oneway interface ITranslationManager { void getSupportedLocales(in IResultReceiver receiver, int userId); void onSessionCreated(in TranslationSpec sourceSpec, in TranslationSpec destSpec, int sessionId, in IResultReceiver receiver, int userId); + + void updateUiTranslationState(int state, in TranslationSpec sourceSpec, + in TranslationSpec destSpec, in List viewIds, in int taskId, + int userId); } diff --git a/core/java/android/view/translation/UiTranslationManager.java b/core/java/android/view/translation/UiTranslationManager.java new file mode 100644 index 0000000000000..eeb463ae0ed38 --- /dev/null +++ b/core/java/android/view/translation/UiTranslationManager.java @@ -0,0 +1,179 @@ +/* + * Copyright (C) 2020 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.IntDef; +import android.annotation.NonNull; +import android.annotation.RequiresPermission; +import android.annotation.SystemApi; +import android.content.Context; +import android.os.RemoteException; +import android.view.View; +import android.view.autofill.AutofillId; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.List; +import java.util.Objects; + +/** + * The {@link UiTranslationManager} class provides ways for apps to use the ui translation + * function in framework. + * + * @hide + */ +@SystemApi +public final class UiTranslationManager { + + private static final String TAG = "UiTranslationManager"; + + /** + * The state caller request to disable utranslation,, it is no longer need to ui translation. + * + * @hide + */ + public static final int STATE_UI_TRANSLATION_STARTED = 0; + /** + * The state caller request to pause ui translation, it will switch back to the original text. + * + * @hide + */ + public static final int STATE_UI_TRANSLATION_PAUSED = 1; + /** + * The state caller request to resume the paused ui translation, it will show the translated + * text again if the text had been translated. + * + * @hide + */ + public static final int STATE_UI_TRANSLATION_RESUMED = 2; + /** + * The state the caller request to enable ui translation. + * + * @hide + */ + public static final int STATE_UI_TRANSLATION_FINISHED = 3; + /** + * @hide + */ + @IntDef(prefix = {"STATE__TRANSLATION"}, value = { + STATE_UI_TRANSLATION_STARTED, + STATE_UI_TRANSLATION_PAUSED, + STATE_UI_TRANSLATION_RESUMED, + STATE_UI_TRANSLATION_FINISHED + }) + @Retention(RetentionPolicy.SOURCE) + public @interface UiTranslationState { + } + + @NonNull + private final Context mContext; + + private final ITranslationManager mService; + + /** + * @hide + */ + public UiTranslationManager(@NonNull Context context, ITranslationManager service) { + mContext = Objects.requireNonNull(context); + mService = service; + } + + /** + * 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 taskId the Activity Task id which needs ui translation + */ + @RequiresPermission(android.Manifest.permission.MANAGE_UI_TRANSLATION) + public void startTranslation(@NonNull TranslationSpec sourceSpec, + @NonNull TranslationSpec destSpec, @NonNull List 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, 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); + + try { + mService.updateUiTranslationState(STATE_UI_TRANSLATION_STARTED, sourceSpec, + destSpec, 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 taskId the Activity Task id which needs ui translation + */ + @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, + null /* sourceSpec */, null /* destSpec*/, null /* viewIds */, taskId, + 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. + * + * @param taskId the Activity Task id which needs ui translation + */ + @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, + 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 taskId the Activity Task id which needs ui translation + */ + @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, + null /* sourceSpec */, null /* destSpec*/, null /* viewIds */, + taskId, mContext.getUserId()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } +} diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index c18e15ef9f5c7..05fbe4baba1ab 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -3599,6 +3599,15 @@ + + +