Changed createOnDeviceTranslator to be asynchronous with callback.
Bug: 176208267
Test: atest CtsTranslationTestCases
Change-Id: Icedc953611e70dc208cbef54b4e459ebb0ccd5a9
diff --git a/core/api/current.txt b/core/api/current.txt
index 4cdc519..145719b 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -52839,7 +52839,8 @@
method public void addOnDeviceTranslationCapabilityUpdateListener(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.view.translation.TranslationCapability>);
method @Deprecated public void addOnDeviceTranslationCapabilityUpdateListener(int, int, @NonNull android.app.PendingIntent);
method @Deprecated public void addTranslationCapabilityUpdateListener(int, int, @NonNull android.app.PendingIntent);
- method @Nullable @WorkerThread public android.view.translation.Translator createOnDeviceTranslator(@NonNull android.view.translation.TranslationContext);
+ method public void createOnDeviceTranslator(@NonNull android.view.translation.TranslationContext, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.view.translation.Translator>);
+ method @Deprecated @Nullable @WorkerThread public android.view.translation.Translator createOnDeviceTranslator(@NonNull android.view.translation.TranslationContext);
method @Deprecated @Nullable @WorkerThread public android.view.translation.Translator createTranslator(@NonNull android.view.translation.TranslationContext);
method @NonNull @WorkerThread public java.util.Set<android.view.translation.TranslationCapability> getOnDeviceTranslationCapabilities(int, int);
method @Nullable public android.app.PendingIntent getOnDeviceTranslationSettingsActivityIntent();
diff --git a/core/java/android/view/translation/TranslationManager.java b/core/java/android/view/translation/TranslationManager.java
index e755774..20d817d 100644
--- a/core/java/android/view/translation/TranslationManager.java
+++ b/core/java/android/view/translation/TranslationManager.java
@@ -100,10 +100,6 @@
private final ITranslationManager mService;
- @Nullable
- @GuardedBy("mLock")
- private ITranslationDirectManager mDirectServiceBinder;
-
@NonNull
@GuardedBy("mLock")
private final SparseArray<Translator> mTranslators = new SparseArray<>();
@@ -131,11 +127,72 @@
/**
* Creates an on-device Translator for natural language translation.
*
+ * @param translationContext {@link TranslationContext} containing the specs for creating the
+ * Translator.
+ * @param executor Executor to run callback operations
+ * @param callback {@link Consumer} to receive the translator. A {@code null} value is returned
+ * if the service could not create the translator.
+ */
+ public void createOnDeviceTranslator(@NonNull TranslationContext translationContext,
+ @NonNull @CallbackExecutor Executor executor, @NonNull Consumer<Translator> callback) {
+ Objects.requireNonNull(translationContext, "translationContext cannot be null");
+ Objects.requireNonNull(executor, "executor cannot be null");
+ Objects.requireNonNull(callback, "callback cannot be null");
+
+ synchronized (mLock) {
+ // TODO(b/176464808): Disallow multiple Translator now, it will throw
+ // IllegalStateException. Need to discuss if we can allow multiple Translators.
+ if (mTranslatorIds.containsKey(translationContext)) {
+ executor.execute(() -> callback.accept(
+ mTranslators.get(mTranslatorIds.get(translationContext))));
+ return;
+ }
+
+ int translatorId;
+ do {
+ translatorId = Math.abs(ID_GENERATOR.nextInt());
+ } while (translatorId == 0 || mTranslators.indexOfKey(translatorId) >= 0);
+ final int tId = translatorId;
+
+ new Translator(mContext, translationContext, translatorId, this, mHandler, mService,
+ new Consumer<Translator>() {
+ @Override
+ public void accept(Translator translator) {
+ if (translator == null) {
+ final long token = Binder.clearCallingIdentity();
+ try {
+ executor.execute(() -> callback.accept(null));
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ return;
+ }
+
+ mTranslators.put(tId, translator);
+ mTranslatorIds.put(translationContext, tId);
+ final long token = Binder.clearCallingIdentity();
+ try {
+ executor.execute(() -> callback.accept(translator));
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+ });
+ }
+ }
+
+ /**
+ * Creates an on-device Translator for natural language translation.
+ *
* <p><strong>NOTE: </strong>Call on a worker thread.
*
+ * @deprecated use {@link #createOnDeviceTranslator(TranslationContext, Executor, Consumer)}
+ * instead.
+ *
* @param translationContext {@link TranslationContext} containing the specs for creating the
* Translator.
*/
+ @Deprecated
@Nullable
@WorkerThread
public Translator createOnDeviceTranslator(@NonNull TranslationContext translationContext) {
diff --git a/core/java/android/view/translation/Translator.java b/core/java/android/view/translation/Translator.java
index 6037302..b0d95b3 100644
--- a/core/java/android/view/translation/Translator.java
+++ b/core/java/android/view/translation/Translator.java
@@ -101,10 +101,18 @@
public static final String EXTRA_SESSION_ID = "sessionId";
static class ServiceBinderReceiver extends IResultReceiver.Stub {
+ // TODO: refactor how translator is instantiated after removing deprecated createTranslator.
private final WeakReference<Translator> mTranslator;
private final CountDownLatch mLatch = new CountDownLatch(1);
private int mSessionId;
+ private Consumer<Translator> mCallback;
+
+ ServiceBinderReceiver(Translator translator, Consumer<Translator> callback) {
+ mTranslator = new WeakReference<>(translator);
+ mCallback = callback;
+ }
+
ServiceBinderReceiver(Translator translator) {
mTranslator = new WeakReference<>(translator);
}
@@ -126,6 +134,9 @@
public void send(int resultCode, Bundle resultData) {
if (resultCode == STATUS_SYNC_CALL_FAIL) {
mLatch.countDown();
+ if (mCallback != null) {
+ mCallback.accept(null);
+ }
return;
}
mSessionId = resultData.getInt(EXTRA_SESSION_ID);
@@ -146,6 +157,9 @@
}
translator.setServiceBinder(binder);
mLatch.countDown();
+ if (mCallback != null) {
+ mCallback.accept(translator);
+ }
}
// TODO(b/176464808): maybe make SyncResultReceiver.TimeoutException constructor public
@@ -165,6 +179,32 @@
public Translator(@NonNull Context context,
@NonNull TranslationContext translationContext, int sessionId,
@NonNull TranslationManager translationManager, @NonNull Handler handler,
+ @Nullable ITranslationManager systemServerBinder,
+ @NonNull Consumer<Translator> callback) {
+ mContext = context;
+ mTranslationContext = translationContext;
+ mId = sessionId;
+ mManager = translationManager;
+ mHandler = handler;
+ mSystemServerBinder = systemServerBinder;
+ mServiceBinderReceiver = new ServiceBinderReceiver(this, callback);
+
+ try {
+ mSystemServerBinder.onSessionCreated(mTranslationContext, mId,
+ mServiceBinderReceiver, mContext.getUserId());
+ } catch (RemoteException e) {
+ Log.w(TAG, "RemoteException calling startSession(): " + e);
+ }
+ }
+
+ /**
+ * Create the Translator.
+ *
+ * @hide
+ */
+ public Translator(@NonNull Context context,
+ @NonNull TranslationContext translationContext, int sessionId,
+ @NonNull TranslationManager translationManager, @NonNull Handler handler,
@Nullable ITranslationManager systemServerBinder) {
mContext = context;
mTranslationContext = translationContext;