From 50a637b1e52f0fb6728eb112c51494de55879e44 Mon Sep 17 00:00:00 2001 From: Adam He Date: Wed, 21 Apr 2021 16:33:10 -0700 Subject: Changed createOnDeviceTranslator to be asynchronous with callback. Bug: 176208267 Test: atest CtsTranslationTestCases Change-Id: Icedc953611e70dc208cbef54b4e459ebb0ccd5a9 --- .../view/translation/TranslationManager.java | 65 ++++++++++++++++++++-- core/java/android/view/translation/Translator.java | 40 +++++++++++++ 2 files changed, 101 insertions(+), 4 deletions(-) (limited to 'core/java') diff --git a/core/java/android/view/translation/TranslationManager.java b/core/java/android/view/translation/TranslationManager.java index e75577487d1c..20d817db02b3 100644 --- a/core/java/android/view/translation/TranslationManager.java +++ b/core/java/android/view/translation/TranslationManager.java @@ -100,10 +100,6 @@ public final class TranslationManager { private final ITranslationManager mService; - @Nullable - @GuardedBy("mLock") - private ITranslationDirectManager mDirectServiceBinder; - @NonNull @GuardedBy("mLock") private final SparseArray mTranslators = new SparseArray<>(); @@ -128,14 +124,75 @@ public final class TranslationManager { mHandler = Handler.createAsync(Looper.getMainLooper()); } + /** + * 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 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() { + @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. * *

NOTE: 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 6037302a9445..b0d95b3b0a0f 100644 --- a/core/java/android/view/translation/Translator.java +++ b/core/java/android/view/translation/Translator.java @@ -101,10 +101,18 @@ public class Translator { 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 mTranslator; private final CountDownLatch mLatch = new CountDownLatch(1); private int mSessionId; + private Consumer mCallback; + + ServiceBinderReceiver(Translator translator, Consumer callback) { + mTranslator = new WeakReference<>(translator); + mCallback = callback; + } + ServiceBinderReceiver(Translator translator) { mTranslator = new WeakReference<>(translator); } @@ -126,6 +134,9 @@ public class Translator { 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 @@ public class Translator { } translator.setServiceBinder(binder); mLatch.countDown(); + if (mCallback != null) { + mCallback.accept(translator); + } } // TODO(b/176464808): maybe make SyncResultReceiver.TimeoutException constructor public @@ -157,6 +171,32 @@ public class Translator { } } + /** + * Create the Translator. + * + * @hide + */ + public Translator(@NonNull Context context, + @NonNull TranslationContext translationContext, int sessionId, + @NonNull TranslationManager translationManager, @NonNull Handler handler, + @Nullable ITranslationManager systemServerBinder, + @NonNull Consumer 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. * -- cgit v1.2.3