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

Commit 04073dc5 authored by George Mount's avatar George Mount
Browse files

Internal API for cross-task Activity used by assistant.

29091742

A new internal API has been created for use by assistant
to launch an Activity Transition from a non-Activity.

The ActivityOptions are also passed along when using
a spring board Activity so that the shared elements
can be properly synchronized.

This also fixes TransitionManager.endTransition so
that it forces Transitions to end the animations.

Change-Id: Id18d9765bfc0c7b438e17966455aa66d3fa3aeda
parent 912e2b2c
Loading
Loading
Loading
Loading
+16 −1
Original line number Original line Diff line number Diff line
@@ -4219,6 +4219,7 @@ public class Activity extends ContextThemeWrapper
    public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,
    public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,
            @Nullable Bundle options) {
            @Nullable Bundle options) {
        if (mParent == null) {
        if (mParent == null) {
            options = transferSpringboardActivityOptions(options);
            Instrumentation.ActivityResult ar =
            Instrumentation.ActivityResult ar =
                mInstrumentation.execStartActivity(
                mInstrumentation.execStartActivity(
                    this, mMainThread.getApplicationThread(), mToken, this,
                    this, mMainThread.getApplicationThread(), mToken, this,
@@ -4267,6 +4268,14 @@ public class Activity extends ContextThemeWrapper
        }
        }
    }
    }


    private Bundle transferSpringboardActivityOptions(Bundle options) {
        if (options == null && (mWindow != null && !mWindow.isActive())) {
            return mActivityTransitionState.transferEnterActivityOptions();
        } else {
            return options;
        }
    }

    /**
    /**
     * @hide Implement to provide correct calling token.
     * @hide Implement to provide correct calling token.
     */
     */
@@ -4282,6 +4291,7 @@ public class Activity extends ContextThemeWrapper
        if (mParent != null) {
        if (mParent != null) {
            throw new RuntimeException("Can't be called from a child");
            throw new RuntimeException("Can't be called from a child");
        }
        }
        options = transferSpringboardActivityOptions(options);
        Instrumentation.ActivityResult ar = mInstrumentation.execStartActivity(
        Instrumentation.ActivityResult ar = mInstrumentation.execStartActivity(
                this, mMainThread.getApplicationThread(), mToken, this, intent, requestCode,
                this, mMainThread.getApplicationThread(), mToken, this, intent, requestCode,
                options, user);
                options, user);
@@ -4317,6 +4327,7 @@ public class Activity extends ContextThemeWrapper
        if (mParent != null) {
        if (mParent != null) {
            throw new RuntimeException("Can't be called from a child");
            throw new RuntimeException("Can't be called from a child");
        }
        }
        options = transferSpringboardActivityOptions(options);
        Instrumentation.ActivityResult ar =
        Instrumentation.ActivityResult ar =
                mInstrumentation.execStartActivity(
                mInstrumentation.execStartActivity(
                        this, mMainThread.getApplicationThread(), mToken, this,
                        this, mMainThread.getApplicationThread(), mToken, this,
@@ -4349,6 +4360,7 @@ public class Activity extends ContextThemeWrapper
        if (mParent != null) {
        if (mParent != null) {
            throw new RuntimeException("Can't be called from a child");
            throw new RuntimeException("Can't be called from a child");
        }
        }
        options = transferSpringboardActivityOptions(options);
        Instrumentation.ActivityResult ar =
        Instrumentation.ActivityResult ar =
                mInstrumentation.execStartActivityAsCaller(
                mInstrumentation.execStartActivityAsCaller(
                        this, mMainThread.getApplicationThread(), mToken, this,
                        this, mMainThread.getApplicationThread(), mToken, this,
@@ -4788,6 +4800,7 @@ public class Activity extends ContextThemeWrapper
     */
     */
    public void startActivityFromChild(@NonNull Activity child, @RequiresPermission Intent intent,
    public void startActivityFromChild(@NonNull Activity child, @RequiresPermission Intent intent,
            int requestCode, @Nullable Bundle options) {
            int requestCode, @Nullable Bundle options) {
        options = transferSpringboardActivityOptions(options);
        Instrumentation.ActivityResult ar =
        Instrumentation.ActivityResult ar =
            mInstrumentation.execStartActivity(
            mInstrumentation.execStartActivity(
                this, mMainThread.getApplicationThread(), mToken, child,
                this, mMainThread.getApplicationThread(), mToken, child,
@@ -4853,6 +4866,7 @@ public class Activity extends ContextThemeWrapper
        if (referrer != null) {
        if (referrer != null) {
            intent.putExtra(Intent.EXTRA_REFERRER, referrer);
            intent.putExtra(Intent.EXTRA_REFERRER, referrer);
        }
        }
        options = transferSpringboardActivityOptions(options);
        Instrumentation.ActivityResult ar =
        Instrumentation.ActivityResult ar =
            mInstrumentation.execStartActivity(
            mInstrumentation.execStartActivity(
                this, mMainThread.getApplicationThread(), mToken, who,
                this, mMainThread.getApplicationThread(), mToken, who,
@@ -6650,11 +6664,11 @@ public class Activity extends ContextThemeWrapper
        mVisibleFromClient = !mWindow.getWindowStyle().getBoolean(
        mVisibleFromClient = !mWindow.getWindowStyle().getBoolean(
                com.android.internal.R.styleable.Window_windowNoDisplay, false);
                com.android.internal.R.styleable.Window_windowNoDisplay, false);
        mFragments.dispatchActivityCreated();
        mFragments.dispatchActivityCreated();
        mActivityTransitionState.setEnterActivityOptions(this, getActivityOptions());
    }
    }


    final void performCreate(Bundle icicle) {
    final void performCreate(Bundle icicle) {
        restoreHasCurrentPermissionRequest(icicle);
        restoreHasCurrentPermissionRequest(icicle);
        mActivityTransitionState.setEnterActivityOptions(this, getActivityOptions());
        onCreate(icicle);
        onCreate(icicle);
        mActivityTransitionState.readState(icicle);
        mActivityTransitionState.readState(icicle);
        performCreateCommon();
        performCreateCommon();
@@ -6662,6 +6676,7 @@ public class Activity extends ContextThemeWrapper


    final void performCreate(Bundle icicle, PersistableBundle persistentState) {
    final void performCreate(Bundle icicle, PersistableBundle persistentState) {
        restoreHasCurrentPermissionRequest(icicle);
        restoreHasCurrentPermissionRequest(icicle);
        mActivityTransitionState.setEnterActivityOptions(this, getActivityOptions());
        onCreate(icicle, persistentState);
        onCreate(icicle, persistentState);
        mActivityTransitionState.readState(icicle);
        mActivityTransitionState.readState(icicle);
        performCreateCommon();
        performCreateCommon();
+148 −9
Original line number Original line Diff line number Diff line
@@ -31,10 +31,13 @@ import android.os.IRemoteCallback;
import android.os.Parcelable;
import android.os.Parcelable;
import android.os.RemoteException;
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.ResultReceiver;
import android.transition.Transition;
import android.transition.TransitionManager;
import android.util.Pair;
import android.util.Pair;
import android.util.Slog;
import android.util.Slog;
import android.view.AppTransitionAnimationSpec;
import android.view.AppTransitionAnimationSpec;
import android.view.View;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.Window;


import java.util.ArrayList;
import java.util.ArrayList;
@@ -640,10 +643,71 @@ public class ActivityOptions {
    public static ActivityOptions makeSceneTransitionAnimation(Activity activity,
    public static ActivityOptions makeSceneTransitionAnimation(Activity activity,
            Pair<View, String>... sharedElements) {
            Pair<View, String>... sharedElements) {
        ActivityOptions opts = new ActivityOptions();
        ActivityOptions opts = new ActivityOptions();
        if (!activity.getWindow().hasFeature(Window.FEATURE_ACTIVITY_TRANSITIONS)) {
        makeSceneTransitionAnimation(activity, activity.getWindow(), opts,
            opts.mAnimationType = ANIM_DEFAULT;
                activity.mExitTransitionListener, sharedElements);
        return opts;
        return opts;
    }
    }

    /**
     * Call this immediately prior to startActivity to begin a shared element transition
     * from a non-Activity. The window must support Window.FEATURE_ACTIVITY_TRANSITIONS.
     * The exit transition will start immediately and the shared element transition will
     * start once the launched Activity's shared element is ready.
     * <p>
     * When all transitions have completed and the shared element has been transfered,
     * the window's decor View will have its visibility set to View.GONE.
     *
     * @hide
     */
    @SafeVarargs
    public static ActivityOptions startSharedElementAnimation(Window window,
            Pair<View, String>... sharedElements) {
        ActivityOptions opts = new ActivityOptions();
        final View decorView = window.getDecorView();
        if (decorView == null) {
            return opts;
        }
        final ExitTransitionCoordinator exit =
                makeSceneTransitionAnimation(null, window, opts, null, sharedElements);
        if (exit != null) {
            HideWindowListener listener = new HideWindowListener(window, exit);
            exit.setHideSharedElementsCallback(listener);
            exit.startExit();
        }
        return opts;
    }

    /**
     * This method should be called when the {@link #startSharedElementAnimation(Window, Pair[])}
     * animation must be stopped and the Views reset. This can happen if there was an error
     * from startActivity or a springboard activity and the animation should stop and reset.
     *
     * @hide
     */
    public static void stopSharedElementAnimation(Window window) {
        final View decorView = window.getDecorView();
        if (decorView == null) {
            return;
        }
        final ExitTransitionCoordinator exit = (ExitTransitionCoordinator)
                decorView.getTag(com.android.internal.R.id.cross_task_transition);
        if (exit != null) {
            exit.cancelPendingTransitions();
            decorView.setTagInternal(com.android.internal.R.id.cross_task_transition, null);
            TransitionManager.endTransitions((ViewGroup) decorView);
            exit.resetViews();
            exit.clearState();
            decorView.setVisibility(View.VISIBLE);
        }
    }

    static ExitTransitionCoordinator makeSceneTransitionAnimation(Activity activity, Window window,
            ActivityOptions opts, SharedElementCallback callback,
            Pair<View, String>[] sharedElements) {
        if (!window.hasFeature(Window.FEATURE_ACTIVITY_TRANSITIONS)) {
            opts.mAnimationType = ANIM_DEFAULT;
            return null;
        }
        opts.mAnimationType = ANIM_SCENE_TRANSITION;
        opts.mAnimationType = ANIM_SCENE_TRANSITION;


        ArrayList<String> names = new ArrayList<String>();
        ArrayList<String> names = new ArrayList<String>();
@@ -665,18 +729,22 @@ public class ActivityOptions {
            }
            }
        }
        }


        ExitTransitionCoordinator exit = new ExitTransitionCoordinator(activity, names, names,
        ExitTransitionCoordinator exit = new ExitTransitionCoordinator(activity, window,
                views, false);
                callback, names, names, views, false);
        opts.mTransitionReceiver = exit;
        opts.mTransitionReceiver = exit;
        opts.mSharedElementNames = names;
        opts.mSharedElementNames = names;
        opts.mIsReturning = false;
        opts.mIsReturning = (activity == null);
        if (activity == null) {
            opts.mExitCoordinatorIndex = -1;
        } else {
            opts.mExitCoordinatorIndex =
            opts.mExitCoordinatorIndex =
                    activity.mActivityTransitionState.addExitTransitionCoordinator(exit);
                    activity.mActivityTransitionState.addExitTransitionCoordinator(exit);
        return opts;
        }
        return exit;
    }
    }


    /** @hide */
    /** @hide */
    public static ActivityOptions makeSceneTransitionAnimation(Activity activity,
    static ActivityOptions makeSceneTransitionAnimation(Activity activity,
            ExitTransitionCoordinator exitCoordinator, ArrayList<String> sharedElementNames,
            ExitTransitionCoordinator exitCoordinator, ArrayList<String> sharedElementNames,
            int resultCode, Intent resultData) {
            int resultCode, Intent resultData) {
        ActivityOptions opts = new ActivityOptions();
        ActivityOptions opts = new ActivityOptions();
@@ -900,6 +968,16 @@ public class ActivityOptions {
        return mIsReturning;
        return mIsReturning;
    }
    }


    /**
     * Returns whether or not the ActivityOptions was created with
     * {@link #startSharedElementAnimation(Window, Pair[])}.
     *
     * @hide
     */
    boolean isCrossTask() {
        return mExitCoordinatorIndex < 0;
    }

    /** @hide */
    /** @hide */
    public ArrayList<String> getSharedElementNames() {
    public ArrayList<String> getSharedElementNames() {
        return mSharedElementNames;
        return mSharedElementNames;
@@ -1191,4 +1269,65 @@ public class ActivityOptions {
                + ", mAnimationType=" + mAnimationType + ", mStartX=" + mStartX + ", mStartY="
                + ", mAnimationType=" + mAnimationType + ", mStartX=" + mStartX + ", mStartY="
                + mStartY + ", mWidth=" + mWidth + ", mHeight=" + mHeight;
                + mStartY + ", mWidth=" + mWidth + ", mHeight=" + mHeight;
    }
    }

    private static class HideWindowListener extends Transition.TransitionListenerAdapter
        implements ExitTransitionCoordinator.HideSharedElementsCallback {
        private final Window mWindow;
        private final ExitTransitionCoordinator mExit;
        private final boolean mWaitingForTransition;
        private boolean mTransitionEnded;
        private boolean mSharedElementHidden;
        private ArrayList<View> mSharedElements;

        public HideWindowListener(Window window, ExitTransitionCoordinator exit) {
            mWindow = window;
            mExit = exit;
            mSharedElements = new ArrayList<>(exit.mSharedElements);
            Transition transition = mWindow.getExitTransition();
            if (transition != null) {
                transition.addListener(this);
                mWaitingForTransition = true;
            } else {
                mWaitingForTransition = false;
            }
            View decorView = mWindow.getDecorView();
            if (decorView != null) {
                if (decorView.getTag(com.android.internal.R.id.cross_task_transition) != null) {
                    throw new IllegalStateException(
                            "Cannot start a transition while one is running");
                }
                decorView.setTagInternal(com.android.internal.R.id.cross_task_transition, exit);
            }
        }

        @Override
        public void onTransitionEnd(Transition transition) {
            mTransitionEnded = true;
            hideWhenDone();
            transition.removeListener(this);
        }

        @Override
        public void hideSharedElements() {
            mSharedElementHidden = true;
            hideWhenDone();
        }

        private void hideWhenDone() {
            if (mSharedElementHidden && (!mWaitingForTransition || mTransitionEnded)) {
                mExit.resetViews();
                int numSharedElements = mSharedElements.size();
                for (int i = 0; i < numSharedElements; i++) {
                    View view = mSharedElements.get(i);
                    view.requestLayout();
                }
                View decorView = mWindow.getDecorView();
                if (decorView != null) {
                    decorView.setTagInternal(
                            com.android.internal.R.id.cross_task_transition, null);
                    decorView.setVisibility(View.GONE);
                }
            }
        }
    }
}
}
+28 −4
Original line number Original line Diff line number Diff line
@@ -105,6 +105,12 @@ class ActivityTransitionState {


    private boolean mIsEnterTriggered;
    private boolean mIsEnterTriggered;


    /**
     * The ActivityOptions Bundle. This is used to transfer ActivityOptions through a
     * springboard Activity.
     */
    private Bundle mEnterBundle;

    public ActivityTransitionState() {
    public ActivityTransitionState() {
    }
    }


@@ -150,6 +156,10 @@ class ActivityTransitionState {
    }
    }


    public void setEnterActivityOptions(Activity activity, ActivityOptions options) {
    public void setEnterActivityOptions(Activity activity, ActivityOptions options) {
        if (options != null && mEnterBundle == null &&
                options.getAnimationType() == ActivityOptions.ANIM_SCENE_TRANSITION) {
            mEnterBundle = options.toBundle();
        }
        final Window window = activity.getWindow();
        final Window window = activity.getWindow();
        if (window == null) {
        if (window == null) {
            return;
            return;
@@ -185,7 +195,12 @@ class ActivityTransitionState {
            activity.getWindow().getDecorView().setVisibility(View.VISIBLE);
            activity.getWindow().getDecorView().setVisibility(View.VISIBLE);
        }
        }
        mEnterTransitionCoordinator = new EnterTransitionCoordinator(activity,
        mEnterTransitionCoordinator = new EnterTransitionCoordinator(activity,
                resultReceiver, sharedElementNames, mEnterActivityOptions.isReturning());
                resultReceiver, sharedElementNames, mEnterActivityOptions.isReturning(),
                mEnterActivityOptions.isCrossTask());
        if (mEnterActivityOptions.isCrossTask()) {
            mExitingFrom = new ArrayList<>(mEnterActivityOptions.getSharedElementNames());
            mExitingTo = new ArrayList<>(mEnterActivityOptions.getSharedElementNames());
        }


        if (!mIsEnterPostponed) {
        if (!mIsEnterPostponed) {
            startEnter();
            startEnter();
@@ -224,6 +239,13 @@ class ActivityTransitionState {
        mEnterActivityOptions = null;
        mEnterActivityOptions = null;
    }
    }


    Bundle transferEnterActivityOptions() {
        mEnterActivityOptions = null;
        Bundle options = mEnterBundle;
        mEnterBundle = null;
        return options;
    }

    public void onStop() {
    public void onStop() {
        restoreExitedViews();
        restoreExitedViews();
        if (mEnterTransitionCoordinator != null) {
        if (mEnterTransitionCoordinator != null) {
@@ -275,7 +297,8 @@ class ActivityTransitionState {
    }
    }


    private void restoreReenteringViews() {
    private void restoreReenteringViews() {
        if (mEnterTransitionCoordinator != null && mEnterTransitionCoordinator.isReturning()) {
        if (mEnterTransitionCoordinator != null && mEnterTransitionCoordinator.isReturning() &&
                !mEnterTransitionCoordinator.isCrossTask()) {
            mEnterTransitionCoordinator.forceViewsToAppear();
            mEnterTransitionCoordinator.forceViewsToAppear();
            mExitingFrom = null;
            mExitingFrom = null;
            mExitingTo = null;
            mExitingTo = null;
@@ -302,8 +325,9 @@ class ActivityTransitionState {
                    }
                    }
                }
                }


                mReturnExitCoordinator =
                mReturnExitCoordinator = new ExitTransitionCoordinator(activity,
                        new ExitTransitionCoordinator(activity, mEnteringNames, null, null, true);
                        activity.getWindow(), activity.mEnterTransitionListener, mEnteringNames,
                        null, null, true);
                if (enterViewsTransition != null && decor != null) {
                if (enterViewsTransition != null && decor != null) {
                    enterViewsTransition.resume(decor);
                    enterViewsTransition.resume(decor);
                }
                }
+11 −3
Original line number Original line Diff line number Diff line
@@ -59,12 +59,14 @@ class EnterTransitionCoordinator extends ActivityTransitionCoordinator {
    private boolean mIsViewsTransitionStarted;
    private boolean mIsViewsTransitionStarted;
    private Transition mEnterViewsTransition;
    private Transition mEnterViewsTransition;
    private OnPreDrawListener mViewsReadyListener;
    private OnPreDrawListener mViewsReadyListener;
    private final boolean mIsCrossTask;


    public EnterTransitionCoordinator(Activity activity, ResultReceiver resultReceiver,
    public EnterTransitionCoordinator(Activity activity, ResultReceiver resultReceiver,
            ArrayList<String> sharedElementNames, boolean isReturning) {
            ArrayList<String> sharedElementNames, boolean isReturning, boolean isCrossTask) {
        super(activity.getWindow(), sharedElementNames,
        super(activity.getWindow(), sharedElementNames,
                getListener(activity, isReturning), isReturning);
                getListener(activity, isReturning && !isCrossTask), isReturning);
        mActivity = activity;
        mActivity = activity;
        mIsCrossTask = isCrossTask;
        setResultReceiver(resultReceiver);
        setResultReceiver(resultReceiver);
        prepareEnter();
        prepareEnter();
        Bundle resultReceiverBundle = new Bundle();
        Bundle resultReceiverBundle = new Bundle();
@@ -85,6 +87,10 @@ class EnterTransitionCoordinator extends ActivityTransitionCoordinator {
        }
        }
    }
    }


    boolean isCrossTask() {
        return mIsCrossTask;
    }

    public void viewInstancesReady(ArrayList<String> accepted, ArrayList<String> localNames,
    public void viewInstancesReady(ArrayList<String> accepted, ArrayList<String> localNames,
            ArrayList<View> localViews) {
            ArrayList<View> localViews) {
        boolean remap = false;
        boolean remap = false;
@@ -325,7 +331,9 @@ class EnterTransitionCoordinator extends ActivityTransitionCoordinator {
        if (mActivity == null || decorView == null) {
        if (mActivity == null || decorView == null) {
            return;
            return;
        }
        }
        if (!isCrossTask()) {
            mActivity.overridePendingTransition(0, 0);
            mActivity.overridePendingTransition(0, 0);
        }
        if (!mIsReturning) {
        if (!mIsReturning) {
            mWasOpaque = mActivity.convertToTranslucent(null, null);
            mWasOpaque = mActivity.convertToTranslucent(null, null);
            Drawable background = decorView.getBackground();
            Drawable background = decorView.getBackground();
+19 −5
Original line number Original line Diff line number Diff line
@@ -35,6 +35,7 @@ import android.transition.TransitionManager;
import android.view.View;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.view.ViewTreeObserver;
import android.view.Window;


import java.util.ArrayList;
import java.util.ArrayList;


@@ -59,18 +60,20 @@ class ExitTransitionCoordinator extends ActivityTransitionCoordinator {
    private Bundle mExitSharedElementBundle;
    private Bundle mExitSharedElementBundle;
    private boolean mIsExitStarted;
    private boolean mIsExitStarted;
    private boolean mSharedElementsHidden;
    private boolean mSharedElementsHidden;
    private HideSharedElementsCallback mHideSharedElementsCallback;


    public ExitTransitionCoordinator(Activity activity, ArrayList<String> names,
    public ExitTransitionCoordinator(Activity activity, Window window,
            SharedElementCallback listener, ArrayList<String> names,
            ArrayList<String> accepted, ArrayList<View> mapped, boolean isReturning) {
            ArrayList<String> accepted, ArrayList<View> mapped, boolean isReturning) {
        super(activity.getWindow(), names, getListener(activity, isReturning), isReturning);
        super(window, names, listener, isReturning);
        viewsReady(mapSharedElements(accepted, mapped));
        viewsReady(mapSharedElements(accepted, mapped));
        stripOffscreenViews();
        stripOffscreenViews();
        mIsBackgroundReady = !isReturning;
        mIsBackgroundReady = !isReturning;
        mActivity = activity;
        mActivity = activity;
    }
    }


    private static SharedElementCallback getListener(Activity activity, boolean isReturning) {
    void setHideSharedElementsCallback(HideSharedElementsCallback callback) {
        return isReturning ? activity.mEnterTransitionListener : activity.mExitTransitionListener;
        mHideSharedElementsCallback = callback;
    }
    }


    @Override
    @Override
@@ -188,6 +191,9 @@ class ExitTransitionCoordinator extends ActivityTransitionCoordinator {


    private void hideSharedElements() {
    private void hideSharedElements() {
        moveSharedElementsFromOverlay();
        moveSharedElementsFromOverlay();
        if (mHideSharedElementsCallback != null) {
            mHideSharedElementsCallback.hideSharedElements();
        }
        if (!mIsHidden) {
        if (!mIsHidden) {
            hideViews(mSharedElements);
            hideViews(mSharedElements);
        }
        }
@@ -207,7 +213,11 @@ class ExitTransitionCoordinator extends ActivityTransitionCoordinator {
            startTransition(new Runnable() {
            startTransition(new Runnable() {
                @Override
                @Override
                public void run() {
                public void run() {
                    if (mActivity != null) {
                        beginTransitions();
                        beginTransitions();
                    } else {
                        startExitTransition();
                    }
                }
                }
            });
            });
        }
        }
@@ -508,4 +518,8 @@ class ExitTransitionCoordinator extends ActivityTransitionCoordinator {
            return getWindow().getSharedElementExitTransition();
            return getWindow().getSharedElementExitTransition();
        }
        }
    }
    }

    interface HideSharedElementsCallback {
        void hideSharedElements();
    }
}
}
Loading