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

Commit 1fecfb2d authored by George Mount's avatar George Mount
Browse files

Activity Transitions: don't require transitionName.

Bug 15585623
Bug 15607591

Exit transitions now run because exit transitions are executed
with startActivity.

Change-Id: Ie55793a9514c64d96e2cf1abdd2d39c4d2606a23
parent 51fa6bcb
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -780,7 +780,7 @@ public class Activity extends ContextThemeWrapper
    private Thread mUiThread;
    final Handler mHandler = new Handler();

    private ActivityTransitionState mActivityTransitionState = new ActivityTransitionState();
    ActivityTransitionState mActivityTransitionState = new ActivityTransitionState();
    SharedElementListener mEnterTransitionListener = SharedElementListener.NULL_LISTENER;
    SharedElementListener mExitTransitionListener = SharedElementListener.NULL_LISTENER;

+18 −36
Original line number Diff line number Diff line
@@ -108,9 +108,9 @@ public class ActivityOptions {

    private static final String KEY_TRANSITION_IS_RETURNING = "android:transitionIsReturning";
    private static final String KEY_TRANSITION_SHARED_ELEMENTS = "android:sharedElementNames";
    private static final String KEY_LOCAL_SHARED_ELEMENTS = "android:localSharedElementNames";
    private static final String KEY_RESULT_DATA = "android:resultData";
    private static final String KEY_RESULT_CODE = "android:resultCode";
    private static final String KEY_EXIT_COORDINATOR_INDEX = "android:exitCoordinatorIndex";

    /** @hide */
    public static final int ANIM_NONE = 0;
@@ -138,9 +138,9 @@ public class ActivityOptions {
    private ResultReceiver mTransitionReceiver;
    private boolean mIsReturning;
    private ArrayList<String> mSharedElementNames;
    private ArrayList<String> mLocalSharedElementNames;
    private Intent mResultData;
    private int mResultCode;
    private int mExitCoordinatorIndex;

    /**
     * Create an ActivityOptions specifying a custom animation to run when
@@ -387,7 +387,7 @@ public class ActivityOptions {
        opts.mAnimationType = ANIM_SCENE_TRANSITION;

        ArrayList<String> names = new ArrayList<String>();
        ArrayList<String> mappedNames = new ArrayList<String>();
        ArrayList<View> views = new ArrayList<View>();

        if (sharedElements != null) {
            for (int i = 0; i < sharedElements.length; i++) {
@@ -396,23 +396,22 @@ public class ActivityOptions {
                if (sharedElementName == null) {
                    throw new IllegalArgumentException("Shared element name must not be null");
                }
                String name = sharedElement.first.getTransitionName();
                if (name == null) {
                    throw new IllegalArgumentException("Shared elements must have non-null " +
                            "transitionNames");
                }

                names.add(sharedElementName);
                mappedNames.add(name);
                View view = sharedElement.first;
                if (view == null) {
                    throw new IllegalArgumentException("Shared element must not be null");
                }
                views.add(sharedElement.first);
            }
        }

        ExitTransitionCoordinator exit = new ExitTransitionCoordinator(activity, names, names,
                mappedNames, false);
                views, false);
        opts.mTransitionReceiver = exit;
        opts.mSharedElementNames = names;
        opts.mLocalSharedElementNames = mappedNames;
        opts.mIsReturning = false;
        opts.mExitCoordinatorIndex =
                activity.mActivityTransitionState.addExitTransitionCoordinator(exit);
        return opts;
    }

@@ -427,6 +426,8 @@ public class ActivityOptions {
        opts.mIsReturning = true;
        opts.mResultCode = resultCode;
        opts.mResultData = resultData;
        opts.mExitCoordinatorIndex =
                activity.mActivityTransitionState.addExitTransitionCoordinator(exitCoordinator);
        return opts;
    }

@@ -465,9 +466,9 @@ public class ActivityOptions {
                mTransitionReceiver = opts.getParcelable(KEY_TRANSITION_COMPLETE_LISTENER);
                mIsReturning = opts.getBoolean(KEY_TRANSITION_IS_RETURNING, false);
                mSharedElementNames = opts.getStringArrayList(KEY_TRANSITION_SHARED_ELEMENTS);
                mLocalSharedElementNames = opts.getStringArrayList(KEY_LOCAL_SHARED_ELEMENTS);
                mResultData = opts.getParcelable(KEY_RESULT_DATA);
                mResultCode = opts.getInt(KEY_RESULT_CODE);
                mExitCoordinatorIndex = opts.getInt(KEY_EXIT_COORDINATOR_INDEX);
                break;
        }
    }
@@ -523,18 +524,7 @@ public class ActivityOptions {
    }

    /** @hide */
    public void dispatchActivityStopped() {
        if (mTransitionReceiver != null) {
            mTransitionReceiver.send(ActivityTransitionCoordinator.MSG_ACTIVITY_STOPPED, null);
        }
    }

    /** @hide */
    public void dispatchStartExit() {
        if (mTransitionReceiver != null) {
            mTransitionReceiver.send(ActivityTransitionCoordinator.MSG_START_EXIT_TRANSITION, null);
        }
    }
    public int getExitCoordinatorKey() { return mExitCoordinatorIndex; }

    /** @hide */
    public void abort() {
@@ -546,11 +536,6 @@ public class ActivityOptions {
        }
    }

    /** @hide */
    public void setReturning() {
        mIsReturning = true;
    }

    /** @hide */
    public boolean isReturning() {
        return mIsReturning;
@@ -561,9 +546,6 @@ public class ActivityOptions {
        return mSharedElementNames;
    }

    /** @hide */
    public ArrayList<String> getLocalSharedElementNames() { return mLocalSharedElementNames; }

    /** @hide */
    public ResultReceiver getResultReceiver() { return mTransitionReceiver; }

@@ -591,10 +573,10 @@ public class ActivityOptions {
        }
        mTransitionReceiver = null;
        mSharedElementNames = null;
        mLocalSharedElementNames = null;
        mIsReturning = false;
        mResultData = null;
        mResultCode = 0;
        mExitCoordinatorIndex = 0;
        switch (otherOptions.mAnimationType) {
            case ANIM_CUSTOM:
                mAnimationType = otherOptions.mAnimationType;
@@ -641,12 +623,12 @@ public class ActivityOptions {
                mAnimationType = otherOptions.mAnimationType;
                mTransitionReceiver = otherOptions.mTransitionReceiver;
                mSharedElementNames = otherOptions.mSharedElementNames;
                mLocalSharedElementNames = otherOptions.mLocalSharedElementNames;
                mIsReturning = otherOptions.mIsReturning;
                mThumbnail = null;
                mAnimationStartedListener = null;
                mResultData = otherOptions.mResultData;
                mResultCode = otherOptions.mResultCode;
                mExitCoordinatorIndex = otherOptions.mExitCoordinatorIndex;
                break;
        }
    }
@@ -695,9 +677,9 @@ public class ActivityOptions {
                }
                b.putBoolean(KEY_TRANSITION_IS_RETURNING, mIsReturning);
                b.putStringArrayList(KEY_TRANSITION_SHARED_ELEMENTS, mSharedElementNames);
                b.putStringArrayList(KEY_LOCAL_SHARED_ELEMENTS, mLocalSharedElementNames);
                b.putParcelable(KEY_RESULT_DATA, mResultData);
                b.putInt(KEY_RESULT_CODE, mResultCode);
                b.putInt(KEY_EXIT_COORDINATOR_INDEX, mExitCoordinatorIndex);
                break;
        }
        return b;
+27 −43
Original line number Diff line number Diff line
@@ -150,12 +150,6 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver {
     */
    public static final int MSG_HIDE_SHARED_ELEMENTS = 101;

    /**
     * Sent by the exiting Activity in ActivityOptions#dispatchActivityStopped
     * to leave the Activity in a good state after it has been hidden.
     */
    public static final int MSG_ACTIVITY_STOPPED = 102;

    /**
     * Sent by the exiting coordinator (either EnterTransitionCoordinator
     * or ExitTransitionCoordinator) after the shared elements have
@@ -209,15 +203,6 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver {
    private Runnable mPendingTransition;
    private boolean mIsStartingTransition;


    public ActivityTransitionCoordinator(Window window,
            ArrayList<String> allSharedElementNames,
            ArrayList<String> accepted, ArrayList<String> localNames,
            SharedElementListener listener, boolean isReturning) {
        this(window, allSharedElementNames, listener, isReturning);
        viewsReady(accepted, localNames);
    }

    public ActivityTransitionCoordinator(Window window,
            ArrayList<String> allSharedElementNames,
            SharedElementListener listener, boolean isReturning) {
@@ -228,8 +213,8 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver {
        mIsReturning = isReturning;
    }

    protected void viewsReady(ArrayList<String> accepted, ArrayList<String> localNames) {
        setSharedElements(accepted, localNames);
    protected void viewsReady(ArrayMap<String, View> sharedElements) {
        setSharedElements(sharedElements);
        if (getViewsTransition() != null) {
            getDecor().captureTransitioningViews(mTransitioningViews);
            mTransitioningViews.removeAll(mSharedElements);
@@ -286,6 +271,10 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver {
        return names;
    }

    public ArrayList<View> getMappedViews() {
        return mSharedElements;
    }

    public ArrayList<String> getAllSharedElementNames() { return mAllSharedElementNames; }

    public static void setViewVisibility(Collection<View> views, int visibility) {
@@ -335,22 +324,22 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver {
        }
    }

    private void setSharedElements(ArrayList<String> accepted, ArrayList<String> localNames) {
        if (!mAllSharedElementNames.isEmpty()) {
    protected ArrayMap<String, View> mapSharedElements(ArrayList<String> accepted,
            ArrayList<View> localViews) {
        ArrayMap<String, View> sharedElements = new ArrayMap<String, View>();
            getDecor().findNamedViews(sharedElements);
        if (!mAllSharedElementNames.isEmpty()) {
            if (accepted != null) {
                for (int i = 0; i < localNames.size(); i++) {
                    String localName = localNames.get(i);
                    String acceptedName = accepted.get(i);
                    if (!localName.equals(acceptedName)) {
                        View view = sharedElements.remove(localName);
                        if (view != null) {
                            sharedElements.put(acceptedName, view);
                for (int i = 0; i < accepted.size(); i++) {
                    sharedElements.put(accepted.get(i), localViews.get(i));
                }
            } else {
                getDecor().findNamedViews(sharedElements);
            }
        }
        return sharedElements;
    }

    private void setSharedElements(ArrayMap<String, View> sharedElements) {
        sharedElements.retainAll(mAllSharedElementNames);
        mListener.remapSharedElements(mAllSharedElementNames, sharedElements);
        sharedElements.retainAll(mAllSharedElementNames);
@@ -358,16 +347,11 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver {
            String name = mAllSharedElementNames.get(i);
            View sharedElement = sharedElements.get(name);
            if (sharedElement != null) {
                    if (sharedElement.getTransitionName() == null) {
                        throw new IllegalArgumentException("Shared elements must have " +
                                "non-null transitionNames");
                    }
                mSharedElementNames.add(name);
                mSharedElements.add(sharedElement);
            }
        }
    }
    }

    protected void setResultReceiver(ResultReceiver resultReceiver) {
        mResultReceiver = resultReceiver;
+63 −34
Original line number Diff line number Diff line
@@ -18,9 +18,11 @@ package android.app;
import android.os.Bundle;
import android.os.ResultReceiver;
import android.util.ArrayMap;
import android.util.SparseArray;
import android.view.View;
import android.view.Window;

import java.lang.ref.WeakReference;
import java.util.ArrayList;

/**
@@ -31,10 +33,6 @@ class ActivityTransitionState {

    private static final String ENTERING_SHARED_ELEMENTS = "android:enteringSharedElements";

    private static final String ENTERING_MAPPED_FROM = "android:enteringMappedFrom";

    private static final String ENTERING_MAPPED_TO = "android:enteringMappedTo";

    private static final String EXITING_MAPPED_FROM = "android:exitingMappedFrom";

    private static final String EXITING_MAPPED_TO = "android:exitingMappedTo";
@@ -45,16 +43,6 @@ class ActivityTransitionState {
     */
    private ArrayList<String> mEnteringNames;

    /**
     * The shared elements that this Activity as accepted and mapped to local Views.
     */
    private ArrayList<String> mEnteringFrom;

    /**
     * The names of local Views that are mapped to those elements in mEnteringFrom.
     */
    private ArrayList<String> mEnteringTo;

    /**
     * The names of shared elements that were shared to the called Activity.
     */
@@ -66,10 +54,15 @@ class ActivityTransitionState {
    private ArrayList<String> mExitingTo;

    /**
     * The ActivityOptions used to call an Activity. Used to make the elements restore
     * The local Views that were shared out, mapped to those elements in mExitingFrom.
     */
    private ArrayList<View> mExitingToView;

    /**
     * The ExitTransitionCoordinator used to start an Activity. Used to make the elements restore
     * Visibility of exited Views.
     */
    private ActivityOptions mCalledActivityOptions;
    private ExitTransitionCoordinator mCalledExitCoordinator;

    /**
     * We must be able to cancel entering transitions to stop changing the Window to
@@ -92,15 +85,42 @@ class ActivityTransitionState {
     */
    private boolean mIsEnterPostponed;

    /**
     * Potential exit transition coordinators.
     */
    private SparseArray<WeakReference<ExitTransitionCoordinator>> mExitTransitionCoordinators;

    /**
     * Next key for mExitTransitionCoordinator.
     */
    private int mExitTransitionCoordinatorsKey = 1;

    public ActivityTransitionState() {
    }

    public int addExitTransitionCoordinator(ExitTransitionCoordinator exitTransitionCoordinator) {
        if (mExitTransitionCoordinators == null) {
            mExitTransitionCoordinators =
                    new SparseArray<WeakReference<ExitTransitionCoordinator>>();
        }
        WeakReference<ExitTransitionCoordinator> ref = new WeakReference(exitTransitionCoordinator);
        // clean up old references:
        for (int i = mExitTransitionCoordinators.size() - 1; i >= 0; i--) {
            WeakReference<ExitTransitionCoordinator> oldRef
                    = mExitTransitionCoordinators.valueAt(i);
            if (oldRef.get() == null) {
                mExitTransitionCoordinators.removeAt(i);
            }
        }
        int newKey = mExitTransitionCoordinatorsKey++;
        mExitTransitionCoordinators.append(newKey, ref);
        return newKey;
    }

    public void readState(Bundle bundle) {
        if (bundle != null) {
            if (mEnterTransitionCoordinator == null || mEnterTransitionCoordinator.isReturning()) {
                mEnteringNames = bundle.getStringArrayList(ENTERING_SHARED_ELEMENTS);
                mEnteringFrom = bundle.getStringArrayList(ENTERING_MAPPED_FROM);
                mEnteringTo = bundle.getStringArrayList(ENTERING_MAPPED_TO);
            }
            if (mEnterTransitionCoordinator == null) {
                mExitingFrom = bundle.getStringArrayList(EXITING_MAPPED_FROM);
@@ -112,8 +132,6 @@ class ActivityTransitionState {
    public void saveState(Bundle bundle) {
        if (mEnteringNames != null) {
            bundle.putStringArrayList(ENTERING_SHARED_ELEMENTS, mEnteringNames);
            bundle.putStringArrayList(ENTERING_MAPPED_FROM, mEnteringFrom);
            bundle.putStringArrayList(ENTERING_MAPPED_TO, mEnteringTo);
        }
        if (mExitingFrom != null) {
            bundle.putStringArrayList(EXITING_MAPPED_FROM, mExitingFrom);
@@ -169,16 +187,19 @@ class ActivityTransitionState {

    private void startEnter() {
        if (mEnterActivityOptions.isReturning()) {
            mEnterTransitionCoordinator.viewsReady(mExitingFrom, mExitingTo);
            if (mExitingToView != null) {
                mEnterTransitionCoordinator.viewInstancesReady(mExitingFrom, mExitingToView);
            } else {
                mEnterTransitionCoordinator.namedViewsReady(mExitingFrom, mExitingTo);
            }
        } else {
            mEnterTransitionCoordinator.viewsReady(null, null);
            mEnterTransitionCoordinator.namedViewsReady(null, null);
            mEnteringNames = mEnterTransitionCoordinator.getAllSharedElementNames();
            mEnteringFrom = mEnterTransitionCoordinator.getAcceptedNames();
            mEnteringTo = mEnterTransitionCoordinator.getMappedNames();
        }

        mExitingFrom = null;
        mExitingTo = null;
        mExitingToView = null;
        mEnterActivityOptions = null;
    }

@@ -195,9 +216,9 @@ class ActivityTransitionState {
    }

    private void restoreExitedViews() {
        if (mCalledActivityOptions != null) {
            mCalledActivityOptions.dispatchActivityStopped();
            mCalledActivityOptions = null;
        if (mCalledExitCoordinator != null) {
            mCalledExitCoordinator.resetViews();
            mCalledExitCoordinator = null;
        }
    }

@@ -215,8 +236,7 @@ class ActivityTransitionState {
                activity.getWindow().getDecorView().findNamedViews(sharedElements);

                ExitTransitionCoordinator exitCoordinator =
                        new ExitTransitionCoordinator(activity, mEnteringNames, mEnteringFrom,
                                mEnteringTo, true);
                        new ExitTransitionCoordinator(activity, mEnteringNames, null, null, true);
                exitCoordinator.startExit(activity.mResultCode, activity.mResultData);
            }
            return true;
@@ -227,11 +247,20 @@ class ActivityTransitionState {
        if (!activity.getWindow().hasFeature(Window.FEATURE_CONTENT_TRANSITIONS)) {
            return;
        }
        mCalledActivityOptions = new ActivityOptions(options);
        if (mCalledActivityOptions.getAnimationType() == ActivityOptions.ANIM_SCENE_TRANSITION) {
            mExitingFrom = mCalledActivityOptions.getSharedElementNames();
            mExitingTo = mCalledActivityOptions.getLocalSharedElementNames();
            mCalledActivityOptions.dispatchStartExit();
        ActivityOptions activityOptions = new ActivityOptions(options);
        if (activityOptions.getAnimationType() == ActivityOptions.ANIM_SCENE_TRANSITION) {
            int key = activityOptions.getExitCoordinatorKey();
            int index = mExitTransitionCoordinators.indexOfKey(key);
            if (index >= 0) {
                mCalledExitCoordinator = mExitTransitionCoordinators.valueAt(index).get();
                mExitTransitionCoordinators.removeAt(index);
                if (mCalledExitCoordinator != null) {
                    mExitingFrom = mCalledExitCoordinator.getAcceptedNames();
                    mExitingTo = mCalledExitCoordinator.getMappedNames();
                    mExitingToView = mCalledExitCoordinator.getMappedViews();
                    mCalledExitCoordinator.startExit();
                }
            }
        }
    }
}
+33 −2
Original line number Diff line number Diff line
@@ -79,12 +79,24 @@ class EnterTransitionCoordinator extends ActivityTransitionCoordinator {
                });
    }

    public void viewsReady(ArrayList<String> accepted, ArrayList<String> localNames) {
    public void viewInstancesReady(ArrayList<String> accepted, ArrayList<View> localViews) {
        if (mIsReadyForTransition) {
            return;
        }
        super.viewsReady(accepted, localNames);
        viewsReady(mapSharedElements(accepted, localViews));
    }

    public void namedViewsReady(ArrayList<String> accepted, ArrayList<String> localNames) {
        if (mIsReadyForTransition) {
            return;
        }

        viewsReady(mapNamedElements(accepted, localNames));
    }

    @Override
    protected void viewsReady(ArrayMap<String, View> sharedElements) {
        super.viewsReady(sharedElements);
        mIsReadyForTransition = true;
        if (mIsReturning) {
            mHandler = new Handler() {
@@ -105,6 +117,25 @@ class EnterTransitionCoordinator extends ActivityTransitionCoordinator {
        }
    }

    private ArrayMap<String, View> mapNamedElements(ArrayList<String> accepted,
            ArrayList<String> localNames) {
        ArrayMap<String, View> sharedElements = new ArrayMap<String, View>();
        getDecor().findNamedViews(sharedElements);
        if (accepted != null) {
            for (int i = 0; i < localNames.size(); i++) {
                String localName = localNames.get(i);
                String acceptedName = accepted.get(i);
                if (localName != null && !localName.equals(acceptedName)) {
                    View view = sharedElements.remove(localName);
                    if (view != null) {
                        sharedElements.put(acceptedName, view);
                    }
                }
            }
        }
        return sharedElements;
    }

    private void sendSharedElementDestination() {
        ViewGroup decor = getDecor();
        boolean allReady = !decor.isLayoutRequested();
Loading