From dd0224162c894c7abdd803a0422b526666b8ce29 Mon Sep 17 00:00:00 2001 From: Joanne Chung Date: Wed, 17 Mar 2021 00:42:04 +0800 Subject: [PATCH] Add API to get the PendingIntent for translation settings Activity Bug: 176208267 Test: manual test with sample app Test: atest CtsTranslationTestCases Change-Id: I00416cf9cb63d522b9d8a448be3533b89b753aa0 --- core/api/current.txt | 1 + .../translation/TranslationServiceInfo.java | 4 +- .../view/translation/ITranslationManager.aidl | 1 + .../view/translation/TranslationManager.java | 26 ++++++++++ .../TranslationManagerService.java | 47 +++++++++++++++++++ .../TranslationManagerServiceImpl.java | 21 +++++++-- 6 files changed, 95 insertions(+), 5 deletions(-) diff --git a/core/api/current.txt b/core/api/current.txt index dd0ea286b54fd..87b5b07db37ce 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -52559,6 +52559,7 @@ package android.view.translation { method public void addTranslationCapabilityUpdateListener(int, int, @NonNull android.app.PendingIntent); method @Nullable @WorkerThread public android.view.translation.Translator createTranslator(@NonNull android.view.translation.TranslationContext); method @NonNull @WorkerThread public java.util.Set getTranslationCapabilities(int, int); + method @Nullable public android.app.PendingIntent getTranslationSettingsActivityIntent(); method public void removeTranslationCapabilityUpdateListener(int, int, @NonNull android.app.PendingIntent); } diff --git a/core/java/android/service/translation/TranslationServiceInfo.java b/core/java/android/service/translation/TranslationServiceInfo.java index 18cc29d12b5fc..c7017b2ea73b2 100644 --- a/core/java/android/service/translation/TranslationServiceInfo.java +++ b/core/java/android/service/translation/TranslationServiceInfo.java @@ -100,9 +100,9 @@ public final class TranslationServiceInfo { if (!Manifest.permission.BIND_TRANSLATION_SERVICE.equals(si.permission)) { Slog.w(TAG, "TranslationServiceInfo from '" + si.packageName + "' does not require permission " - + Manifest.permission.BIND_CONTENT_CAPTURE_SERVICE); + + Manifest.permission.BIND_TRANSLATION_SERVICE); throw new SecurityException("Service does not require permission " - + Manifest.permission.BIND_CONTENT_CAPTURE_SERVICE); + + Manifest.permission.BIND_TRANSLATION_SERVICE); } mServiceInfo = si; diff --git a/core/java/android/view/translation/ITranslationManager.aidl b/core/java/android/view/translation/ITranslationManager.aidl index dbc32e9cf0cad..9c53f461eb951 100644 --- a/core/java/android/view/translation/ITranslationManager.aidl +++ b/core/java/android/view/translation/ITranslationManager.aidl @@ -46,4 +46,5 @@ oneway interface ITranslationManager { void registerUiTranslationStateCallback(in IRemoteCallback callback, int userId); void unregisterUiTranslationStateCallback(in IRemoteCallback callback, int userId); + void getServiceSettingsActivity(in IResultReceiver result, int userId); } diff --git a/core/java/android/view/translation/TranslationManager.java b/core/java/android/view/translation/TranslationManager.java index 66b45f3e41e05..dfa70951059a7 100644 --- a/core/java/android/view/translation/TranslationManager.java +++ b/core/java/android/view/translation/TranslationManager.java @@ -35,6 +35,7 @@ import android.util.Pair; import android.util.SparseArray; import com.android.internal.annotations.GuardedBy; +import com.android.internal.util.SyncResultReceiver; import java.util.ArrayList; import java.util.Collections; @@ -263,6 +264,31 @@ public final class TranslationManager { //TODO: Add method to propagate updates to mTCapabilityUpdateListeners + /** + * Returns an immutable PendingIntent which can used by apps to launch translation settings. + * + * @return An immutable PendingIntent or {@code null} if one of reason met: + * + **/ + @Nullable + public PendingIntent getTranslationSettingsActivityIntent() { + final SyncResultReceiver resultReceiver = new SyncResultReceiver(SYNC_CALLS_TIMEOUT_MS); + try { + mService.getServiceSettingsActivity(resultReceiver, mContext.getUserId()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + try { + return resultReceiver.getParcelableResult(); + } catch (SyncResultReceiver.TimeoutException e) { + Log.e(TAG, "Fail to get translation service settings activity."); + return null; + } + } + void removeTranslator(int id) { synchronized (mLock) { mTranslators.remove(id); diff --git a/services/translation/java/com/android/server/translation/TranslationManagerService.java b/services/translation/java/com/android/server/translation/TranslationManagerService.java index 6203ae9540650..f132b49e9dd8f 100644 --- a/services/translation/java/com/android/server/translation/TranslationManagerService.java +++ b/services/translation/java/com/android/server/translation/TranslationManagerService.java @@ -17,13 +17,19 @@ package com.android.server.translation; import static android.Manifest.permission.MANAGE_UI_TRANSLATION; +import static android.app.PendingIntent.FLAG_IMMUTABLE; import static android.content.Context.TRANSLATION_MANAGER_SERVICE; import static android.view.translation.TranslationManager.STATUS_SYNC_CALL_FAIL; +import static android.view.translation.TranslationManager.STATUS_SYNC_CALL_SUCCESS; + +import static com.android.internal.util.SyncResultReceiver.bundleFor; import android.annotation.NonNull; import android.annotation.Nullable; +import android.app.PendingIntent; import android.content.ComponentName; import android.content.Context; +import android.content.Intent; import android.content.pm.PackageManager; import android.os.Binder; import android.os.IBinder; @@ -31,6 +37,7 @@ import android.os.IRemoteCallback; import android.os.RemoteException; import android.os.ResultReceiver; import android.os.ShellCallback; +import android.os.UserHandle; import android.util.Slog; import android.view.autofill.AutofillId; import android.view.translation.ITranslationManager; @@ -231,6 +238,46 @@ public final class TranslationManagerService } } + @Override + public void getServiceSettingsActivity(IResultReceiver result, int userId) { + final TranslationManagerServiceImpl service; + synchronized (mLock) { + service = getServiceForUserLocked(userId); + } + if (service != null) { + final ComponentName componentName = service.getServiceSettingsActivityLocked(); + if (componentName == null) { + try { + result.send(STATUS_SYNC_CALL_SUCCESS, null); + } catch (RemoteException e) { + Slog.w(TAG, "Unable to send getServiceSettingsActivity(): " + e); + } + } + final Intent intent = new Intent(); + intent.setComponent(componentName); + final long identity = Binder.clearCallingIdentity(); + try { + final PendingIntent pendingIntent = + PendingIntent.getActivityAsUser(getContext(), 0, intent, FLAG_IMMUTABLE, + null, new UserHandle(userId)); + try { + + result.send(STATUS_SYNC_CALL_SUCCESS, bundleFor(pendingIntent)); + } catch (RemoteException e) { + Slog.w(TAG, "Unable to send getServiceSettingsActivity(): " + e); + } + } finally { + Binder.restoreCallingIdentity(identity); + } + } else { + try { + result.send(STATUS_SYNC_CALL_FAIL, null); + } catch (RemoteException e) { + Slog.w(TAG, "Unable to send getServiceSettingsActivity(): " + e); + } + } + } + /** * Dump the service state into the given stream. You run "adb shell dumpsys translation". */ diff --git a/services/translation/java/com/android/server/translation/TranslationManagerServiceImpl.java b/services/translation/java/com/android/server/translation/TranslationManagerServiceImpl.java index ee5ec47ec71a7..2cd41ba5377c4 100644 --- a/services/translation/java/com/android/server/translation/TranslationManagerServiceImpl.java +++ b/services/translation/java/com/android/server/translation/TranslationManagerServiceImpl.java @@ -62,6 +62,9 @@ final class TranslationManagerServiceImpl extends @Nullable private ServiceInfo mRemoteTranslationServiceInfo; + @GuardedBy("mLock") + private TranslationServiceInfo mTranslationServiceInfo; + private ActivityTaskManagerInternal mActivityTaskManagerInternal; protected TranslationManagerServiceImpl( @@ -76,10 +79,10 @@ final class TranslationManagerServiceImpl extends @Override // from PerUserSystemService protected ServiceInfo newServiceInfoLocked(@NonNull ComponentName serviceComponent) throws PackageManager.NameNotFoundException { - final TranslationServiceInfo info = new TranslationServiceInfo(getContext(), + mTranslationServiceInfo = new TranslationServiceInfo(getContext(), serviceComponent, isTemporaryServiceSetLocked(), mUserId); - mRemoteTranslationServiceInfo = info.getServiceInfo(); - return info.getServiceInfo(); + mRemoteTranslationServiceInfo = mTranslationServiceInfo.getServiceInfo(); + return mTranslationServiceInfo.getServiceInfo(); } @GuardedBy("mLock") @@ -227,4 +230,16 @@ final class TranslationManagerServiceImpl extends } private final RemoteCallbackList mCallbacks = new RemoteCallbackList<>(); + + public ComponentName getServiceSettingsActivityLocked() { + if (mTranslationServiceInfo == null) { + return null; + } + final String activityName = mTranslationServiceInfo.getSettingsActivity(); + if (activityName == null) { + return null; + } + final String packageName = mTranslationServiceInfo.getServiceInfo().packageName; + return new ComponentName(packageName, activityName); + } }