Loading core/java/android/view/translation/ITranslationManager.aidl +3 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package android.view.translation; import android.content.ComponentName; import android.os.IBinder; import android.os.IRemoteCallback; import android.os.ResultReceiver; Loading Loading @@ -47,4 +48,6 @@ oneway interface ITranslationManager { void registerUiTranslationStateCallback(in IRemoteCallback callback, int userId); void unregisterUiTranslationStateCallback(in IRemoteCallback callback, int userId); void getServiceSettingsActivity(in IResultReceiver result, int userId); void onTranslationFinished(boolean activityDestroyed, IBinder token, in ComponentName componentName, int userId); } core/java/android/view/translation/UiTranslationController.java +18 −0 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ import static android.view.translation.UiTranslationManager.STATE_UI_TRANSLATION import android.annotation.NonNull; import android.annotation.WorkerThread; import android.app.Activity; import android.app.assist.ActivityId; import android.content.Context; import android.os.Build; import android.os.Handler; Loading Loading @@ -161,6 +162,7 @@ public class UiTranslationController { view.setHasTranslationTransientState(false); } }); notifyTranslationFinished(/* activityDestroyed= */ false); synchronized (mLock) { mViews.clear(); } Loading @@ -175,12 +177,28 @@ public class UiTranslationController { */ public void onActivityDestroyed() { synchronized (mLock) { if (DEBUG) { Log.i(TAG, "onActivityDestroyed(): mCurrentState is " + stateToString(mCurrentState)); } if (mCurrentState != STATE_UI_TRANSLATION_FINISHED) { notifyTranslationFinished(/* activityDestroyed= */ true); } mViews.clear(); destroyTranslators(); mWorkerThread.quitSafely(); } } private void notifyTranslationFinished(boolean activityDestroyed) { UiTranslationManager manager = mContext.getSystemService(UiTranslationManager.class); if (manager != null) { manager.onTranslationFinished(activityDestroyed, new ActivityId(mActivity.getTaskId(), mActivity.getShareableActivityToken()), mActivity.getComponentName()); } } private void setLastRequestAutofillIdsLocked(List<AutofillId> views) { if (mLastRequestAutofillIds == null) { mLastRequestAutofillIds = new ArraySet<>(); Loading core/java/android/view/translation/UiTranslationManager.java +21 −0 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ import android.annotation.NonNull; import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.app.assist.ActivityId; import android.content.ComponentName; import android.content.Context; import android.icu.util.ULocale; import android.os.Binder; Loading Loading @@ -308,6 +309,26 @@ public final class UiTranslationManager { } } /** * Notify apps the translation is finished because {@link #finishTranslation(ActivityId)} is * called or Activity is destroyed. * * @param activityDestroyed if the ui translation is finished because of activity destroyed. * @param activityId the identifier for the Activity which needs ui translation * @param componentName the ui translated Activity componentName. * * @hide */ public void onTranslationFinished(boolean activityDestroyed, ActivityId activityId, ComponentName componentName) { try { mService.onTranslationFinished(activityDestroyed, activityId.getToken(), componentName, mContext.getUserId()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } @NonNull @GuardedBy("mCallbacks") private final Map<UiTranslationStateCallback, IRemoteCallback> mCallbacks = new ArrayMap<>(); Loading services/translation/java/com/android/server/translation/TranslationManagerService.java +10 −0 Original line number Diff line number Diff line Loading @@ -245,6 +245,16 @@ public final class TranslationManagerService } } @Override public void onTranslationFinished(boolean activityDestroyed, IBinder token, ComponentName componentName, int userId) { TranslationManagerServiceImpl service; synchronized (mLock) { service = getServiceForUserLocked(userId); service.onTranslationFinishedLocked(activityDestroyed, token, componentName); } } @Override public void getServiceSettingsActivity(IResultReceiver result, int userId) { final TranslationManagerServiceImpl service; Loading services/translation/java/com/android/server/translation/TranslationManagerServiceImpl.java +57 −13 Original line number Diff line number Diff line Loading @@ -20,10 +20,12 @@ import static android.view.translation.TranslationManager.EXTRA_CAPABILITIES; import static android.view.translation.UiTranslationManager.EXTRA_SOURCE_LOCALE; import static android.view.translation.UiTranslationManager.EXTRA_STATE; import static android.view.translation.UiTranslationManager.EXTRA_TARGET_LOCALE; import static android.view.translation.UiTranslationManager.STATE_UI_TRANSLATION_FINISHED; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.ComponentName; import android.content.Context; import android.content.pm.PackageManager; import android.content.pm.ServiceInfo; import android.os.Bundle; Loading @@ -33,6 +35,7 @@ import android.os.RemoteCallbackList; import android.os.RemoteException; import android.os.ResultReceiver; import android.service.translation.TranslationServiceInfo; import android.util.ArraySet; import android.util.Slog; import android.view.autofill.AutofillId; import android.view.inputmethod.InputMethodInfo; Loading Loading @@ -83,6 +86,7 @@ final class TranslationManagerServiceImpl extends new TranslationServiceRemoteCallback(); private final RemoteCallbackList<IRemoteCallback> mTranslationCapabilityCallbacks = new RemoteCallbackList<>(); private final ArraySet<IBinder> mWaitingFinishedCallbackActivities = new ArraySet(); protected TranslationManagerServiceImpl( @NonNull TranslationManagerService master, Loading Loading @@ -169,6 +173,41 @@ final class TranslationManagerServiceImpl extends } } private int getActivityUidByComponentName(Context context, ComponentName componentName, int userId) { int translationActivityUid = -1; try { if (componentName != null) { translationActivityUid = context.getPackageManager().getApplicationInfoAsUser( componentName.getPackageName(), 0, userId).uid; } } catch (PackageManager.NameNotFoundException e) { Slog.d(TAG, "Cannot find packageManager for" + componentName); } return translationActivityUid; } @GuardedBy("mLock") public void onTranslationFinishedLocked(boolean activityDestroyed, IBinder token, ComponentName componentName) { int translationActivityUid = getActivityUidByComponentName(getContext(), componentName, getUserId()); if (activityDestroyed) { // In the Activity destroy case, we only calls onTranslationFinished() in // non-finisTranslation() state. If there is a finisTranslation() calls by apps, we // should remove the waiting callback to avoid callback twice. invokeCallbacks(STATE_UI_TRANSLATION_FINISHED, /* sourceSpec= */ null, /* targetSpec= */null, translationActivityUid); mWaitingFinishedCallbackActivities.remove(token); } else { if (mWaitingFinishedCallbackActivities.contains(token)) { invokeCallbacks(STATE_UI_TRANSLATION_FINISHED, /* sourceSpec= */ null, /* targetSpec= */null, translationActivityUid); mWaitingFinishedCallbackActivities.remove(token); } } } @GuardedBy("mLock") public void updateUiTranslationStateLocked(@UiTranslationState int state, TranslationSpec sourceSpec, TranslationSpec targetSpec, List<AutofillId> viewIds, Loading @@ -178,10 +217,13 @@ final class TranslationManagerServiceImpl extends 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); Slog.w(TAG, "Unknown activity or it was finished to query for update translation " + "state for token=" + token + " taskId=" + taskId + " for state= " + state); return; } if (state == STATE_UI_TRANSLATION_FINISHED) { mWaitingFinishedCallbackActivities.add(token); } int translationActivityUid = -1; try { IBinder activityToken = taskTopActivityTokens.getActivityToken(); Loading @@ -191,20 +233,15 @@ final class TranslationManagerServiceImpl extends mLastActivityTokens = new WeakReference<>(taskTopActivityTokens); ComponentName componentName = mActivityTaskManagerInternal.getActivityName(activityToken); try { if (componentName != null) { translationActivityUid = getContext().getPackageManager().getApplicationInfoAsUser( componentName.getPackageName(), 0, getUserId()).uid; } } catch (PackageManager.NameNotFoundException e) { Slog.d(TAG, "Cannot find package for" + componentName); } getActivityUidByComponentName(getContext(), componentName, getUserId()); } catch (RemoteException e) { Slog.w(TAG, "Update UiTranslationState fail: " + e); } if (state != STATE_UI_TRANSLATION_FINISHED) { invokeCallbacks(state, sourceSpec, targetSpec, translationActivityUid); } } @GuardedBy("mLock") public void dumpLocked(String prefix, FileDescriptor fd, PrintWriter pw) { Loading @@ -226,6 +263,14 @@ final class TranslationManagerServiceImpl extends } else { pw.print(prefix); pw.println("No requested UiTranslation Activity."); } final int waitingFinishCallbackSize = mWaitingFinishedCallbackActivities.size(); if (waitingFinishCallbackSize > 0) { pw.print(prefix); pw.print("number waiting finish callback activities: "); pw.println(waitingFinishCallbackSize); for (IBinder activityToken : mWaitingFinishedCallbackActivities) { pw.print(prefix); pw.print("activityToken: "); pw.println(activityToken); } } } private void invokeCallbacks( Loading @@ -243,7 +288,6 @@ final class TranslationManagerServiceImpl extends LocalServices.getService(InputMethodManagerInternal.class) .getEnabledInputMethodListAsUser(mUserId); mCallbacks.broadcast((callback, uid) -> { // callback to the application that is translated if registered. if ((int) uid == translationActivityUid) { try { callback.sendResult(res); Loading Loading
core/java/android/view/translation/ITranslationManager.aidl +3 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package android.view.translation; import android.content.ComponentName; import android.os.IBinder; import android.os.IRemoteCallback; import android.os.ResultReceiver; Loading Loading @@ -47,4 +48,6 @@ oneway interface ITranslationManager { void registerUiTranslationStateCallback(in IRemoteCallback callback, int userId); void unregisterUiTranslationStateCallback(in IRemoteCallback callback, int userId); void getServiceSettingsActivity(in IResultReceiver result, int userId); void onTranslationFinished(boolean activityDestroyed, IBinder token, in ComponentName componentName, int userId); }
core/java/android/view/translation/UiTranslationController.java +18 −0 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ import static android.view.translation.UiTranslationManager.STATE_UI_TRANSLATION import android.annotation.NonNull; import android.annotation.WorkerThread; import android.app.Activity; import android.app.assist.ActivityId; import android.content.Context; import android.os.Build; import android.os.Handler; Loading Loading @@ -161,6 +162,7 @@ public class UiTranslationController { view.setHasTranslationTransientState(false); } }); notifyTranslationFinished(/* activityDestroyed= */ false); synchronized (mLock) { mViews.clear(); } Loading @@ -175,12 +177,28 @@ public class UiTranslationController { */ public void onActivityDestroyed() { synchronized (mLock) { if (DEBUG) { Log.i(TAG, "onActivityDestroyed(): mCurrentState is " + stateToString(mCurrentState)); } if (mCurrentState != STATE_UI_TRANSLATION_FINISHED) { notifyTranslationFinished(/* activityDestroyed= */ true); } mViews.clear(); destroyTranslators(); mWorkerThread.quitSafely(); } } private void notifyTranslationFinished(boolean activityDestroyed) { UiTranslationManager manager = mContext.getSystemService(UiTranslationManager.class); if (manager != null) { manager.onTranslationFinished(activityDestroyed, new ActivityId(mActivity.getTaskId(), mActivity.getShareableActivityToken()), mActivity.getComponentName()); } } private void setLastRequestAutofillIdsLocked(List<AutofillId> views) { if (mLastRequestAutofillIds == null) { mLastRequestAutofillIds = new ArraySet<>(); Loading
core/java/android/view/translation/UiTranslationManager.java +21 −0 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ import android.annotation.NonNull; import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.app.assist.ActivityId; import android.content.ComponentName; import android.content.Context; import android.icu.util.ULocale; import android.os.Binder; Loading Loading @@ -308,6 +309,26 @@ public final class UiTranslationManager { } } /** * Notify apps the translation is finished because {@link #finishTranslation(ActivityId)} is * called or Activity is destroyed. * * @param activityDestroyed if the ui translation is finished because of activity destroyed. * @param activityId the identifier for the Activity which needs ui translation * @param componentName the ui translated Activity componentName. * * @hide */ public void onTranslationFinished(boolean activityDestroyed, ActivityId activityId, ComponentName componentName) { try { mService.onTranslationFinished(activityDestroyed, activityId.getToken(), componentName, mContext.getUserId()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } @NonNull @GuardedBy("mCallbacks") private final Map<UiTranslationStateCallback, IRemoteCallback> mCallbacks = new ArrayMap<>(); Loading
services/translation/java/com/android/server/translation/TranslationManagerService.java +10 −0 Original line number Diff line number Diff line Loading @@ -245,6 +245,16 @@ public final class TranslationManagerService } } @Override public void onTranslationFinished(boolean activityDestroyed, IBinder token, ComponentName componentName, int userId) { TranslationManagerServiceImpl service; synchronized (mLock) { service = getServiceForUserLocked(userId); service.onTranslationFinishedLocked(activityDestroyed, token, componentName); } } @Override public void getServiceSettingsActivity(IResultReceiver result, int userId) { final TranslationManagerServiceImpl service; Loading
services/translation/java/com/android/server/translation/TranslationManagerServiceImpl.java +57 −13 Original line number Diff line number Diff line Loading @@ -20,10 +20,12 @@ import static android.view.translation.TranslationManager.EXTRA_CAPABILITIES; import static android.view.translation.UiTranslationManager.EXTRA_SOURCE_LOCALE; import static android.view.translation.UiTranslationManager.EXTRA_STATE; import static android.view.translation.UiTranslationManager.EXTRA_TARGET_LOCALE; import static android.view.translation.UiTranslationManager.STATE_UI_TRANSLATION_FINISHED; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.ComponentName; import android.content.Context; import android.content.pm.PackageManager; import android.content.pm.ServiceInfo; import android.os.Bundle; Loading @@ -33,6 +35,7 @@ import android.os.RemoteCallbackList; import android.os.RemoteException; import android.os.ResultReceiver; import android.service.translation.TranslationServiceInfo; import android.util.ArraySet; import android.util.Slog; import android.view.autofill.AutofillId; import android.view.inputmethod.InputMethodInfo; Loading Loading @@ -83,6 +86,7 @@ final class TranslationManagerServiceImpl extends new TranslationServiceRemoteCallback(); private final RemoteCallbackList<IRemoteCallback> mTranslationCapabilityCallbacks = new RemoteCallbackList<>(); private final ArraySet<IBinder> mWaitingFinishedCallbackActivities = new ArraySet(); protected TranslationManagerServiceImpl( @NonNull TranslationManagerService master, Loading Loading @@ -169,6 +173,41 @@ final class TranslationManagerServiceImpl extends } } private int getActivityUidByComponentName(Context context, ComponentName componentName, int userId) { int translationActivityUid = -1; try { if (componentName != null) { translationActivityUid = context.getPackageManager().getApplicationInfoAsUser( componentName.getPackageName(), 0, userId).uid; } } catch (PackageManager.NameNotFoundException e) { Slog.d(TAG, "Cannot find packageManager for" + componentName); } return translationActivityUid; } @GuardedBy("mLock") public void onTranslationFinishedLocked(boolean activityDestroyed, IBinder token, ComponentName componentName) { int translationActivityUid = getActivityUidByComponentName(getContext(), componentName, getUserId()); if (activityDestroyed) { // In the Activity destroy case, we only calls onTranslationFinished() in // non-finisTranslation() state. If there is a finisTranslation() calls by apps, we // should remove the waiting callback to avoid callback twice. invokeCallbacks(STATE_UI_TRANSLATION_FINISHED, /* sourceSpec= */ null, /* targetSpec= */null, translationActivityUid); mWaitingFinishedCallbackActivities.remove(token); } else { if (mWaitingFinishedCallbackActivities.contains(token)) { invokeCallbacks(STATE_UI_TRANSLATION_FINISHED, /* sourceSpec= */ null, /* targetSpec= */null, translationActivityUid); mWaitingFinishedCallbackActivities.remove(token); } } } @GuardedBy("mLock") public void updateUiTranslationStateLocked(@UiTranslationState int state, TranslationSpec sourceSpec, TranslationSpec targetSpec, List<AutofillId> viewIds, Loading @@ -178,10 +217,13 @@ final class TranslationManagerServiceImpl extends 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); Slog.w(TAG, "Unknown activity or it was finished to query for update translation " + "state for token=" + token + " taskId=" + taskId + " for state= " + state); return; } if (state == STATE_UI_TRANSLATION_FINISHED) { mWaitingFinishedCallbackActivities.add(token); } int translationActivityUid = -1; try { IBinder activityToken = taskTopActivityTokens.getActivityToken(); Loading @@ -191,20 +233,15 @@ final class TranslationManagerServiceImpl extends mLastActivityTokens = new WeakReference<>(taskTopActivityTokens); ComponentName componentName = mActivityTaskManagerInternal.getActivityName(activityToken); try { if (componentName != null) { translationActivityUid = getContext().getPackageManager().getApplicationInfoAsUser( componentName.getPackageName(), 0, getUserId()).uid; } } catch (PackageManager.NameNotFoundException e) { Slog.d(TAG, "Cannot find package for" + componentName); } getActivityUidByComponentName(getContext(), componentName, getUserId()); } catch (RemoteException e) { Slog.w(TAG, "Update UiTranslationState fail: " + e); } if (state != STATE_UI_TRANSLATION_FINISHED) { invokeCallbacks(state, sourceSpec, targetSpec, translationActivityUid); } } @GuardedBy("mLock") public void dumpLocked(String prefix, FileDescriptor fd, PrintWriter pw) { Loading @@ -226,6 +263,14 @@ final class TranslationManagerServiceImpl extends } else { pw.print(prefix); pw.println("No requested UiTranslation Activity."); } final int waitingFinishCallbackSize = mWaitingFinishedCallbackActivities.size(); if (waitingFinishCallbackSize > 0) { pw.print(prefix); pw.print("number waiting finish callback activities: "); pw.println(waitingFinishCallbackSize); for (IBinder activityToken : mWaitingFinishedCallbackActivities) { pw.print(prefix); pw.print("activityToken: "); pw.println(activityToken); } } } private void invokeCallbacks( Loading @@ -243,7 +288,6 @@ final class TranslationManagerServiceImpl extends LocalServices.getService(InputMethodManagerInternal.class) .getEnabledInputMethodListAsUser(mUserId); mCallbacks.broadcast((callback, uid) -> { // callback to the application that is translated if registered. if ((int) uid == translationActivityUid) { try { callback.sendResult(res); Loading