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

Commit 192818d7 authored by Joanne Chung's avatar Joanne Chung Committed by Automerger Merge Worker
Browse files

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

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/15125592

Change-Id: I4d089a39da9a05e94bfd7d40680eccb69980ab66
parents f8a72564 d78977a7
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);