am 99d2ffa1: Merge "Split Activity Transitions out of PhoneWindow."

* commit '99d2ffa1268da1258390fa6f272bf41687084d7b':
  Split Activity Transitions out of PhoneWindow.
This commit is contained in:
George Mount
2014-04-17 18:13:30 +00:00
committed by Android Git Automerger
20 changed files with 1745 additions and 1146 deletions

View File

@@ -948,10 +948,6 @@ public abstract class ActionBar {
public void dispatchMenuVisibilityChanged(boolean visible) {
}
/** @hide */
public void captureSharedElements(Map<String, View> sharedElements) {
}
/** @hide */
public ActionMode startActionMode(ActionMode.Callback callback) {
return null;

View File

@@ -18,7 +18,6 @@ package android.app;
import android.annotation.NonNull;
import android.transition.Scene;
import android.transition.Transition;
import android.transition.TransitionManager;
import android.util.ArrayMap;
import android.util.SuperNotCalledException;
@@ -773,6 +772,8 @@ public class Activity extends ContextThemeWrapper
private Thread mUiThread;
final Handler mHandler = new Handler();
private ActivityOptions mCalledActivityOptions;
private EnterTransitionCoordinator mEnterTransitionCoordinator;
/** Return the intent that started this activity. */
public Intent getIntent() {
@@ -1026,6 +1027,9 @@ public class Activity extends ContextThemeWrapper
mTitleReady = true;
onTitleChanged(getTitle(), getTitleColor());
}
if (mEnterTransitionCoordinator != null) {
mEnterTransitionCoordinator.readyToEnter();
}
mCalled = true;
}
@@ -1106,6 +1110,7 @@ public class Activity extends ContextThemeWrapper
protected void onResume() {
if (DEBUG_LIFECYCLE) Slog.v(TAG, "onResume " + this);
getApplication().dispatchActivityResumed(this);
mCalledActivityOptions = null;
mCalled = true;
}
@@ -1398,8 +1403,9 @@ public class Activity extends ContextThemeWrapper
protected void onStop() {
if (DEBUG_LIFECYCLE) Slog.v(TAG, "onStop " + this);
if (mActionBar != null) mActionBar.setShowHideAnimationEnabled(false);
if (mWindow != null) {
mWindow.restoreViewVisibilityAfterTransitionToCallee();
if (mCalledActivityOptions != null) {
mCalledActivityOptions.dispatchActivityStopped();
mCalledActivityOptions = null;
}
getApplication().dispatchActivityStopped(this);
mTranslucentCallback = null;
@@ -3484,7 +3490,7 @@ public class Activity extends ContextThemeWrapper
public void startActivityForResult(Intent intent, int requestCode) {
Bundle options = null;
if (mWindow.hasFeature(Window.FEATURE_CONTENT_TRANSITIONS)) {
options = ActivityOptions.makeSceneTransitionAnimation().toBundle();
options = ActivityOptions.makeSceneTransitionAnimation(mWindow, null).toBundle();
}
startActivityForResult(intent, requestCode, options);
}
@@ -3526,14 +3532,8 @@ public class Activity extends ContextThemeWrapper
public void startActivityForResult(Intent intent, int requestCode, @Nullable Bundle options) {
if (options != null) {
ActivityOptions activityOptions = new ActivityOptions(options);
if (activityOptions.getAnimationType() == ActivityOptions.ANIM_SCENE_TRANSITION) {
if (mActionBar != null) {
ArrayMap<String, View> sharedElementMap = new ArrayMap<String, View>();
mActionBar.captureSharedElements(sharedElementMap);
activityOptions.addSharedElements(sharedElementMap);
}
options = mWindow.startExitTransitionToCallee(options);
}
activityOptions.dispatchStartExit();
mCalledActivityOptions = activityOptions;
}
if (mParent == null) {
Instrumentation.ActivityResult ar =
@@ -4391,16 +4391,15 @@ public class Activity extends ContextThemeWrapper
* to reverse its exit Transition. When the exit Transition completes,
* {@link #finish()} is called. If no entry Transition was used, finish() is called
* immediately and the Activity exit Transition is run.
* @see android.view.Window#setTriggerEarlySceneTransition(boolean, boolean)
* @see android.app.ActivityOptions#makeSceneTransitionAnimation(android.view.View, String)
* @see android.app.ActivityOptions#makeSceneTransitionAnimation(android.view.Window,
* android.app.ActivityOptions.ActivityTransitionListener)
*/
public void finishWithTransition() {
mWindow.startExitTransitionToCaller(new Runnable() {
@Override
public void run() {
finish();
}
});
if (mEnterTransitionCoordinator != null) {
mEnterTransitionCoordinator.startExit();
} else {
finish();
}
}
/**
@@ -5346,6 +5345,21 @@ public class Activity extends ContextThemeWrapper
}
}
/**
* When {@link android.app.ActivityOptions#makeSceneTransitionAnimation(android.view.Window,
* android.app.ActivityOptions.ActivityTransitionListener)} was used to start an Activity,
* the Window will be triggered to enter with a Transition. <code>listener</code> allows
* The Activity to listen to events of the entering transition and control the mapping of
* shared elements. This requires {@link Window#FEATURE_CONTENT_TRANSITIONS}.
*
* @param listener Used to listen to events in the entering transition.
*/
public void setActivityTransitionListener(ActivityOptions.ActivityTransitionListener listener) {
if (mEnterTransitionCoordinator != null) {
mEnterTransitionCoordinator.setActivityTransitionListener(listener);
}
}
// ------------------ Internal API ------------------
final void setParent(Activity parent) {
@@ -5413,34 +5427,12 @@ public class Activity extends ContextThemeWrapper
}
mWindowManager = mWindow.getWindowManager();
mCurrentConfig = config;
Window.SceneTransitionListener sceneTransitionListener
= new Window.SceneTransitionListener() {
@Override
public void nullPendingTransition() {
overridePendingTransition(0, 0);
if (options != null) {
ActivityOptions activityOptions = new ActivityOptions(options);
if (activityOptions.getAnimationType() == ActivityOptions.ANIM_SCENE_TRANSITION) {
mEnterTransitionCoordinator = activityOptions.createEnterActivityTransition(this);
}
@Override
public void convertFromTranslucent() {
Activity.this.convertFromTranslucent();
}
@Override
public void convertToTranslucent() {
Activity.this.convertToTranslucent(null);
}
@Override
public void sharedElementStart(Transition transition) {
Activity.this.onCaptureSharedElementStart(transition);
}
@Override
public void sharedElementEnd() {
Activity.this.onCaptureSharedElementEnd();
}
};
mWindow.setTransitionOptions(options, sceneTransitionListener);
}
}
/** @hide */
@@ -5627,26 +5619,6 @@ public class Activity extends ContextThemeWrapper
}
}
/**
* Called when setting up Activity Scene transitions when the start state for shared
* elements has been captured. Override this method to modify the start position of shared
* elements for the entry Transition.
*
* @param transition The <code>Transition</code> being used to change
* bounds of shared elements in the source Activity to
* the bounds defined by the entering Scene.
*/
public void onCaptureSharedElementStart(Transition transition) {
}
/**
* Called when setting up Activity Scene transitions when the final state for
* shared elements state has been captured. Override this method to modify the destination
* position of shared elements for the entry Transition.
*/
public void onCaptureSharedElementEnd() {
}
/**
* @hide
*/

View File

@@ -20,16 +20,16 @@ import android.content.Context;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.IRemoteCallback;
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.transition.Transition;
import android.util.Log;
import android.util.ArrayMap;
import android.util.Pair;
import android.view.View;
import android.view.Window;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
@@ -108,23 +108,6 @@ public class ActivityOptions {
private static final String KEY_TRANSITION_COMPLETE_LISTENER
= "android:transitionCompleteListener";
/**
* For Activity transitions, the called Activity's listener to receive calls
* when transitions complete.
*/
private static final String KEY_TRANSITION_TARGET_LISTENER = "android:transitionTargetListener";
/**
* The names of shared elements that are transitioned to the started Activity.
* This is also the name of shared elements that the started Activity accepted.
*/
private static final String KEY_SHARED_ELEMENT_NAMES = "android:shared_element_names";
/**
* The shared elements names of the views in the calling Activity.
*/
private static final String KEY_LOCAL_ELEMENT_NAMES = "android:local_element_names";
/** @hide */
public static final int ANIM_NONE = 0;
/** @hide */
@@ -138,11 +121,6 @@ public class ActivityOptions {
/** @hide */
public static final int ANIM_SCENE_TRANSITION = 5;
private static final int MSG_SET_LISTENER = 100;
private static final int MSG_HIDE_SHARED_ELEMENTS = 101;
private static final int MSG_PREPARE_RESTORE = 102;
private static final int MSG_RESTORE = 103;
private String mPackageName;
private int mAnimationType = ANIM_NONE;
private int mCustomEnterResId;
@@ -153,9 +131,7 @@ public class ActivityOptions {
private int mStartWidth;
private int mStartHeight;
private IRemoteCallback mAnimationStartedListener;
private ResultReceiver mTransitionCompleteListener;
private ArrayList<String> mSharedElementNames;
private ArrayList<String> mLocalElementNames;
private ResultReceiver mExitReceiver;
/**
* Create an ActivityOptions specifying a custom animation to run when
@@ -231,12 +207,6 @@ public class ActivityOptions {
void onAnimationStarted();
}
/** @hide */
public interface ActivityTransitionTarget {
void sharedElementTransitionComplete(Bundle transitionArgs);
void exitTransitionComplete();
}
/**
* Create an ActivityOptions specifying an animation where the new
* activity is scaled from a small originating area of the screen to
@@ -357,49 +327,53 @@ public class ActivityOptions {
/**
* Create an ActivityOptions to transition between Activities using cross-Activity scene
* animations. This method carries the position of one shared element to the started Activity.
* The position of <code>sharedElement</code> will be used as the epicenter for the
* exit Transition. The position of the shared element in the launched Activity will be the
* epicenter of its entering Transition.
*
* <p>This requires {@link android.view.Window#FEATURE_CONTENT_TRANSITIONS} to be
* enabled on the calling Activity to cause an exit transition. The same must be in
* the called Activity to get an entering transition.</p>
* @param window The window containing shared elements.
* @param sharedElement The View to transition to the started Activity. sharedElement must
* have a non-null sharedElementName.
* @param sharedElementName The shared element name as used in the target Activity. This may
* be null if it has the same name as sharedElement.
* @return Returns a new ActivityOptions object that you can use to
* supply these options as the options Bundle when starting an activity.
* @see android.transition.Transition#setEpicenterCallback(
* android.transition.Transition.EpicenterCallback)
*/
public static ActivityOptions makeSceneTransitionAnimation(View sharedElement,
String sharedElementName) {
return makeSceneTransitionAnimation(
new Pair<View, String>(sharedElement, sharedElementName));
public static ActivityOptions makeSceneTransitionAnimation(Window window,
View sharedElement, String sharedElementName) {
return makeSceneTransitionAnimation(window,
new SharedElementMappingListener(sharedElement, sharedElementName));
}
/**
* Create an ActivityOptions to transition between Activities using cross-Activity scene
* animations. This method carries the position of multiple shared elements to the started
* Activity.
* Activity. The position of the first element in the value returned from
* {@link android.app.ActivityOptions.ActivityTransitionListener#getSharedElementsMapping()}
* will be used as the epicenter for the exit Transition. The position of the associated
* shared element in the launched Activity will be the epicenter of its entering Transition.
*
* <p>This requires {@link android.view.Window#FEATURE_CONTENT_TRANSITIONS} to be
* enabled on the calling Activity to cause an exit transition. The same must be in
* the called Activity to get an entering transition.</p>
* @param sharedElements The View to transition to the started Activity along with the
* shared element name as used in the started Activity. The view
* must have a non-null sharedElementName.
* @param window The window containing shared elements.
* @param listener The listener to use to monitor activity transition events.
* @return Returns a new ActivityOptions object that you can use to
* supply these options as the options Bundle when starting an activity.
* @see android.transition.Transition#setEpicenterCallback(
* android.transition.Transition.EpicenterCallback)
*/
public static ActivityOptions makeSceneTransitionAnimation(
Pair<View, String>... sharedElements) {
public static ActivityOptions makeSceneTransitionAnimation(Window window,
ActivityTransitionListener listener) {
ActivityOptions opts = new ActivityOptions();
opts.mAnimationType = ANIM_SCENE_TRANSITION;
opts.mSharedElementNames = new ArrayList<String>();
opts.mLocalElementNames = new ArrayList<String>();
if (sharedElements != null) {
for (Pair<View, String> sharedElement : sharedElements) {
opts.addSharedElement(sharedElement.first, sharedElement.second);
}
}
ExitTransitionCoordinator exit = new ExitTransitionCoordinator(window, listener);
opts.mExitReceiver = exit;
return opts;
}
@@ -435,9 +409,7 @@ public class ActivityOptions {
break;
case ANIM_SCENE_TRANSITION:
mTransitionCompleteListener = opts.getParcelable(KEY_TRANSITION_COMPLETE_LISTENER);
mSharedElementNames = opts.getStringArrayList(KEY_SHARED_ELEMENT_NAMES);
mLocalElementNames = opts.getStringArrayList(KEY_LOCAL_ELEMENT_NAMES);
mExitReceiver = opts.getParcelable(KEY_TRANSITION_COMPLETE_LISTENER);
break;
}
}
@@ -493,50 +465,16 @@ public class ActivityOptions {
}
/** @hide */
public ArrayList<String> getSharedElementNames() { return mSharedElementNames; }
/** @hide */
public ArrayList<String> getLocalElementNames() { return mLocalElementNames; }
/** @hide */
public void dispatchSceneTransitionStarted(final ActivityTransitionTarget target,
ArrayList<String> sharedElementNames) {
if (mTransitionCompleteListener != null) {
IRemoteCallback callback = new IRemoteCallback.Stub() {
@Override
public void sendResult(Bundle data) throws RemoteException {
if (data == null) {
target.exitTransitionComplete();
} else {
target.sharedElementTransitionComplete(data);
}
}
};
Bundle bundle = new Bundle();
bundle.putBinder(KEY_TRANSITION_TARGET_LISTENER, callback.asBinder());
bundle.putStringArrayList(KEY_SHARED_ELEMENT_NAMES, sharedElementNames);
mTransitionCompleteListener.send(MSG_SET_LISTENER, bundle);
public void dispatchActivityStopped() {
if (mExitReceiver != null) {
mExitReceiver.send(ActivityTransitionCoordinator.MSG_ACTIVITY_STOPPED, null);
}
}
/** @hide */
public void dispatchSharedElementsReady() {
if (mTransitionCompleteListener != null) {
mTransitionCompleteListener.send(MSG_HIDE_SHARED_ELEMENTS, null);
}
}
/** @hide */
public void dispatchPrepareRestore() {
if (mTransitionCompleteListener != null) {
mTransitionCompleteListener.send(MSG_PREPARE_RESTORE, null);
}
}
/** @hide */
public void dispatchRestore(Bundle sharedElementsArgs) {
if (mTransitionCompleteListener != null) {
mTransitionCompleteListener.send(MSG_RESTORE, sharedElementsArgs);
public void dispatchStartExit() {
if (mExitReceiver != null) {
mExitReceiver.send(ActivityTransitionCoordinator.MSG_START_EXIT_TRANSITION, null);
}
}
@@ -557,6 +495,15 @@ public class ActivityOptions {
}
}
/** @hide */
public EnterTransitionCoordinator createEnterActivityTransition(Activity activity) {
EnterTransitionCoordinator coordinator = null;
if (mAnimationType == ANIM_SCENE_TRANSITION) {
coordinator = new EnterTransitionCoordinator(activity, mExitReceiver);
}
return coordinator;
}
/**
* Update the current values in this ActivityOptions from those supplied
* in <var>otherOptions</var>. Any values
@@ -566,8 +513,7 @@ public class ActivityOptions {
if (otherOptions.mPackageName != null) {
mPackageName = otherOptions.mPackageName;
}
mSharedElementNames = null;
mLocalElementNames = null;
mExitReceiver = null;
switch (otherOptions.mAnimationType) {
case ANIM_CUSTOM:
mAnimationType = otherOptions.mAnimationType;
@@ -581,7 +527,6 @@ public class ActivityOptions {
}
}
mAnimationStartedListener = otherOptions.mAnimationStartedListener;
mTransitionCompleteListener = null;
break;
case ANIM_SCALE_UP:
mAnimationType = otherOptions.mAnimationType;
@@ -596,7 +541,6 @@ public class ActivityOptions {
}
}
mAnimationStartedListener = null;
mTransitionCompleteListener = null;
break;
case ANIM_THUMBNAIL_SCALE_UP:
case ANIM_THUMBNAIL_SCALE_DOWN:
@@ -611,15 +555,12 @@ public class ActivityOptions {
}
}
mAnimationStartedListener = otherOptions.mAnimationStartedListener;
mTransitionCompleteListener = null;
break;
case ANIM_SCENE_TRANSITION:
mAnimationType = otherOptions.mAnimationType;
mTransitionCompleteListener = otherOptions.mTransitionCompleteListener;
mExitReceiver = otherOptions.mExitReceiver;
mThumbnail = null;
mAnimationStartedListener = null;
mSharedElementNames = otherOptions.mSharedElementNames;
mLocalElementNames = otherOptions.mLocalElementNames;
break;
}
}
@@ -663,11 +604,9 @@ public class ActivityOptions {
break;
case ANIM_SCENE_TRANSITION:
b.putInt(KEY_ANIM_TYPE, mAnimationType);
if (mTransitionCompleteListener != null) {
b.putParcelable(KEY_TRANSITION_COMPLETE_LISTENER, mTransitionCompleteListener);
if (mExitReceiver != null) {
b.putParcelable(KEY_TRANSITION_COMPLETE_LISTENER, mExitReceiver);
}
b.putStringArrayList(KEY_SHARED_ELEMENT_NAMES, mSharedElementNames);
b.putStringArrayList(KEY_LOCAL_ELEMENT_NAMES, mLocalElementNames);
break;
}
return b;
@@ -687,130 +626,92 @@ public class ActivityOptions {
return null;
}
/** @hide */
public void addSharedElements(Map<String, View> sharedElements) {
for (Map.Entry<String, View> entry : sharedElements.entrySet()) {
addSharedElement(entry.getValue(), entry.getKey());
}
/**
* Listener provided in
* {@link android.app.ActivityOptions#makeSceneTransitionAnimation(android.view.Window,
* android.app.ActivityOptions.ActivityTransitionListener)} or in
* {@link android.app.Activity#setActivityTransitionListener(
* android.app.ActivityOptions.ActivityTransitionListener)} to monitor the Activity transitions.
* The events can be used to customize or override Activity Transition behavior.
*/
public static class ActivityTransitionListener {
/**
* Called when the enter Transition is ready to start, but hasn't started yet. If
* {@link android.view.Window#getEnterTransition()} is non-null,
* The entering views will be {@link View#INVISIBLE}.
*/
public void onEnterReady() {}
/**
* Called when the remote exiting transition completes.
*/
public void onRemoteExitComplete() {}
/**
* Called when the start state for shared elements is captured on enter.
*/
public void onCaptureSharedElementStart() {}
/**
* Called when the end state for shared elements is captured on enter.
*/
public void onCaptureSharedElementEnd() {}
/**
* Called when the enter Transition has been started.
* @param sharedElementNames The names of shared elements that were transferred.
* @param sharedElements The shared elements that were transferred.
*/
public void onStartEnterTransition(List<String> sharedElementNames,
List<View> sharedElements) {}
/**
* Called when the exit Transition has been started.
* @param sharedElementNames The names of all shared elements that will be transferred.
* @param sharedElements All shared elements that will be transferred.
*/
public void onStartExitTransition(List<String> sharedElementNames,
List<View> sharedElements) {}
/**
* Called when the exiting shared element transition completes.
*/
public void onSharedElementExitTransitionComplete() {}
/**
* Called on exit when the shared element has been transferred.
* @param sharedElementNames The names of all shared elements that were transferred.
* @param sharedElements All shared elements that will were transferred.
*/
public void onSharedElementTransferred(List<String> sharedElementNames,
List<View> sharedElements) {}
/**
* Called when the exit transition has completed.
*/
public void onExitTransitionComplete() {}
/**
* Returns a mapping from a View in the View hierarchy to the shared element name used
* in the call. This is called twice -- once when the view is
* entering and again when it exits. A null return value indicates that the
* View hierachy can be trusted without any remapping.
* @return A map from a View in the hierarchy to the shared element name used in the
* call.
*/
public Pair<View, String>[] getSharedElementsMapping() { return null; }
}
/** @hide */
public void updateSceneTransitionAnimation(Transition exitTransition,
Transition sharedElementTransition, SharedElementSource sharedElementSource) {
mTransitionCompleteListener = new ExitTransitionListener(exitTransition,
sharedElementTransition, sharedElementSource);
}
private static class SharedElementMappingListener extends ActivityTransitionListener {
Pair<View, String>[] mSharedElementsMapping = new Pair[1];
private void addSharedElement(View view, String name) {
String sharedElementName = view.getSharedElementName();
if (name == null) {
name = sharedElementName;
}
mSharedElementNames.add(name);
mLocalElementNames.add(sharedElementName);
}
/** @hide */
public interface SharedElementSource {
Bundle getSharedElementExitState();
void acceptedSharedElements(ArrayList<String> sharedElementNames);
void hideSharedElements();
void restore(Bundle sharedElementState);
void prepareForRestore();
}
private static class ExitTransitionListener extends ResultReceiver
implements Transition.TransitionListener {
private boolean mSharedElementNotified;
private IRemoteCallback mTransitionCompleteCallback;
private boolean mExitComplete;
private boolean mSharedElementComplete;
private SharedElementSource mSharedElementSource;
public ExitTransitionListener(Transition exitTransition, Transition sharedElementTransition,
SharedElementSource sharedElementSource) {
super(null);
mSharedElementSource = sharedElementSource;
exitTransition.addListener(this);
sharedElementTransition.addListener(new Transition.TransitionListenerAdapter() {
@Override
public void onTransitionEnd(Transition transition) {
mSharedElementComplete = true;
notifySharedElement();
transition.removeListener(this);
}
});
public SharedElementMappingListener(View view, String name) {
mSharedElementsMapping[0] = Pair.create(view, name);
}
@Override
protected void onReceiveResult(int resultCode, Bundle resultData) {
switch (resultCode) {
case MSG_SET_LISTENER:
IBinder listener = resultData.getBinder(KEY_TRANSITION_TARGET_LISTENER);
mTransitionCompleteCallback = IRemoteCallback.Stub.asInterface(listener);
ArrayList<String> sharedElementNames
= resultData.getStringArrayList(KEY_SHARED_ELEMENT_NAMES);
mSharedElementSource.acceptedSharedElements(sharedElementNames);
notifySharedElement();
notifyExit();
break;
case MSG_HIDE_SHARED_ELEMENTS:
mSharedElementSource.hideSharedElements();
break;
case MSG_PREPARE_RESTORE:
mSharedElementSource.prepareForRestore();
break;
case MSG_RESTORE:
mSharedElementSource.restore(resultData);
break;
}
}
@Override
public void onTransitionStart(Transition transition) {
}
@Override
public void onTransitionEnd(Transition transition) {
mExitComplete = true;
notifyExit();
transition.removeListener(this);
}
@Override
public void onTransitionCancel(Transition transition) {
onTransitionEnd(transition);
}
@Override
public void onTransitionPause(Transition transition) {
}
@Override
public void onTransitionResume(Transition transition) {
}
private void notifySharedElement() {
if (!mSharedElementNotified && mSharedElementComplete
&& mTransitionCompleteCallback != null) {
mSharedElementNotified = true;
try {
Bundle sharedElementState = mSharedElementSource.getSharedElementExitState();
mTransitionCompleteCallback.sendResult(sharedElementState);
} catch (RemoteException e) {
Log.w(TAG, "Couldn't notify that the transition ended", e);
}
}
}
private void notifyExit() {
if (mExitComplete && mTransitionCompleteCallback != null) {
try {
mTransitionCompleteCallback.sendResult(null);
} catch (RemoteException e) {
Log.w(TAG, "Couldn't notify that the transition ended", e);
}
}
public Pair<View, String>[] getSharedElementsMapping() {
return mSharedElementsMapping;
}
}
}

View File

@@ -0,0 +1,736 @@
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.app;
import android.graphics.Rect;
import android.os.Bundle;
import android.os.Handler;
import android.os.ResultReceiver;
import android.transition.Transition;
import android.transition.TransitionManager;
import android.transition.TransitionSet;
import android.util.ArrayMap;
import android.util.Pair;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.view.Window;
import java.util.ArrayList;
import java.util.Collection;
/**
* Base class for ExitTransitionCoordinator and EnterTransitionCoordinator, classes
* that manage activity transitions and the communications coordinating them between
* Activities. The ExitTransitionCoordinator is created in the
* ActivityOptions#makeSceneTransitionAnimation. The EnterTransitionCoordinator
* is created by ActivityOptions#createEnterActivityTransition by Activity when the window is
* attached.
*
* Typical startActivity goes like this:
* 1) ExitTransitionCoordinator created with ActivityOptions#makeSceneTransitionAnimation
* 2) Activity#startActivity called and that calls startExit() through
* ActivityOptions#dispatchStartExit
* - Exit transition starts by setting transitioning Views to INVISIBLE
* 3) Launched Activity starts, creating an EnterTransitionCoordinator.
* - The Window is made translucent
* - The Window background alpha is set to 0
* - The transitioning views are made INVISIBLE
* - MSG_SET_LISTENER is sent back to the ExitTransitionCoordinator.
* 4) The shared element transition completes.
* - MSG_TAKE_SHARED_ELEMENTS is sent to the EnterTransitionCoordinator
* 5) The MSG_TAKE_SHARED_ELEMENTS is received by the EnterTransitionCoordinator.
* - Shared elements are made VISIBLE
* - Shared elements positions and size are set to match the end state of the calling
* Activity.
* - The shared element transition is started
* - If the window allows overlapping transitions, the views transition is started by setting
* the entering Views to VISIBLE and the background alpha is animated to opaque.
* - MSG_HIDE_SHARED_ELEMENTS is sent to the ExitTransitionCoordinator
* 6) MSG_HIDE_SHARED_ELEMENTS is received by the ExitTransitionCoordinator
* - The shared elements are made INVISIBLE
* 7) The exit transition completes in the calling Activity.
* - MSG_EXIT_TRANSITION_COMPLETE is sent to the EnterTransitionCoordinator.
* 8) The MSG_EXIT_TRANSITION_COMPLETE is received by the EnterTransitionCoordinator.
* - If the window doesn't allow overlapping enter transitions, the enter transition is started
* by setting entering views to VISIBLE and the background is animated to opaque.
* 9) The background opacity animation completes.
* - The window is made opaque
* 10) The calling Activity gets an onStop() call
* - onActivityStopped() is called and all exited Views are made VISIBLE.
*
* Typical finishWithTransition goes like this:
* 1) finishWithTransition() calls startExit()
* - The Window start transitioning to Translucent
* - If no background exists, a black background is substituted
* - MSG_PREPARE_RESTORE is sent to the ExitTransitionCoordinator
* - The shared elements in the scene are matched against those shared elements
* that were sent by comparing the names.
* - The exit transition is started by setting Views to INVISIBLE.
* 2) MSG_PREPARE_RESTORE is received by the EnterTransitionCoordinator
* - All transitioning views are made VISIBLE to reverse what was done when onActivityStopped()
* was called
* 3) The Window is made translucent and a callback is received
* - The background alpha is animated to 0
* 4) The background alpha animation completes
* 5) The shared element transition completes
* - After both 4 & 5 complete, MSG_TAKE_SHARED_ELEMENTS is sent to the
* ExitTransitionCoordinator
* 6) MSG_TAKE_SHARED_ELEMENTS is received by ExitTransitionCoordinator
* - Shared elements are made VISIBLE
* - Shared elements positions and size are set to match the end state of the calling
* Activity.
* - The shared element transition is started
* - If the window allows overlapping transitions, the views transition is started by setting
* the entering Views to VISIBLE.
* - MSG_HIDE_SHARED_ELEMENTS is sent to the EnterTransitionCoordinator
* 7) MSG_HIDE_SHARED_ELEMENTS is received by the EnterTransitionCoordinator
* - The shared elements are made INVISIBLE
* 8) The exit transition completes in the finishing Activity.
* - MSG_EXIT_TRANSITION_COMPLETE is sent to the ExitTransitionCoordinator.
* - finish() is called on the exiting Activity
* 9) The MSG_EXIT_TRANSITION_COMPLETE is received by the ExitTransitionCoordinator.
* - If the window doesn't allow overlapping enter transitions, the enter transition is started
* by setting entering views to VISIBLE.
*/
abstract class ActivityTransitionCoordinator extends ResultReceiver {
private static final String TAG = "ActivityTransitionCoordinator";
/**
* The names of shared elements that are transitioned to the started Activity.
* This is also the name of shared elements that the started Activity accepted.
*/
public static final String KEY_SHARED_ELEMENT_NAMES = "android:shared_element_names";
public static final String KEY_SHARED_ELEMENT_STATE = "android:shared_element_state";
/**
* For Activity transitions, the called Activity's listener to receive calls
* when transitions complete.
*/
static final String KEY_TRANSITION_RESULTS_RECEIVER = "android:transitionTargetListener";
private static final String KEY_SCREEN_X = "shared_element:screenX";
private static final String KEY_SCREEN_Y = "shared_element:screenY";
private static final String KEY_TRANSLATION_Z = "shared_element:translationZ";
private static final String KEY_WIDTH = "shared_element:width";
private static final String KEY_HEIGHT = "shared_element:height";
private static final String KEY_NAME = "shared_element:name";
/**
* Sent by the exiting coordinator (either EnterTransitionCoordinator
* or ExitTransitionCoordinator) after the shared elements have
* become stationary (shared element transition completes). This tells
* the remote coordinator to take control of the shared elements and
* that animations may begin. The remote Activity won't start entering
* until this message is received, but may wait for
* MSG_EXIT_TRANSITION_COMPLETE if allowOverlappingTransitions() is true.
*/
public static final int MSG_SET_LISTENER = 100;
/**
* Sent by the entering coordinator to tell the exiting coordinator
* to hide its shared elements after it has started its shared
* element transition. This is temporary until the
* interlock of shared elements is figured out.
*/
public static final int MSG_HIDE_SHARED_ELEMENTS = 101;
/**
* Sent by the EnterTransitionCoordinator to tell the
* ExitTransitionCoordinator to hide all of its exited views after
* MSG_ACTIVITY_STOPPED has caused them all to show.
*/
public static final int MSG_PREPARE_RESTORE = 102;
/**
* 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 = 103;
/**
* Sent by the exiting coordinator (either EnterTransitionCoordinator
* or ExitTransitionCoordinator) after the shared elements have
* become stationary (shared element transition completes). This tells
* the remote coordinator to take control of the shared elements and
* that animations may begin. The remote Activity won't start entering
* until this message is received, but may wait for
* MSG_EXIT_TRANSITION_COMPLETE if allowOverlappingTransitions() is true.
*/
public static final int MSG_TAKE_SHARED_ELEMENTS = 104;
/**
* Sent by the exiting coordinator (either
* EnterTransitionCoordinator or ExitTransitionCoordinator) after
* the exiting Views have finished leaving the scene. This will
* be ignored if allowOverlappingTransitions() is true on the
* remote coordinator. If it is false, it will trigger the enter
* transition to start.
*/
public static final int MSG_EXIT_TRANSITION_COMPLETE = 105;
/**
* Sent by Activity#startActivity to begin the exit transition.
*/
public static final int MSG_START_EXIT_TRANSITION = 106;
private Window mWindow;
private ArrayList<View> mSharedElements = new ArrayList<View>();
private ArrayList<String> mTargetSharedNames = new ArrayList<String>();
private ActivityOptions.ActivityTransitionListener mListener =
new ActivityOptions.ActivityTransitionListener();
private ArrayList<View> mEnteringViews;
private ResultReceiver mRemoteResultReceiver;
private boolean mNotifiedSharedElementTransitionComplete;
private boolean mNotifiedExitTransitionComplete;
private FixedEpicenterCallback mEpicenterCallback = new FixedEpicenterCallback();
private Transition.TransitionListener mSharedElementListener =
new Transition.TransitionListenerAdapter() {
@Override
public void onTransitionEnd(Transition transition) {
transition.removeListener(this);
onSharedElementTransitionEnd();
}
};
private Transition.TransitionListener mExitListener =
new Transition.TransitionListenerAdapter() {
@Override
public void onTransitionEnd(Transition transition) {
transition.removeListener(this);
onExitTransitionEnd();
}
};
public ActivityTransitionCoordinator(Window window)
{
super(new Handler());
mWindow = window;
}
// -------------------- ResultsReceiver Overrides ----------------------
@Override
protected void onReceiveResult(int resultCode, Bundle resultData) {
switch (resultCode) {
case MSG_SET_LISTENER:
ResultReceiver resultReceiver
= resultData.getParcelable(KEY_TRANSITION_RESULTS_RECEIVER);
setRemoteResultReceiver(resultReceiver);
onSetResultReceiver();
break;
case MSG_HIDE_SHARED_ELEMENTS:
onHideSharedElements();
break;
case MSG_PREPARE_RESTORE:
onPrepareRestore();
break;
case MSG_EXIT_TRANSITION_COMPLETE:
onRemoteSceneExitComplete();
break;
case MSG_TAKE_SHARED_ELEMENTS:
ArrayList<String> sharedElementNames
= resultData.getStringArrayList(KEY_SHARED_ELEMENT_NAMES);
Bundle sharedElementState = resultData.getBundle(KEY_SHARED_ELEMENT_STATE);
onTakeSharedElements(sharedElementNames, sharedElementState);
break;
case MSG_ACTIVITY_STOPPED:
onActivityStopped();
break;
case MSG_START_EXIT_TRANSITION:
startExit();
break;
}
}
// -------------------- calls that can be overridden by subclasses --------------------
/**
* Called when MSG_SET_LISTENER is received. This will only be received by
* ExitTransitionCoordinator.
*/
protected void onSetResultReceiver() {}
/**
* Called when MSG_HIDE_SHARED_ELEMENTS is received
*/
protected void onHideSharedElements() {
setViewVisibility(getSharedElements(), View.INVISIBLE);
mListener.onSharedElementTransferred(getSharedElementNames(), getSharedElements());
}
/**
* Called when MSG_PREPARE_RESTORE is called. This will only be received by
* ExitTransitionCoordinator.
*/
protected void onPrepareRestore() {
mListener.onEnterReady();
}
/**
* Called when MSG_EXIT_TRANSITION_COMPLETE is received -- the remote coordinator has
* completed its exit transition. This can be called by the ExitTransitionCoordinator when
* starting an Activity or EnterTransitionCoordinator when called with finishWithTransition.
*/
protected void onRemoteSceneExitComplete() {
if (!allowOverlappingTransitions()) {
Transition transition = beginTransition(mEnteringViews, false, true, true);
onStartEnterTransition(transition, mEnteringViews);
}
mListener.onRemoteExitComplete();
}
/**
* Called when MSG_TAKE_SHARED_ELEMENTS is received. This means that the shared elements are
* in a stable state and ready to move to the Window.
* @param sharedElementNames The names of the shared elements to move.
* @param state Contains the shared element states (size & position)
*/
protected void onTakeSharedElements(ArrayList<String> sharedElementNames, Bundle state) {
setSharedElements();
reconcileSharedElements(sharedElementNames);
mEnteringViews.removeAll(mSharedElements);
setSharedElementState(state);
if (getViewsTransition() != null) {
setViewVisibility(mEnteringViews, View.INVISIBLE);
}
setViewVisibility(mSharedElements, View.VISIBLE);
Transition transition = beginTransition(mEnteringViews, true, allowOverlappingTransitions(),
true);
if (allowOverlappingTransitions()) {
onStartEnterTransition(transition, mEnteringViews);
}
mRemoteResultReceiver.send(MSG_HIDE_SHARED_ELEMENTS, null);
}
/**
* Called when MSG_ACTIVITY_STOPPED is received. This is received when Activity.onStop is
* called after running startActivity* is called using an Activity Transition.
*/
protected void onActivityStopped() {}
/**
* Called when the start transition is ready to run. This may be immediately after
* MSG_TAKE_SHARED_ELEMENTS or MSG_EXIT_TRANSITION_COMPLETE, depending on whether
* overlapping transitions are allowed.
* @param transition The transition currently started.
* @param enteringViews The views entering the scene. This won't include shared elements.
*/
protected void onStartEnterTransition(Transition transition, ArrayList<View> enteringViews) {
if (getViewsTransition() != null) {
setViewVisibility(enteringViews, View.VISIBLE);
}
mEnteringViews = null;
mListener.onStartEnterTransition(getSharedElementNames(), getSharedElements());
}
/**
* Called when the exit transition has started.
* @param exitingViews The views leaving the scene. This won't include shared elements.
*/
protected void onStartExitTransition(ArrayList<View> exitingViews) {}
/**
* Called during the exit when the shared element transition has completed.
*/
protected void onSharedElementTransitionEnd() {
Bundle bundle = new Bundle();
int[] tempLoc = new int[2];
for (int i = 0; i < mSharedElements.size(); i++) {
View sharedElement = mSharedElements.get(i);
String name = mTargetSharedNames.get(i);
captureSharedElementState(sharedElement, name, bundle, tempLoc);
}
Bundle allValues = new Bundle();
allValues.putStringArrayList(KEY_SHARED_ELEMENT_NAMES, getSharedElementNames());
allValues.putBundle(KEY_SHARED_ELEMENT_STATE, bundle);
sharedElementTransitionComplete(allValues);
mListener.onSharedElementExitTransitionComplete();
}
/**
* Called after the shared element transition is complete to pass the shared element state
* to the remote coordinator.
* @param bundle The Bundle to send to the coordinator containing the shared element state.
*/
protected abstract void sharedElementTransitionComplete(Bundle bundle);
/**
* Called when the exit transition finishes.
*/
protected void onExitTransitionEnd() {
mListener.onExitTransitionComplete();
}
/**
* Called to start the exit transition. Launched from ActivityOptions#dispatchStartExit
*/
protected abstract void startExit();
/**
* A non-null transition indicates that the Views of the Window should be made INVISIBLE.
* @return The Transition used to cause transitioning views to either enter or exit the scene.
*/
protected abstract Transition getViewsTransition();
/**
* @return The Transition used to move the shared elements from the start position and size
* to the end position and size.
*/
protected abstract Transition getSharedElementTransition();
/**
* @return When the enter transition should overlap with the exit transition of the
* remote controller.
*/
protected abstract boolean allowOverlappingTransitions();
// called by subclasses
protected void notifySharedElementTransitionComplete(Bundle sharedElements) {
if (!mNotifiedSharedElementTransitionComplete) {
mNotifiedSharedElementTransitionComplete = true;
mRemoteResultReceiver.send(MSG_TAKE_SHARED_ELEMENTS, sharedElements);
}
}
protected void notifyExitTransitionComplete() {
if (!mNotifiedExitTransitionComplete) {
mNotifiedExitTransitionComplete = true;
mRemoteResultReceiver.send(MSG_EXIT_TRANSITION_COMPLETE, null);
}
}
protected void notifyPrepareRestore() {
mRemoteResultReceiver.send(MSG_PREPARE_RESTORE, null);
}
protected void setRemoteResultReceiver(ResultReceiver resultReceiver) {
mRemoteResultReceiver = resultReceiver;
}
protected void notifySetListener() {
Bundle bundle = new Bundle();
bundle.putParcelable(KEY_TRANSITION_RESULTS_RECEIVER, this);
mRemoteResultReceiver.send(MSG_SET_LISTENER, bundle);
}
protected void setEnteringViews(ArrayList<View> views) {
mEnteringViews = views;
}
protected void setSharedElements() {
Pair<View, String>[] sharedElements = mListener.getSharedElementsMapping();
mSharedElements.clear();
mTargetSharedNames.clear();
if (sharedElements == null) {
ArrayMap<String, View> map = new ArrayMap<String, View>();
setViewVisibility(mEnteringViews, View.VISIBLE);
getDecor().findSharedElements(map);
setViewVisibility(mEnteringViews, View.INVISIBLE);
for (int i = 0; i < map.size(); i++) {
View view = map.valueAt(i);
String name = map.keyAt(i);
mSharedElements.add(view);
mTargetSharedNames.add(name);
}
} else {
for (int i = 0; i < sharedElements.length; i++) {
Pair<View, String> viewStringPair = sharedElements[i];
View view = viewStringPair.first;
String name = viewStringPair.second;
mSharedElements.add(view);
mTargetSharedNames.add(name);
}
}
}
protected ArrayList<View> getSharedElements() {
return mSharedElements;
}
protected ArrayList<String> getSharedElementNames() {
return mTargetSharedNames;
}
protected Window getWindow() {
return mWindow;
}
protected ViewGroup getDecor() {
return (mWindow == null) ? null : (ViewGroup) mWindow.getDecorView();
}
protected void startExitTransition(ArrayList<String> sharedElements) {
setSharedElements();
reconcileSharedElements(sharedElements);
ArrayList<View> transitioningViews = captureTransitioningViews();
beginTransition(transitioningViews, true, true, false);
onStartExitTransition(transitioningViews);
if (getViewsTransition() != null) {
setViewVisibility(transitioningViews, View.INVISIBLE);
}
mListener.onStartExitTransition(getSharedElementNames(), getSharedElements());
}
protected void clearConnections() {
mRemoteResultReceiver = null;
}
// public API
public void setActivityTransitionListener(ActivityOptions.ActivityTransitionListener listener) {
if (listener == null) {
mListener = new ActivityOptions.ActivityTransitionListener();
} else {
mListener = listener;
}
}
// private methods
private Transition configureTransition(Transition transition) {
if (transition != null) {
transition = transition.clone();
transition.setEpicenterCallback(mEpicenterCallback);
}
return transition;
}
private void reconcileSharedElements(ArrayList<String> sharedElementNames) {
Rect epicenter = null;
for (int i = mTargetSharedNames.size() - 1; i >= 0; i--) {
if (!sharedElementNames.contains(mTargetSharedNames.get(i))) {
mTargetSharedNames.remove(i);
mSharedElements.remove(i);
}
}
if (!mSharedElements.isEmpty()) {
epicenter = calcEpicenter(mSharedElements.get(0));
}
mEpicenterCallback.setEpicenter(epicenter);
}
private void setSharedElementState(Bundle sharedElementState) {
if (sharedElementState != null) {
int[] tempLoc = new int[2];
for (int i = 0; i < mSharedElements.size(); i++) {
View sharedElement = mSharedElements.get(i);
String name = mTargetSharedNames.get(i);
setSharedElementState(sharedElement, name, sharedElementState, tempLoc);
}
}
mListener.onCaptureSharedElementStart();
getDecor().getViewTreeObserver().addOnPreDrawListener(
new ViewTreeObserver.OnPreDrawListener() {
@Override
public boolean onPreDraw() {
getDecor().getViewTreeObserver().removeOnPreDrawListener(this);
mListener.onCaptureSharedElementEnd();
return true;
}
}
);
}
/**
* Sets the captured values from a previous
* {@link #captureSharedElementState(android.view.View, String, android.os.Bundle, int[])}
* @param view The View to apply placement changes to.
* @param name The shared element name given from the source Activity.
* @param transitionArgs A <code>Bundle</code> containing all placementinformation for named
* shared elements in the scene.
* @param tempLoc A temporary int[2] for capturing the current location of views.
*/
private static void setSharedElementState(View view, String name, Bundle transitionArgs,
int[] tempLoc) {
Bundle sharedElementBundle = transitionArgs.getBundle(name);
if (sharedElementBundle == null) {
return;
}
float z = sharedElementBundle.getFloat(KEY_TRANSLATION_Z);
view.setTranslationZ(z);
int x = sharedElementBundle.getInt(KEY_SCREEN_X);
int y = sharedElementBundle.getInt(KEY_SCREEN_Y);
int width = sharedElementBundle.getInt(KEY_WIDTH);
int height = sharedElementBundle.getInt(KEY_HEIGHT);
int widthSpec = View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY);
int heightSpec = View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.EXACTLY);
view.measure(widthSpec, heightSpec);
ViewGroup parent = (ViewGroup) view.getParent();
parent.getLocationOnScreen(tempLoc);
int left = x - tempLoc[0];
int top = y - tempLoc[1];
int right = left + width;
int bottom = top + height;
view.layout(left, top, right, bottom);
view.requestLayout();
}
/**
* Captures placement information for Views with a shared element name for
* Activity Transitions.
* @param view The View to capture the placement information for.
* @param name The shared element name in the target Activity to apply the placement
* information for.
* @param transitionArgs Bundle to store shared element placement information.
* @param tempLoc A temporary int[2] for capturing the current location of views.
* @see #setSharedElementState(android.view.View, String, android.os.Bundle, int[])
*/
private static void captureSharedElementState(View view, String name, Bundle transitionArgs,
int[] tempLoc) {
Bundle sharedElementBundle = new Bundle();
view.getLocationOnScreen(tempLoc);
float scaleX = view.getScaleX();
sharedElementBundle.putInt(KEY_SCREEN_X, tempLoc[0]);
int width = Math.round(view.getWidth() * scaleX);
sharedElementBundle.putInt(KEY_WIDTH, width);
float scaleY = view.getScaleY();
sharedElementBundle.putInt(KEY_SCREEN_Y, tempLoc[1]);
int height= Math.round(view.getHeight() * scaleY);
sharedElementBundle.putInt(KEY_HEIGHT, height);
sharedElementBundle.putFloat(KEY_TRANSLATION_Z, view.getTranslationZ());
sharedElementBundle.putString(KEY_NAME, view.getSharedElementName());
transitionArgs.putBundle(name, sharedElementBundle);
}
private static Rect calcEpicenter(View view) {
int[] loc = new int[2];
view.getLocationOnScreen(loc);
int left = loc[0] + Math.round(view.getTranslationX());
int top = loc[1] + Math.round(view.getTranslationY());
int right = left + view.getWidth();
int bottom = top + view.getHeight();
return new Rect(left, top, right, bottom);
}
public static void setViewVisibility(Collection<View> views, int visibility) {
if (views != null) {
for (View view : views) {
view.setVisibility(visibility);
}
}
}
private static Transition addTransitionTargets(Transition transition, Collection<View> views) {
if (transition == null || views == null || views.isEmpty()) {
return null;
}
TransitionSet set = new TransitionSet();
set.addTransition(transition.clone());
if (views != null) {
for (View view: views) {
set.addTarget(view);
}
}
return set;
}
private ArrayList<View> captureTransitioningViews() {
if (getViewsTransition() == null) {
return null;
}
ArrayList<View> transitioningViews = new ArrayList<View>();
getDecor().captureTransitioningViews(transitioningViews);
transitioningViews.removeAll(getSharedElements());
return transitioningViews;
}
private Transition getSharedElementTransition(boolean isEnter) {
Transition transition = getSharedElementTransition();
if (transition == null) {
return null;
}
transition = configureTransition(transition);
if (!isEnter) {
transition.addListener(mSharedElementListener);
}
return transition;
}
private Transition getViewsTransition(ArrayList<View> transitioningViews, boolean isEnter) {
Transition transition = getViewsTransition();
if (transition == null) {
return null;
}
transition = configureTransition(transition);
if (!isEnter) {
transition.addListener(mExitListener);
}
return addTransitionTargets(transition, transitioningViews);
}
private Transition beginTransition(ArrayList<View> transitioningViews,
boolean transitionSharedElement, boolean transitionViews, boolean isEnter) {
Transition sharedElementTransition = null;
if (transitionSharedElement) {
sharedElementTransition = getSharedElementTransition(isEnter);
if (!isEnter && sharedElementTransition == null) {
onSharedElementTransitionEnd();
}
}
Transition viewsTransition = null;
if (transitionViews) {
viewsTransition = getViewsTransition(transitioningViews, isEnter);
if (!isEnter && viewsTransition == null) {
onExitTransitionEnd();
}
}
Transition transition = null;
if (sharedElementTransition == null) {
transition = viewsTransition;
} else if (viewsTransition == null) {
transition = sharedElementTransition;
} else {
TransitionSet set = new TransitionSet();
set.addTransition(sharedElementTransition);
set.addTransition(viewsTransition);
transition = set;
}
if (transition != null) {
TransitionManager.beginDelayedTransition(getDecor(), transition);
if (transitionSharedElement && !mSharedElements.isEmpty()) {
mSharedElements.get(0).invalidate();
} else if (transitionViews && !transitioningViews.isEmpty()) {
transitioningViews.get(0).invalidate();
}
}
return transition;
}
private static class FixedEpicenterCallback extends Transition.EpicenterCallback {
private Rect mEpicenter;
public void setEpicenter(Rect epicenter) { mEpicenter = epicenter; }
@Override
public Rect getEpicenter(Transition transition) {
return mEpicenter;
}
}
}

View File

@@ -0,0 +1,292 @@
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.app;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.ResultReceiver;
import android.transition.Transition;
import android.util.ArrayMap;
import android.util.Pair;
import android.view.View;
import android.view.ViewTreeObserver;
import android.view.Window;
import java.util.ArrayList;
/**
* This ActivityTransitionCoordinator is created by the Activity to manage
* the enter scene and shared element transfer as well as Activity#finishWithTransition
* exiting the Scene and transferring shared elements back to the called Activity.
*/
class EnterTransitionCoordinator extends ActivityTransitionCoordinator
implements ViewTreeObserver.OnPreDrawListener {
private static final String TAG = "EnterTransitionCoordinator";
// The background fade in/out duration. 150ms is pretty quick, but not abrupt.
private static final int FADE_BACKGROUND_DURATION_MS = 150;
/**
* The shared element names sent by the ExitTransitionCoordinator and may be
* shared when exiting back.
*/
private ArrayList<String> mEnteringSharedElementNames;
/**
* The Activity that has created this coordinator. This is used solely to make the
* Window translucent/opaque.
*/
private Activity mActivity;
/**
* True if the Window was opaque at the start and we should make it opaque again after
* enter transitions have completed.
*/
private boolean mWasOpaque;
/**
* During exit, is the background alpha == 0?
*/
private boolean mBackgroundFadedOut;
/**
* During exit, has the shared element transition completed?
*/
private boolean mSharedElementTransitionComplete;
/**
* Has the exit started? We don't want to accidentally exit multiple times. e.g. when
* back is hit twice during the exit animation.
*/
private boolean mExitTransitionStarted;
/**
* Has the exit transition ended?
*/
private boolean mExitTransitionComplete;
/**
* We only want to make the Window transparent and set the background alpha once. After that,
* the Activity won't want the same enter transition.
*/
private boolean mMadeReady;
/**
* True if Window.hasFeature(Window.FEATURE_CONTENT_TRANSITIONS) -- this means that
* enter and exit transitions should be active.
*/
private boolean mSupportsTransition;
/**
* Background alpha animations may complete prior to receiving the callback for
* onTranslucentConversionComplete. If so, we need to immediately call to make the Window
* opaque.
*/
private boolean mMakeOpaque;
public EnterTransitionCoordinator(Activity activity, ResultReceiver resultReceiver) {
super(activity.getWindow());
mActivity = activity;
setRemoteResultReceiver(resultReceiver);
}
public void readyToEnter() {
if (!mMadeReady) {
mMadeReady = true;
mSupportsTransition = getWindow().hasFeature(Window.FEATURE_CONTENT_TRANSITIONS);
if (mSupportsTransition) {
Window window = getWindow();
window.getDecorView().getViewTreeObserver().addOnPreDrawListener(this);
mActivity.overridePendingTransition(0, 0);
mActivity.convertToTranslucent(new Activity.TranslucentConversionListener() {
@Override
public void onTranslucentConversionComplete(boolean drawComplete) {
mWasOpaque = true;
if (mMakeOpaque) {
mActivity.convertFromTranslucent();
}
}
});
Drawable background = getDecor().getBackground();
if (background != null) {
window.setBackgroundDrawable(null);
background.setAlpha(0);
window.setBackgroundDrawable(background);
}
}
}
}
@Override
protected void onRemoteSceneExitComplete() {
super.onRemoteSceneExitComplete();
}
@Override
protected void onTakeSharedElements(ArrayList<String> sharedElementNames, Bundle state) {
mEnteringSharedElementNames = new ArrayList<String>();
mEnteringSharedElementNames.addAll(sharedElementNames);
super.onTakeSharedElements(sharedElementNames, state);
}
@Override
protected void sharedElementTransitionComplete(Bundle bundle) {
notifySharedElementTransitionComplete(bundle);
}
@Override
public boolean onPreDraw() {
getWindow().getDecorView().getViewTreeObserver().removeOnPreDrawListener(this);
setEnteringViews(readyEnteringViews());
notifySetListener();
onPrepareRestore();
return false;
}
@Override
public void startExit() {
if (!mExitTransitionStarted) {
mExitTransitionStarted = true;
startExitTransition(mEnteringSharedElementNames);
}
}
@Override
protected Transition getViewsTransition() {
if (!mSupportsTransition) {
return null;
}
return getWindow().getEnterTransition();
}
@Override
protected Transition getSharedElementTransition() {
if (!mSupportsTransition) {
return null;
}
return getWindow().getSharedElementEnterTransition();
}
@Override
protected void onStartEnterTransition(Transition transition, ArrayList<View> enteringViews) {
Drawable background = getDecor().getBackground();
if (background != null) {
ObjectAnimator animator = ObjectAnimator.ofInt(background, "alpha", 255);
animator.setDuration(FADE_BACKGROUND_DURATION_MS);
animator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
mMakeOpaque = true;
if (mWasOpaque) {
mActivity.convertFromTranslucent();
}
}
});
animator.start();
} else if (mWasOpaque) {
transition.addListener(new Transition.TransitionListenerAdapter() {
@Override
public void onTransitionEnd(Transition transition) {
mMakeOpaque = true;
mActivity.convertFromTranslucent();
}
});
}
super.onStartEnterTransition(transition, enteringViews);
}
public ArrayList<View> readyEnteringViews() {
ArrayList<View> enteringViews = new ArrayList<View>();
getDecor().captureTransitioningViews(enteringViews);
if (getViewsTransition() != null) {
setViewVisibility(enteringViews, View.INVISIBLE);
}
return enteringViews;
}
@Override
protected void startExitTransition(ArrayList<String> sharedElements) {
notifyPrepareRestore();
if (getDecor().getBackground() == null) {
ColorDrawable black = new ColorDrawable(0xFF000000);
getWindow().setBackgroundDrawable(black);
}
if (mWasOpaque) {
mActivity.convertToTranslucent(new Activity.TranslucentConversionListener() {
@Override
public void onTranslucentConversionComplete(boolean drawComplete) {
fadeOutBackground();
}
});
} else {
fadeOutBackground();
}
super.startExitTransition(sharedElements);
}
private void fadeOutBackground() {
ObjectAnimator animator = ObjectAnimator.ofInt(getDecor().getBackground(),
"alpha", 0);
animator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
mBackgroundFadedOut = true;
if (mSharedElementTransitionComplete) {
EnterTransitionCoordinator.super.onSharedElementTransitionEnd();
}
}
});
animator.setDuration(FADE_BACKGROUND_DURATION_MS);
animator.start();
}
@Override
protected void onExitTransitionEnd() {
mExitTransitionComplete = true;
exitAfterSharedElementTransition();
super.onExitTransitionEnd();
clearConnections();
}
@Override
protected void onSharedElementTransitionEnd() {
mSharedElementTransitionComplete = true;
if (mBackgroundFadedOut) {
super.onSharedElementTransitionEnd();
}
}
@Override
protected boolean allowOverlappingTransitions() {
return getWindow().getAllowEnterTransitionOverlap();
}
private void exitAfterSharedElementTransition() {
if (mSharedElementTransitionComplete && mExitTransitionComplete) {
mActivity.finish();
if (mSupportsTransition) {
mActivity.overridePendingTransition(0, 0);
}
notifyExitTransitionComplete();
}
}
}

View File

@@ -0,0 +1,171 @@
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.app;
import android.os.Bundle;
import android.transition.Transition;
import android.util.Pair;
import android.view.View;
import android.view.Window;
import java.util.ArrayList;
/**
* This ActivityTransitionCoordinator is created in ActivityOptions#makeSceneTransitionAnimation
* to govern the exit of the Scene and the shared elements when calling an Activity as well as
* the reentry of the Scene when coming back from the called Activity.
*/
class ExitTransitionCoordinator extends ActivityTransitionCoordinator {
private static final String TAG = "ExitTransitionCoordinator";
/**
* The Views that have exited and need to be restored to VISIBLE when returning to the
* normal state.
*/
private ArrayList<View> mTransitioningViews;
/**
* Has the exit started? We don't want to accidentally exit multiple times.
*/
private boolean mExitStarted;
/**
* Has the called Activity's ResultReceiver been set?
*/
private boolean mIsResultReceiverSet;
/**
* Has the exit transition completed? If so, we can notify as soon as the ResultReceiver
* has been set.
*/
private boolean mExitComplete;
/**
* Has the shared element transition completed? If so, we can notify as soon as the
* ResultReceiver has been set.
*/
private Bundle mSharedElements;
/**
* Has the shared element transition completed?
*/
private boolean mSharedElementsComplete;
public ExitTransitionCoordinator(Window window,
ActivityOptions.ActivityTransitionListener listener) {
super(window);
setActivityTransitionListener(listener);
}
@Override
protected void onSetResultReceiver() {
mIsResultReceiverSet = true;
notifyCompletions();
}
@Override
protected void onPrepareRestore() {
makeTransitioningViewsInvisible();
setEnteringViews(mTransitioningViews);
mTransitioningViews = null;
super.onPrepareRestore();
}
@Override
protected void onTakeSharedElements(ArrayList<String> sharedElementNames, Bundle state) {
super.onTakeSharedElements(sharedElementNames, state);
clearConnections();
}
@Override
protected void onActivityStopped() {
if (getViewsTransition() != null) {
setViewVisibility(mTransitioningViews, View.VISIBLE);
}
super.onActivityStopped();
}
@Override
protected void sharedElementTransitionComplete(Bundle bundle) {
mSharedElements = bundle;
mSharedElementsComplete = true;
notifyCompletions();
}
@Override
protected void onExitTransitionEnd() {
mExitComplete = true;
notifyCompletions();
super.onExitTransitionEnd();
}
private void notifyCompletions() {
if (mIsResultReceiverSet && mSharedElementsComplete) {
if (mSharedElements != null) {
notifySharedElementTransitionComplete(mSharedElements);
mSharedElements = null;
}
if (mExitComplete) {
notifyExitTransitionComplete();
}
}
}
@Override
public void startExit() {
if (!mExitStarted) {
mExitStarted = true;
setSharedElements();
startExitTransition(getSharedElementNames());
}
}
@Override
protected Transition getViewsTransition() {
if (!getWindow().hasFeature(Window.FEATURE_CONTENT_TRANSITIONS)) {
return null;
}
return getWindow().getExitTransition();
}
@Override
protected Transition getSharedElementTransition() {
if (!getWindow().hasFeature(Window.FEATURE_CONTENT_TRANSITIONS)) {
return null;
}
return getWindow().getSharedElementExitTransition();
}
private void makeTransitioningViewsInvisible() {
if (getViewsTransition() != null) {
setViewVisibility(mTransitioningViews, View.INVISIBLE);
}
}
@Override
protected void onStartExitTransition(ArrayList<View> exitingViews) {
mTransitioningViews = new ArrayList<View>();
if (exitingViews != null) {
mTransitioningViews.addAll(exitingViews);
}
mTransitioningViews.addAll(getSharedElements());
}
@Override
protected boolean allowOverlappingTransitions() {
return getWindow().getAllowExitTransitionOverlap();
}
}

View File

@@ -1585,7 +1585,7 @@ public abstract class Transition implements Cloneable {
* hierarchy underneath it.
*/
void capturePropagationValues(TransitionValues transitionValues) {
if (mPropagation != null) {
if (mPropagation != null && !transitionValues.values.isEmpty()) {
String[] propertyNames = mPropagation.getPropagationProperties();
if (propertyNames == null) {
return;

View File

@@ -309,15 +309,11 @@ public class TransitionInflater {
if (transitionId >= 0) {
Transition transition = inflateTransition(transitionId);
if (transition != null) {
if (toScene == null) {
throw new RuntimeException("No toScene for transition ID " + transitionId);
}
if (fromScene == null) {
if (toScene == null) {
throw new RuntimeException("No matching fromScene or toScene " +
"for transition ID " + transitionId);
} else {
transitionManager.setTransition(toScene, transition);
}
} else if (toScene == null) {
transitionManager.setExitTransition(fromScene, transition);
transitionManager.setTransition(toScene, transition);
} else {
transitionManager.setTransition(fromScene, toScene, transition);
}

View File

@@ -70,7 +70,6 @@ public class TransitionManager {
private static final String[] EMPTY_STRINGS = new String[0];
ArrayMap<Scene, Transition> mSceneTransitions = new ArrayMap<Scene, Transition>();
ArrayMap<Scene, Transition> mExitSceneTransitions = new ArrayMap<Scene, Transition>();
ArrayMap<Scene, ArrayMap<Scene, Transition>> mScenePairTransitions =
new ArrayMap<Scene, ArrayMap<Scene, Transition>>();
private static ThreadLocal<WeakReference<ArrayMap<ViewGroup, ArrayList<Transition>>>>
@@ -118,21 +117,6 @@ public class TransitionManager {
mSceneTransitions.put(scene, transition);
}
/**
* Sets a specific transition to occur when the given scene is exited. This
* has the lowest priority -- if a Scene-to-Scene transition or
* Scene enter transition can be applied, it will.
*
* @param scene The scene which, when exited, will cause the given
* transition to run.
* @param transition The transition that will play when the given scene is
* exited. A value of null will result in the default behavior of
* using the default transition instead.
*/
public void setExitTransition(Scene scene, Transition transition) {
mExitSceneTransitions.put(scene, transition);
}
/**
* Sets a specific transition to occur when the given pair of scenes is
* exited/entered.
@@ -181,9 +165,6 @@ public class TransitionManager {
}
}
transition = mSceneTransitions.get(scene);
if (transition == null && sceneRoot != null) {
transition = mExitSceneTransitions.get(Scene.getCurrentScene(sceneRoot));
}
return (transition != null) ? transition : sDefaultTransition;
}
@@ -238,34 +219,6 @@ public class TransitionManager {
}
}
/**
* Retrieve the transition to a target defined scene if one has been
* associated with this TransitionManager.
*
* @param toScene Target scene that this transition will move to
* @return Transition corresponding to the given toScene or null
* if no association exists in this TransitionManager
*
* @see #setTransition(Scene, Transition)
* @hide
*/
public Transition getEnterTransition(Scene toScene) {
return mSceneTransitions.get(toScene);
}
/**
* Retrieve the transition from a defined scene to a target named scene if one has been
* associated with this TransitionManager.
*
* @param fromScene Scene that this transition starts from
* @return Transition corresponding to the given fromScene or null
* if no association exists in this TransitionManager
* @hide
*/
public Transition getExitTransition(Scene fromScene) {
return mExitSceneTransitions.get(fromScene);
}
/**
* This private utility class is used to listen for both OnPreDraw and
* OnAttachStateChange events. OnPreDraw events are the main ones we care

View File

@@ -109,14 +109,14 @@ public abstract class Visibility extends Transition {
final VisibilityInfo visInfo = new VisibilityInfo();
visInfo.visibilityChange = false;
visInfo.fadeIn = false;
if (startValues != null) {
if (startValues != null && startValues.values.containsKey(PROPNAME_VISIBILITY)) {
visInfo.startVisibility = (Integer) startValues.values.get(PROPNAME_VISIBILITY);
visInfo.startParent = (ViewGroup) startValues.values.get(PROPNAME_PARENT);
} else {
visInfo.startVisibility = -1;
visInfo.startParent = null;
}
if (endValues != null) {
if (endValues != null && endValues.values.containsKey(PROPNAME_VISIBILITY)) {
visInfo.endVisibility = (Integer) endValues.values.get(PROPNAME_VISIBILITY);
visInfo.endParent = (ViewGroup) endValues.values.get(PROPNAME_PARENT);
} else {

View File

@@ -2305,11 +2305,13 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
/**
* Changes whether or not this ViewGroup should be treated as a single entity during
* ActivityTransitions.
* Activity Transitions.
* @param isTransitionGroup Whether or not the ViewGroup should be treated as a unit
* in Activity transitions. If false, the ViewGroup won't transition,
* only its children. If true, the entire ViewGroup will transition
* together.
* @see android.app.ActivityOptions#makeSceneTransitionAnimation(android.view.Window,
* android.app.ActivityOptions.ActivityTransitionListener)
*/
public void setTransitionGroup(boolean isTransitionGroup) {
mGroupFlags |= FLAG_IS_TRANSITION_GROUP_SET;

View File

@@ -32,8 +32,6 @@ import android.transition.Transition;
import android.transition.TransitionManager;
import android.view.accessibility.AccessibilityEvent;
import java.util.Map;
/**
* Abstract base class for a top-level window look and behavior policy. An
* instance of this class should be used as the top-level view added to the
@@ -1385,86 +1383,132 @@ public abstract class Window {
}
/**
* Set options that can affect the transition behavior within this window.
* @param options Options to set or null for none
* @hide
* Sets the Transition that will be used to move Views into the initial scene. The entering
* Views will be those that are regular Views or ViewGroups that have
* {@link ViewGroup#isTransitionGroup} return true. Typical Transitions will extend
* {@link android.transition.Visibility} as entering is governed by changing visibility from
* {@link View#INVISIBLE} to {@link View#VISIBLE}. If <code>transition</code> is null,
* entering Views will remain unaffected.
* @param transition The Transition to use to move Views into the initial Scene.
*/
public void setTransitionOptions(Bundle options, SceneTransitionListener listener) {
}
public void setEnterTransition(Transition transition) {}
/**
* A callback for Window transitions to be told when the shared element is ready to be shown
* and start the transition to its target location.
* @hide
* Sets the Transition that will be used to move Views out of the scene when starting a
* new Activity. The exiting Views will be those that are regular Views or ViewGroups that
* have {@link ViewGroup#isTransitionGroup} return true. Typical Transitions will extend
* {@link android.transition.Visibility} as exiting is governed by changing visibility
* from {@link View#VISIBLE} to {@link View#INVISIBLE}. If transition is null, the views will
* remain unaffected. Requires {@link #FEATURE_CONTENT_TRANSITIONS}.
* @param transition The Transition to use to move Views out of the scene when calling a
* new Activity.
*/
public interface SceneTransitionListener {
void nullPendingTransition();
void convertFromTranslucent();
void convertToTranslucent();
void sharedElementStart(Transition transition);
void sharedElementEnd();
}
public void setExitTransition(Transition transition) {}
/**
* Controls how the Activity's start Scene is faded in and when the enter scene
* is triggered to start.
* <p>When allow is true, the enter Scene will begin as soon as possible
* and the background will fade in when all shared elements are ready to begin
* transitioning. If allow is false, the Activity enter Scene and
* background fade will be triggered when the calling Activity's exit transition
* completes.</p>
* @param allow Set to true to have the Activity enter scene transition in
* as early as possible or set to false to wait for the calling
* Activity to exit first. The default value is true.
* Returns the transition used to move Views into the initial scene. The entering
* Views will be those that are regular Views or ViewGroups that have
* {@link ViewGroup#isTransitionGroup} return true. Typical Transitions will extend
* {@link android.transition.Visibility} as entering is governed by changing visibility from
* {@link View#INVISIBLE} to {@link View#VISIBLE}. If <code>transition</code> is null,
* entering Views will remain unaffected. Requires {@link #FEATURE_CONTENT_TRANSITIONS}.
*
* @return the Transition to use to move Views into the initial Scene.
*/
public void setAllowOverlappingEnterTransition(boolean allow) {
}
public Transition getEnterTransition() { return null; }
/**
* Controls how the Activity's Scene fades out and when the calling Activity's
* enter scene is triggered when finishing to return to a calling Activity.
* <p>When allow is true, the Scene will fade out quickly
* and inform the calling Activity to transition in when the fade completes.
* When allow is false, the calling Activity will transition in after
* the Activity's Scene has exited.
* </p>
* @param allow Set to true to have the Activity fade out as soon as possible
* and transition in the calling Activity. The default value is
* true.
* Returns the Transition that will be used to move Views out of the scene when starting a
* new Activity. The exiting Views will be those that are regular Views or ViewGroups that
* have {@link ViewGroup#isTransitionGroup} return true. Typical Transitions will extend
* {@link android.transition.Visibility} as exiting is governed by changing visibility
* from {@link View#VISIBLE} to {@link View#INVISIBLE}. If transition is null, the views will
* remain unaffected. Requires {@link #FEATURE_CONTENT_TRANSITIONS}.
* @return the Transition to use to move Views out of the scene when calling a
* new Activity.
*/
public void setAllowOverlappingExitTransition(boolean allow) {
}
public Transition getExitTransition() { return null; }
/**
* Start the exit transition.
* @hide
* Sets the Transition that will be used for shared elements transferred into the content
* Scene. Typical Transitions will affect size and location, such as
* {@link android.transition.MoveImage} and {@link android.transition.ChangeBounds}. A null
* value will cause transferred shared elements to blink to the final position.
* Requires {@link #FEATURE_CONTENT_TRANSITIONS}.
* @param transition The Transition to use for shared elements transferred into the content
* Scene.
*/
public Bundle startExitTransitionToCallee(Bundle options) {
return null;
}
public void setSharedElementEnterTransition(Transition transition) {}
/**
* Starts the transition back to the calling Activity.
* onTransitionEnd will be called on the current thread if there is no exit transition.
* @hide
* Returns the Transition that will be used for shared elements transferred into the content
* Scene. Requires {@link #FEATURE_CONTENT_TRANSITIONS}.
* @return Transition to use for sharend elements transferred into the content Scene.
*/
public void startExitTransitionToCaller(Runnable onTransitionEnd) {
onTransitionEnd.run();
}
/** @hide */
public void restoreViewVisibilityAfterTransitionToCallee() {
}
public Transition getSharedElementEnterTransition() { return null; }
/**
* On entering Activity Scene transitions, shared element names may be mapped from a
* source Activity's specified name to a unique shared element name in the View hierarchy.
* Under most circumstances, mapping is not necessary - a single View will have the
* shared element name given by the calling Activity. However, if there are several similar
* Views (e.g. in a ListView), the correct shared element must be mapped.
* @param sharedElementNames A mapping from the calling Activity's assigned shared element
* name to a unique shared element name in the View hierarchy.
* Sets the Transition that will be used for shared elements after starting a new Activity
* before the shared elements are transferred to the called Activity. If the shared elements
* must animate during the exit transition, this Transition should be used. Upon completion,
* the shared elements may be transferred to the started Activity.
* Requires {@link #FEATURE_CONTENT_TRANSITIONS}.
* @param transition The Transition to use for shared elements in the launching Window
* prior to transferring to the launched Activity's Window.
*/
public void mapTransitionTargets(Map<String, String> sharedElementNames) {
}
public void setSharedElementExitTransition(Transition transition) {}
/**
* Returns the Transition to use for shared elements in the launching Window prior
* to transferring to the launched Activity's Window.
* Requires {@link #FEATURE_CONTENT_TRANSITIONS}.
*
* @return the Transition to use for shared elements in the launching Window prior
* to transferring to the launched Activity's Window.
*/
public Transition getSharedElementExitTransition() { return null; }
/**
* Controls how the transition set in
* {@link #setEnterTransition(android.transition.Transition)} overlaps with the exit
* transition of the calling Activity. When true, the transition will start as soon as possible.
* When false, the transition will wait until the remote exiting transition completes before
* starting.
* @param allow true to start the enter transition when possible or false to
* wait until the exiting transition completes.
*/
public void setAllowEnterTransitionOverlap(boolean allow) {}
/**
* Returns how the transition set in
* {@link #setEnterTransition(android.transition.Transition)} overlaps with the exit
* transition of the calling Activity. When true, the transition will start as soon as possible.
* When false, the transition will wait until the remote exiting transition completes before
* starting.
* @return true when the enter transition should start as soon as possible or false to
* when it should wait until the exiting transition completes.
*/
public boolean getAllowEnterTransitionOverlap() { return true; }
/**
* Controls how the transition set in
* {@link #setExitTransition(android.transition.Transition)} overlaps with the exit
* transition of the called Activity when reentering after if finishes. When true,
* the transition will start as soon as possible. When false, the transition will wait
* until the called Activity's exiting transition completes before starting.
* @param allow true to start the transition when possible or false to wait until the
* called Activity's exiting transition completes.
*/
public void setAllowExitTransitionOverlap(boolean allow) {}
/**
* Returns how the transition set in
* {@link #setExitTransition(android.transition.Transition)} overlaps with the exit
* transition of the called Activity when reentering after if finishes. When true,
* the transition will start as soon as possible. When false, the transition will wait
* until the called Activity's exiting transition completes before starting.
* @return true when the transition should start when possible or false when it should wait
* until the called Activity's exiting transition completes.
*/
public boolean getAllowExitTransitionOverlap() { return true; }
}

View File

@@ -444,9 +444,4 @@ public class ToolbarActionBar extends ActionBar {
mMenuVisibilityListeners.get(i).onMenuVisibilityChanged(isVisible);
}
}
@Override
public void captureSharedElements(Map<String, View> sharedElements) {
mToolbar.findSharedElements(sharedElements);
}
}

View File

@@ -362,10 +362,6 @@ public class WindowDecorActionBar extends ActionBar {
setSubtitle(mContext.getString(resId));
}
public void captureSharedElements(Map<String, View> sharedElements) {
mContainerView.findSharedElements(sharedElements);
}
public void setSelectedNavigationItem(int position) {
switch (mActionView.getNavigationMode()) {
case NAVIGATION_MODE_TABS: