Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d78977a7 authored by Joanne Chung's avatar Joanne Chung Committed by Android (Google) Code Review
Browse files

Merge "Notify onFinished when activity is destroyed." into sc-dev

parents 909281eb bb612abc
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package android.view.translation;

import android.content.ComponentName;
import android.os.IBinder;
import android.os.IRemoteCallback;
import android.os.ResultReceiver;
@@ -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);
}
+18 −0
Original line number Diff line number Diff line
@@ -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;
@@ -161,6 +162,7 @@ public class UiTranslationController {
                        view.setHasTranslationTransientState(false);
                    }
                });
                notifyTranslationFinished(/* activityDestroyed= */ false);
                synchronized (mLock) {
                    mViews.clear();
                }
@@ -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<>();
+21 −0
Original line number Diff line number Diff line
@@ -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;
@@ -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<>();
+10 −0
Original line number Diff line number Diff line
@@ -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;
+57 −13
Original line number Diff line number Diff line
@@ -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;
@@ -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;
@@ -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,
@@ -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,
@@ -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();
@@ -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) {
@@ -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(
@@ -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);