summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChet Haase <chet@google.com>2012-05-18 14:17:57 -0700
committerChet Haase <chet@google.com>2013-04-18 13:33:13 -0700
commitfaebd8f0795b7d275fb4e503533c8c0c4a9acc21 (patch)
tree464de8bb5dcd9ae99402ebb630d329dc8ce953cc
parentb3caa9200a61cde1178a2c83419de56579d3c5a5 (diff)
downloadframeworks_base-faebd8f0795b7d275fb4e503533c8c0c4a9acc21.zip
frameworks_base-faebd8f0795b7d275fb4e503533c8c0c4a9acc21.tar.gz
frameworks_base-faebd8f0795b7d275fb4e503533c8c0c4a9acc21.tar.bz2
First draft of Scenes & Transitions feature
This checkin has preliminary API (in flux, definitely changes still to be made) and implementation for a new "Scenes & Transitions" feature. The current implementation allows you to define different Scenes (via layout resource IDs or callbacks) and Transitions to be used when changing to those scenes. By default, scene changes will use AutoTransition, which generally does the right thing. There are no overview docs or tutorials yet. The best way to learn how things work is to see the code for the various tests in frameworks/base/tests/TransitionTests. Expect the API to change. Expect the implementation to change (mostly to add more functionality). Expect bugs, but tell me if things do not work as expected. Change-Id: Ib025a9f565678b225afa4759325cf6d496cc7215
-rw-r--r--api/current.txt145
-rw-r--r--core/java/android/view/View.java30
-rw-r--r--core/java/android/view/transition/AutoTransition.java34
-rw-r--r--core/java/android/view/transition/Crossfade.java163
-rw-r--r--core/java/android/view/transition/Fade.java209
-rw-r--r--core/java/android/view/transition/Move.java299
-rw-r--r--core/java/android/view/transition/Recolor.java118
-rw-r--r--core/java/android/view/transition/Rotate.java67
-rw-r--r--core/java/android/view/transition/Scene.java191
-rw-r--r--core/java/android/view/transition/Slide.java70
-rw-r--r--core/java/android/view/transition/TextChange.java90
-rw-r--r--core/java/android/view/transition/Transition.java911
-rw-r--r--core/java/android/view/transition/TransitionGroup.java292
-rw-r--r--core/java/android/view/transition/TransitionInflater.java392
-rw-r--r--core/java/android/view/transition/TransitionManager.java261
-rw-r--r--core/java/android/view/transition/TransitionValues.java60
-rw-r--r--core/java/android/view/transition/Visibility.java243
-rw-r--r--core/java/android/view/transition/package.html25
-rw-r--r--core/res/res/values/attrs.xml22
-rw-r--r--core/res/res/values/public.xml4
-rw-r--r--tests/TransitionTests/Android.mk18
-rw-r--r--tests/TransitionTests/AndroidManifest.xml211
-rw-r--r--tests/TransitionTests/res/drawable-hdpi/icon.pngbin0 -> 4147 bytes
-rw-r--r--tests/TransitionTests/res/drawable-ldpi/icon.pngbin0 -> 1723 bytes
-rw-r--r--tests/TransitionTests/res/drawable-mdpi/icon.pngbin0 -> 2574 bytes
-rw-r--r--tests/TransitionTests/res/drawable-nodpi/arrow_thumbnail.pngbin0 -> 2214 bytes
-rw-r--r--tests/TransitionTests/res/drawable-nodpi/self_portrait_square.jpgbin0 -> 6380 bytes
-rw-r--r--tests/TransitionTests/res/drawable-nodpi/self_portrait_square_100.jpgbin0 -> 6643 bytes
-rw-r--r--tests/TransitionTests/res/drawable-nodpi/self_portrait_square_200.jpgbin0 -> 13430 bytes
-rw-r--r--tests/TransitionTests/res/layout/activity_login.xml86
-rw-r--r--tests/TransitionTests/res/layout/button_template.xml9
-rw-r--r--tests/TransitionTests/res/layout/changing_text_1.xml39
-rw-r--r--tests/TransitionTests/res/layout/changing_text_2.xml39
-rw-r--r--tests/TransitionTests/res/layout/clipping_text_1.xml22
-rw-r--r--tests/TransitionTests/res/layout/clipping_text_2.xml21
-rw-r--r--tests/TransitionTests/res/layout/contact_collapsed.xml51
-rw-r--r--tests/TransitionTests/res/layout/contact_expanded.xml41
-rw-r--r--tests/TransitionTests/res/layout/contacts_list.xml11
-rw-r--r--tests/TransitionTests/res/layout/crossfade.xml28
-rw-r--r--tests/TransitionTests/res/layout/crossfade_1.xml29
-rw-r--r--tests/TransitionTests/res/layout/fading_test.xml37
-rw-r--r--tests/TransitionTests/res/layout/fading_test_scene_2.xml34
-rw-r--r--tests/TransitionTests/res/layout/fading_test_simple.xml21
-rw-r--r--tests/TransitionTests/res/layout/fading_test_simple2.xml23
-rw-r--r--tests/TransitionTests/res/layout/incorrect_password.xml37
-rw-r--r--tests/TransitionTests/res/layout/instance_targets.xml38
-rw-r--r--tests/TransitionTests/res/layout/list_view_add_remove.xml14
-rw-r--r--tests/TransitionTests/res/layout/login_password.xml86
-rw-r--r--tests/TransitionTests/res/layout/main.xml11
-rw-r--r--tests/TransitionTests/res/layout/new_user.xml92
-rw-r--r--tests/TransitionTests/res/layout/overlay_test.xml22
-rw-r--r--tests/TransitionTests/res/layout/reparenting.xml17
-rw-r--r--tests/TransitionTests/res/layout/resources_test_layout.xml3
-rw-r--r--tests/TransitionTests/res/layout/results_screen.xml66
-rw-r--r--tests/TransitionTests/res/layout/search_screen.xml25
-rw-r--r--tests/TransitionTests/res/layout/success.xml36
-rw-r--r--tests/TransitionTests/res/layout/surface_texture_views.xml15
-rw-r--r--tests/TransitionTests/res/layout/unique_id_test.xml9
-rw-r--r--tests/TransitionTests/res/layout/username_taken.xml37
-rw-r--r--tests/TransitionTests/res/scene/incorrect_password_scene.xml2
-rw-r--r--tests/TransitionTests/res/scene/login_scene.xml2
-rw-r--r--tests/TransitionTests/res/scene/my_scene.xml3
-rw-r--r--tests/TransitionTests/res/scene/new_user_scene.xml2
-rw-r--r--tests/TransitionTests/res/scene/password_scene.xml2
-rw-r--r--tests/TransitionTests/res/scene/results_scene.xml3
-rw-r--r--tests/TransitionTests/res/scene/search_scene.xml3
-rw-r--r--tests/TransitionTests/res/scene/success_scene.xml2
-rw-r--r--tests/TransitionTests/res/scene/username_taken_scene.xml2
-rw-r--r--tests/TransitionTests/res/transition/colorizer_transition.xml6
-rw-r--r--tests/TransitionTests/res/transition/fader.xml1
-rw-r--r--tests/TransitionTests/res/transition/login_slider_transition.xml22
-rw-r--r--tests/TransitionTests/res/transition/login_transition_mgr.xml39
-rw-r--r--tests/TransitionTests/res/transition/mover.xml1
-rw-r--r--tests/TransitionTests/res/transition/mover_fader.xml5
-rw-r--r--tests/TransitionTests/res/transition/my_transition.xml20
-rw-r--r--tests/TransitionTests/res/transition/my_transition_mgr.xml6
-rw-r--r--tests/TransitionTests/res/values-v11/styles.xml11
-rw-r--r--tests/TransitionTests/res/values-v14/styles.xml12
-rw-r--r--tests/TransitionTests/res/values/strings.xml42
-rw-r--r--tests/TransitionTests/res/values/styles.xml20
-rw-r--r--tests/TransitionTests/src/com/android/transitiontests/ChangingText.java63
-rw-r--r--tests/TransitionTests/src/com/android/transitiontests/ClippingText.java66
-rw-r--r--tests/TransitionTests/src/com/android/transitiontests/ContactsExpansion.java123
-rw-r--r--tests/TransitionTests/src/com/android/transitiontests/CrossFadeDemo.java67
-rw-r--r--tests/TransitionTests/src/com/android/transitiontests/Demo0.java60
-rw-r--r--tests/TransitionTests/src/com/android/transitiontests/Demo1.java88
-rw-r--r--tests/TransitionTests/src/com/android/transitiontests/Demo2.java79
-rw-r--r--tests/TransitionTests/src/com/android/transitiontests/Demo3.java65
-rw-r--r--tests/TransitionTests/src/com/android/transitiontests/Demo4.java74
-rw-r--r--tests/TransitionTests/src/com/android/transitiontests/Demo5.java54
-rw-r--r--tests/TransitionTests/src/com/android/transitiontests/FadingTest.java74
-rw-r--r--tests/TransitionTests/src/com/android/transitiontests/HitRectBug.java92
-rw-r--r--tests/TransitionTests/src/com/android/transitiontests/InstanceTargets.java69
-rw-r--r--tests/TransitionTests/src/com/android/transitiontests/ListViewAddRemove.java167
-rw-r--r--tests/TransitionTests/src/com/android/transitiontests/ListViewAddRemoveNoTransition.java104
-rw-r--r--tests/TransitionTests/src/com/android/transitiontests/LoginActivity.java105
-rw-r--r--tests/TransitionTests/src/com/android/transitiontests/LoginActivityFromResources.java94
-rw-r--r--tests/TransitionTests/src/com/android/transitiontests/OverlayTest.java55
-rw-r--r--tests/TransitionTests/src/com/android/transitiontests/Reparenting.java76
-rw-r--r--tests/TransitionTests/src/com/android/transitiontests/ResourceLoadingTest.java76
-rw-r--r--tests/TransitionTests/src/com/android/transitiontests/ScenesTestAutoTargets.java66
-rw-r--r--tests/TransitionTests/src/com/android/transitiontests/ScenesTestAutoTransition.java57
-rw-r--r--tests/TransitionTests/src/com/android/transitiontests/ScenesTestAutoTransition2.java55
-rw-r--r--tests/TransitionTests/src/com/android/transitiontests/ScenesTestv21.java75
-rw-r--r--tests/TransitionTests/src/com/android/transitiontests/SequenceTest.java74
-rw-r--r--tests/TransitionTests/src/com/android/transitiontests/SequenceTestSimple.java71
-rw-r--r--tests/TransitionTests/src/com/android/transitiontests/SurfaceAndTextureViews.java195
-rw-r--r--tests/TransitionTests/src/com/android/transitiontests/UniqueIds.java86
-rw-r--r--tools/aapt/Resource.cpp51
109 files changed, 7441 insertions, 0 deletions
diff --git a/api/current.txt b/api/current.txt
index 5b6e3a1..c1a02da 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -512,6 +512,7 @@ package android {
field public static final int freezesText = 16843116; // 0x101016c
field public static final int fromAlpha = 16843210; // 0x10101ca
field public static final int fromDegrees = 16843187; // 0x10101b3
+ field public static final int fromScene = 16843737; // 0x10103d9
field public static final int fromXDelta = 16843206; // 0x10101c6
field public static final int fromXScale = 16843202; // 0x10101c2
field public static final int fromYDelta = 16843208; // 0x10101c8
@@ -1012,6 +1013,7 @@ package android {
field public static final int targetActivity = 16843266; // 0x1010202
field public static final int targetClass = 16842799; // 0x101002f
field public static final int targetDescriptions = 16843680; // 0x10103a0
+ field public static final int targetID = 16843736; // 0x10103d8
field public static final int targetPackage = 16842785; // 0x1010021
field public static final int targetSdkVersion = 16843376; // 0x1010270
field public static final int taskAffinity = 16842770; // 0x1010012
@@ -1100,6 +1102,7 @@ package android {
field public static final int titleTextStyle = 16843512; // 0x10102f8
field public static final int toAlpha = 16843211; // 0x10101cb
field public static final int toDegrees = 16843188; // 0x10101b4
+ field public static final int toScene = 16843738; // 0x10103da
field public static final int toXDelta = 16843207; // 0x10101c7
field public static final int toXScale = 16843203; // 0x10101c3
field public static final int toYDelta = 16843209; // 0x10101c9
@@ -1114,6 +1117,7 @@ package android {
field public static final int transcriptMode = 16843008; // 0x1010100
field public static final int transformPivotX = 16843552; // 0x1010320
field public static final int transformPivotY = 16843553; // 0x1010321
+ field public static final int transition = 16843739; // 0x10103db
field public static final int translationX = 16843554; // 0x1010322
field public static final int translationY = 16843555; // 0x1010323
field public static final int type = 16843169; // 0x10101a1
@@ -25876,6 +25880,7 @@ package android.view {
method public java.lang.CharSequence getContentDescription();
method public final android.content.Context getContext();
method protected android.view.ContextMenu.ContextMenuInfo getContextMenuInfo();
+ method public android.view.transition.Scene getCurrentScene();
method public static int getDefaultSize(int, int);
method public android.view.Display getDisplay();
method public final int[] getDrawableState();
@@ -28023,6 +28028,146 @@ package android.view.textservice {
}
+package android.view.transition {
+
+ public class AutoTransition extends android.view.transition.TransitionGroup {
+ ctor public AutoTransition();
+ }
+
+ public class Crossfade extends android.view.transition.Transition {
+ ctor public Crossfade();
+ method protected void captureValues(android.view.transition.TransitionValues, boolean);
+ method protected android.animation.Animator play(android.view.ViewGroup, android.view.transition.TransitionValues, android.view.transition.TransitionValues);
+ }
+
+ public class Fade extends android.view.transition.Visibility {
+ ctor public Fade();
+ ctor public Fade(int);
+ field public static final int IN = 1; // 0x1
+ field public static final int OUT = 2; // 0x2
+ }
+
+ public class Move extends android.view.transition.Transition {
+ ctor public Move();
+ method protected void captureValues(android.view.transition.TransitionValues, boolean);
+ method protected android.animation.Animator play(android.view.ViewGroup, android.view.transition.TransitionValues, android.view.transition.TransitionValues);
+ method public void setReparent(boolean);
+ method public void setResizeClip(boolean);
+ }
+
+ public class Recolor extends android.view.transition.Transition {
+ ctor public Recolor();
+ method protected void captureValues(android.view.transition.TransitionValues, boolean);
+ method protected android.animation.Animator play(android.view.ViewGroup, android.view.transition.TransitionValues, android.view.transition.TransitionValues);
+ }
+
+ public class Rotate extends android.view.transition.Transition {
+ ctor public Rotate();
+ method protected void captureValues(android.view.transition.TransitionValues, boolean);
+ method protected android.animation.Animator play(android.view.ViewGroup, android.view.transition.TransitionValues, android.view.transition.TransitionValues);
+ }
+
+ public final class Scene {
+ ctor public Scene(android.view.ViewGroup);
+ ctor public Scene(android.view.ViewGroup, int, android.content.Context);
+ ctor public Scene(android.view.ViewGroup, android.view.ViewGroup);
+ method public void enter();
+ method public void exit();
+ method public android.view.ViewGroup getSceneRoot();
+ method public void setEnterAction(java.lang.Runnable);
+ method public void setExitAction(java.lang.Runnable);
+ }
+
+ public class Slide extends android.view.transition.Visibility {
+ ctor public Slide();
+ }
+
+ public class TextChange extends android.view.transition.Transition {
+ ctor public TextChange();
+ method protected void captureValues(android.view.transition.TransitionValues, boolean);
+ method protected android.animation.Animator play(android.view.ViewGroup, android.view.transition.TransitionValues, android.view.transition.TransitionValues);
+ }
+
+ public abstract class Transition {
+ ctor public Transition();
+ method public void addListener(android.view.transition.Transition.TransitionListener);
+ method protected void cancelTransition();
+ method protected abstract void captureValues(android.view.transition.TransitionValues, boolean);
+ method public long getDuration();
+ method public android.animation.TimeInterpolator getInterpolator();
+ method public java.util.ArrayList<android.view.transition.Transition.TransitionListener> getListeners();
+ method public long getStartDelay();
+ method public int[] getTargetIds();
+ method public android.view.View[] getTargets();
+ method protected void onTransitionCancel();
+ method protected void onTransitionEnd();
+ method protected void onTransitionStart();
+ method protected abstract android.animation.Animator play(android.view.ViewGroup, android.view.transition.TransitionValues, android.view.transition.TransitionValues);
+ method protected boolean prePlay(android.view.ViewGroup, android.view.transition.TransitionValues, android.view.transition.TransitionValues);
+ method public void removeListener(android.view.transition.Transition.TransitionListener);
+ method public android.view.transition.Transition setDuration(long);
+ method public void setInterpolator(android.animation.TimeInterpolator);
+ method public void setStartDelay(long);
+ method public android.view.transition.Transition setTargetIds(int...);
+ method public android.view.transition.Transition setTargets(android.view.View...);
+ }
+
+ public static abstract interface Transition.TransitionListener {
+ method public abstract void onTransitionCancel(android.view.transition.Transition);
+ method public abstract void onTransitionEnd(android.view.transition.Transition);
+ method public abstract void onTransitionStart(android.view.transition.Transition);
+ }
+
+ public class TransitionGroup extends android.view.transition.Transition {
+ ctor public TransitionGroup();
+ ctor public TransitionGroup(int);
+ method public void addTransitions(android.view.transition.Transition...);
+ method protected void captureValues(android.view.transition.TransitionValues, boolean);
+ method protected android.animation.Animator play(android.view.ViewGroup, android.view.transition.TransitionValues, android.view.transition.TransitionValues);
+ method public void removeTransition(android.view.transition.Transition);
+ method public void setOrdering(int);
+ field public static final int SEQUENTIALLY = 1; // 0x1
+ field public static final int TOGETHER = 0; // 0x0
+ }
+
+ public class TransitionInflater {
+ method public static android.view.transition.TransitionInflater from(android.content.Context);
+ method public android.view.transition.Scene inflateScene(int, android.view.ViewGroup);
+ method public android.view.transition.Transition inflateTransition(int);
+ method public android.view.transition.TransitionManager inflateTransitionManager(int, android.view.ViewGroup);
+ }
+
+ public class TransitionManager {
+ ctor public TransitionManager();
+ method public android.view.transition.Transition getDefaultTransition();
+ method public static void go(android.view.transition.Scene);
+ method public static void go(android.view.transition.Scene, android.view.transition.Transition);
+ method public static void go(android.view.ViewGroup, java.lang.Runnable);
+ method public static void go(android.view.ViewGroup, java.lang.Runnable, android.view.transition.Transition);
+ method public void setDefaultTransition(android.view.transition.Transition);
+ method public void setTransition(android.view.transition.Scene, android.view.transition.Transition);
+ method public void setTransition(android.view.transition.Scene, android.view.transition.Scene, android.view.transition.Transition);
+ method public void transitionTo(android.view.transition.Scene);
+ }
+
+ public class TransitionValues {
+ ctor public TransitionValues();
+ field public final java.util.HashMap values;
+ field public android.view.View view;
+ }
+
+ public abstract class Visibility extends android.view.transition.Transition {
+ ctor public Visibility();
+ method protected android.animation.Animator appear(android.view.ViewGroup, android.view.View, int, android.view.View, int);
+ method protected void captureValues(android.view.transition.TransitionValues, boolean);
+ method protected android.animation.Animator disappear(android.view.ViewGroup, android.view.View, int, android.view.View, int);
+ method protected android.animation.Animator play(android.view.ViewGroup, android.view.transition.TransitionValues, android.view.transition.TransitionValues);
+ method protected boolean preAppear(android.view.ViewGroup, android.view.View, int, android.view.View, int);
+ method protected boolean preDisappear(android.view.ViewGroup, android.view.View, int, android.view.View, int);
+ }
+
+}
+
package android.webkit {
public class ConsoleMessage {
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 2903b6f..7aa2cbf 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -73,6 +73,7 @@ import android.view.animation.Transformation;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputConnection;
import android.view.inputmethod.InputMethodManager;
+import android.view.transition.Scene;
import android.widget.ScrollBarDrawable;
import static android.os.Build.VERSION_CODES.*;
@@ -1572,6 +1573,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*/
protected Object mTag;
+ private Scene mCurrentScene = null;
+
// for mPrivateFlags:
/** {@hide} */
static final int PFLAG_WANTS_FOCUS = 0x00000001;
@@ -12037,6 +12040,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
mCurrentAnimation = null;
+ mCurrentScene = null;
+
resetAccessibilityStateChanged();
}
@@ -17758,6 +17763,31 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
/**
+ * Set the current Scene that this view is in. The current scene is set only
+ * on the root view of a scene, not for every view in that hierarchy. This
+ * information is used by Scene to determine whether there is a previous
+ * scene which should be exited before the new scene is entered.
+ *
+ * @param scene The new scene being set on the view
+ *
+ * @hide
+ */
+ public void setCurrentScene(Scene scene) {
+ mCurrentScene = scene;
+ }
+
+ /**
+ * Gets the current {@link Scene} set on this view. A scene is set on a view
+ * only if that view is the scene root.
+ *
+ * @return The current Scene set on this view. A value of null indicates that
+ * no Scene is current set.
+ */
+ public Scene getCurrentScene() {
+ return mCurrentScene;
+ }
+
+ /**
* Interface definition for a callback to be invoked when a hardware key event is
* dispatched to this view. The callback will be invoked before the key event is
* given to the view. This is only useful for hardware keyboards; a software input
diff --git a/core/java/android/view/transition/AutoTransition.java b/core/java/android/view/transition/AutoTransition.java
new file mode 100644
index 0000000..d94cf2c
--- /dev/null
+++ b/core/java/android/view/transition/AutoTransition.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2013 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.view.transition;
+
+/**
+ * Utility class for creating a default transition that automatically fades,
+ * moves, and resizes views during a scene change.
+ */
+public class AutoTransition extends TransitionGroup {
+
+ /**
+ * Constructs an AutoTransition object, which is a TransitionGroup which
+ * first fades out disappearing targets, then moves and resizes existing
+ * targets, and finally fades in appearing targets.
+ *
+ */
+ public AutoTransition() {
+ setOrdering(SEQUENTIALLY);
+ addTransitions(new Fade(Fade.OUT), new Move(), new Fade(Fade.IN));
+ }
+}
diff --git a/core/java/android/view/transition/Crossfade.java b/core/java/android/view/transition/Crossfade.java
new file mode 100644
index 0000000..babf58f
--- /dev/null
+++ b/core/java/android/view/transition/Crossfade.java
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2013 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.view.transition;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.animation.RectEvaluator;
+import android.animation.ValueAnimator;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Rect;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.util.Log;
+import android.view.SurfaceView;
+import android.view.TextureView;
+import android.view.View;
+import android.view.ViewGroup;
+
+import java.util.HashMap;
+
+/**
+ * This transition captures bitmap representations of target views before and
+ * after the scene change and fades between them.
+ *
+ * <p>Note: This transition is not compatible with {@link TextureView}
+ * or {@link SurfaceView}.</p>
+ */
+public class Crossfade extends Transition {
+ // TODO: Add a hook that lets a Transition call user code to query whether it should run on
+ // a given target view. This would save bitmap comparisons in this transition, for example.
+
+ private static final String LOG_TAG = "Crossfade";
+
+ private static final String PROPNAME_BITMAP = "android:crossfade:bitmap";
+ private static final String PROPNAME_DRAWABLE = "android:crossfade:drawable";
+ private static final String PROPNAME_BOUNDS = "android:crossfade:bounds";
+
+ private static RectEvaluator sRectEvaluator = new RectEvaluator();
+
+ @Override
+ protected boolean prePlay(ViewGroup sceneRoot, TransitionValues startValues,
+ TransitionValues endValues) {
+ if (startValues == null || endValues == null) {
+ return false;
+ }
+ final View view = startValues.view;
+ HashMap<String, Object> startVals = startValues.values;
+ HashMap<String, Object> endVals = endValues.values;
+ Bitmap startBitmap = (Bitmap) startVals.get(PROPNAME_BITMAP);
+ Bitmap endBitmap = (Bitmap) endVals.get(PROPNAME_BITMAP);
+ Drawable startDrawable = (Drawable) startVals.get(PROPNAME_DRAWABLE);
+ Drawable endDrawable = (Drawable) endVals.get(PROPNAME_DRAWABLE);
+ if (Transition.DBG) {
+ Log.d(LOG_TAG, "StartBitmap.sameAs(endBitmap) = " + startBitmap.sameAs(endBitmap) +
+ " for start, end: " + startBitmap + ", " + endBitmap);
+ }
+ if (startDrawable != null && endDrawable != null && !startBitmap.sameAs(endBitmap)) {
+ view.getOverlay().add(endDrawable);
+ view.getOverlay().add(startDrawable);
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ protected Animator play(ViewGroup sceneRoot, TransitionValues startValues,
+ TransitionValues endValues) {
+ if (startValues == null || endValues == null) {
+ return null;
+ }
+ HashMap<String, Object> startVals = startValues.values;
+ HashMap<String, Object> endVals = endValues.values;
+
+ final View view = endValues.view;
+ Rect startBounds = (Rect) startVals.get(PROPNAME_BOUNDS);
+ Rect endBounds = (Rect) endVals.get(PROPNAME_BOUNDS);
+ final BitmapDrawable startDrawable = (BitmapDrawable) startVals.get(PROPNAME_DRAWABLE);
+ final BitmapDrawable endDrawable = (BitmapDrawable) endVals.get(PROPNAME_DRAWABLE);
+
+ // The transition works by placing the end drawable under the start drawable and
+ // gradually fading out the start drawable. So it's not really a cross-fade, but rather
+ // a reveal of the end scene over time. Also, animate the bounds of both drawables
+ // to mimic the change in the size of the view itself between scenes.
+ ObjectAnimator anim = ObjectAnimator.ofInt(startDrawable, "alpha", 0);
+ anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ // TODO: some way to auto-invalidate views based on drawable changes? callbacks?
+ view.invalidate(startDrawable.getBounds());
+ }
+ });
+ if (Transition.DBG) {
+ Log.d(LOG_TAG, "Crossfade: created anim " + anim + " for start, end values " +
+ startValues + ", " + endValues);
+ }
+ anim.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ view.getOverlay().remove(startDrawable);
+ view.getOverlay().remove(endDrawable);
+ }
+ });
+ AnimatorSet set = new AnimatorSet();
+ set.playTogether(anim);
+ if (!startBounds.equals(endBounds)) {
+ if (Transition.DBG) {
+ Log.d(LOG_TAG, "animating from startBounds to endBounds: " +
+ startBounds + ", " + endBounds);
+ }
+ Animator anim2 = ObjectAnimator.ofObject(startDrawable, "bounds",
+ sRectEvaluator, startBounds, endBounds);
+ Animator anim3 = ObjectAnimator.ofObject(endDrawable, "bounds",
+ sRectEvaluator, startBounds, endBounds);
+ set.playTogether(anim2);
+ set.playTogether(anim3);
+ }
+ return set;
+ }
+
+ @Override
+ protected void captureValues(TransitionValues values, boolean start) {
+ View view = values.view;
+ values.values.put(PROPNAME_BOUNDS, new Rect(0, 0,
+ view.getWidth(), view.getHeight()));
+
+ if (Transition.DBG) {
+ Log.d(LOG_TAG, "Captured bounds " + values.values.get(PROPNAME_BOUNDS) + ": start = " +
+ start);
+ }
+ Bitmap bitmap = Bitmap.createBitmap(view.getWidth(), view.getHeight(),
+ Bitmap.Config.ARGB_8888);
+ if (view instanceof TextureView) {
+ bitmap = ((TextureView) view).getBitmap();
+ } else {
+ Canvas c = new Canvas(bitmap);
+ view.draw(c);
+ }
+ values.values.put(PROPNAME_BITMAP, bitmap);
+ // TODO: I don't have resources, can't call the non-deprecated method?
+ BitmapDrawable drawable = new BitmapDrawable(bitmap);
+ // TODO: lrtb will be wrong if the view has transXY set
+ drawable.setBounds(view.getLeft(), view.getTop(), view.getRight(), view.getBottom());
+ values.values.put(PROPNAME_DRAWABLE, drawable);
+ }
+
+}
diff --git a/core/java/android/view/transition/Fade.java b/core/java/android/view/transition/Fade.java
new file mode 100644
index 0000000..8e4909d
--- /dev/null
+++ b/core/java/android/view/transition/Fade.java
@@ -0,0 +1,209 @@
+/*
+ * Copyright (C) 2013 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.view.transition;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
+import android.util.Log;
+import android.view.View;
+import android.view.ViewGroup;
+
+/**
+ * This transition tracks changes to the visibility of target views in the
+ * start and end scenes and fades views in or out when they become visible
+ * or non-visible. Visibility is determined by both the
+ * {@link View#setVisibility(int)} state of the view as well as whether it
+ * is parented in the current view hierarchy.
+ */
+public class Fade extends Visibility {
+
+ private static final String LOG_TAG = "Fade";
+
+ /**
+ * Fading mode used in {@link #Fade(int)} to make the transition
+ * operate on targets that are appearing. Maybe be combined with
+ * {@link #OUT} to fade both in and out.
+ */
+ public static final int IN = 0x1;
+ /**
+ * Fading mode used in {@link #Fade(int)} to make the transition
+ * operate on targets that are disappearing. Maybe be combined with
+ * {@link #IN} to fade both in and out.
+ */
+ public static final int OUT = 0x2;
+
+ private int mFadingMode;
+
+ /**
+ * Constructs a Fade transition that will fade targets in and out.
+ */
+ public Fade() {
+ this(IN | OUT);
+ }
+
+ /**
+ * Constructs a Fade transition that will fade targets in
+ * and/or out, according to the value of fadingMode.
+ *
+ * @param fadingMode The behavior of this transition, a combination of
+ * {@link #IN} and {@link #OUT}.
+ */
+ public Fade(int fadingMode) {
+ mFadingMode = fadingMode;
+ }
+
+ /**
+ * Utility method to handle creating and running the Animator.
+ */
+ private Animator runAnimation(View view, float startAlpha, float endAlpha,
+ Animator.AnimatorListener listener) {
+ final ObjectAnimator anim = ObjectAnimator.ofFloat(view, "alpha", startAlpha, endAlpha);
+ if (listener != null) {
+ anim.addListener(listener);
+ }
+ // TODO: Maybe extract a method into Transition to run an animation that handles the
+ // duration/startDelay stuff for all subclasses.
+ return anim;
+ }
+
+ @Override
+ protected boolean preAppear(ViewGroup sceneRoot, View startView, int startVisibility,
+ View endView, int endVisibility) {
+ if ((mFadingMode & IN) != IN) {
+ return false;
+ }
+ endView.setAlpha(0);
+ return true;
+ }
+
+ @Override
+ protected Animator appear(ViewGroup sceneRoot, View startView, int startVisibility,
+ View endView, int endVisibility) {
+ if ((mFadingMode & IN) != IN) {
+ return null;
+ }
+ // TODO: hack - retain original value from before preAppear
+ return runAnimation(endView, 0, 1, null);
+ // TODO: end listener to make sure we end at 1 no matter what
+ }
+
+ @Override
+ protected boolean preDisappear(ViewGroup sceneRoot, View startView, int startVisibility,
+ View endView, int endVisibility) {
+ if ((mFadingMode & OUT) != OUT) {
+ return false;
+ }
+ if (Transition.DBG) {
+ Log.d(LOG_TAG, "Fade.predisappear: startView, startVis, endView, endVis = " +
+ startView + ", " + startVisibility + ", " + endView + ", " + endVisibility);
+ }
+ View view;
+ View overlayView = null;
+ View viewToKeep = null;
+ if (endView == null) {
+ // view was removed: add the start view to the Overlay
+ view = startView;
+ overlayView = view;
+ } else {
+ // visibility change
+ if (endVisibility == View.INVISIBLE) {
+ view = endView;
+ viewToKeep = view;
+ } else {
+ // Becoming GONE
+ if (startView == endView) {
+ view = endView;
+ viewToKeep = view;
+ } else {
+ view = startView;
+ overlayView = view;
+ }
+ }
+ }
+ // TODO: add automatic facility to Visibility superclass for keeping views around
+ if (overlayView != null) {
+ // TODO: Need to do this for general case of adding to overlay
+ sceneRoot.getOverlay().add(overlayView);
+ return true;
+ }
+ if (viewToKeep != null) {
+ // TODO: find a different way to do this, like just changing the view to be
+ // VISIBLE for the duration of the transition
+ viewToKeep.setVisibility((View.VISIBLE));
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ protected Animator disappear(ViewGroup sceneRoot, View startView, int startVisibility,
+ View endView, int endVisibility) {
+ if ((mFadingMode & OUT) != OUT) {
+ return null;
+ }
+ if (Transition.DBG) {
+ Log.d(LOG_TAG, "Fade.disappear: startView, startVis, endView, endVis = " +
+ startView + ", " + startVisibility + ", " + endView + ", " + endVisibility);
+ }
+ View view;
+ View overlayView = null;
+ View viewToKeep = null;
+ final int finalVisibility = endVisibility;
+ if (endView == null) {
+ // view was removed: add the start view to the Overlay
+ view = startView;
+ overlayView = view;
+ } else {
+ // visibility change
+ if (endVisibility == View.INVISIBLE) {
+ view = endView;
+ viewToKeep = view;
+ } else {
+ // Becoming GONE
+ if (startView == endView) {
+ view = endView;
+ viewToKeep = view;
+ } else {
+ view = startView;
+ overlayView = view;
+ }
+ }
+ }
+ // TODO: add automatic facility to Visibility superclass for keeping views around
+ final float startAlpha = view.getAlpha();
+ float endAlpha = 0;
+ final View finalView = view;
+ final View finalOverlayView = overlayView;
+ final View finalViewToKeep = viewToKeep;
+ final ViewGroup finalSceneRoot = sceneRoot;
+ final Animator.AnimatorListener endListener = new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ finalView.setAlpha(startAlpha);
+ // TODO: restore view offset from overlay repositioning
+ if (finalViewToKeep != null) {
+ finalViewToKeep.setVisibility(finalVisibility);
+ }
+ if (finalOverlayView != null) {
+ finalSceneRoot.getOverlay().remove(finalOverlayView);
+ }
+ }
+ };
+ return runAnimation(view, startAlpha, endAlpha, endListener);
+ }
+
+} \ No newline at end of file
diff --git a/core/java/android/view/transition/Move.java b/core/java/android/view/transition/Move.java
new file mode 100644
index 0000000..3bd57bd
--- /dev/null
+++ b/core/java/android/view/transition/Move.java
@@ -0,0 +1,299 @@
+/*
+ * Copyright (C) 2013 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.view.transition;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
+import android.animation.PropertyValuesHolder;
+import android.animation.RectEvaluator;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Rect;
+import android.graphics.drawable.BitmapDrawable;
+import android.view.View;
+import android.view.ViewGroup;
+
+import java.util.HashMap;
+
+/**
+ * This transition captures the layout bounds of target views before and after
+ * the scene change and animates those changes during the transition.
+ */
+public class Move extends Transition {
+
+ private static final String PROPNAME_BOUNDS = "android:move:bounds";
+ private static final String PROPNAME_PARENT = "android:move:parent";
+ private static final String PROPNAME_WINDOW_X = "android:move:windowX";
+ private static final String PROPNAME_WINDOW_Y = "android:move:windowY";
+ int[] tempLocation = new int[2];
+ boolean mResizeClip = false;
+ boolean mReparent = false;
+
+ private static RectEvaluator sRectEvaluator = new RectEvaluator();
+
+ public void setResizeClip(boolean resizeClip) {
+ mResizeClip = resizeClip;
+ }
+
+ /**
+ * Setting this flag tells Move to track the before/after parent
+ * of every view using this transition. The flag is not enabled by
+ * default because it requires the parent instances to be the same
+ * in the two scenes or else all parents must use ids to allow
+ * the transition to determine which parents are the same.
+ *
+ * @param reparent true if the transition should track the parent
+ * container of target views and animate parent changes.
+ */
+ public void setReparent(boolean reparent) {
+ mReparent = reparent;
+ }
+
+ @Override
+ protected void captureValues(TransitionValues values, boolean start) {
+ View view = values.view;
+ values.values.put(PROPNAME_BOUNDS, new Rect(view.getLeft(), view.getTop(),
+ view.getRight(), view.getBottom()));
+ values.values.put(PROPNAME_PARENT, values.view.getParent());
+ values.view.getLocationInWindow(tempLocation);
+ values.values.put(PROPNAME_WINDOW_X, tempLocation[0]);
+ values.values.put(PROPNAME_WINDOW_Y, tempLocation[1]);
+ }
+
+ @Override
+ protected Animator play(final ViewGroup sceneRoot, TransitionValues startValues,
+ TransitionValues endValues) {
+ if (startValues == null || endValues == null) {
+ return null;
+ }
+ final View view = endValues.view;
+ if (view.getParent() == null) {
+ // TODO: Might want to make it possible to Move an disappearing view.
+ // This workaround is here because if a parallel Fade is not running on the view
+ // Then it won't get added to the hierarchy and the animator below will not fire,
+ // causing the transition to not end
+ return null;
+ }
+ // TODO: need to handle non-VG case?
+ ViewGroup startParent = (ViewGroup) startValues.values.get(PROPNAME_PARENT);
+ ViewGroup endParent = (ViewGroup) endValues.values.get(PROPNAME_PARENT);
+ if (startParent == null || endParent == null) {
+ return null;
+ }
+ boolean parentsEqual = (startParent == endParent) ||
+ (startParent.getId() == endParent.getId());
+ if (!mReparent || parentsEqual) {
+ // Common case - view belongs to the same layout before/after. Just animate its bounds
+ Rect startBounds = (Rect) startValues.values.get(PROPNAME_BOUNDS);
+ Rect endBounds = (Rect) endValues.values.get(PROPNAME_BOUNDS);
+ int startLeft = startBounds.left;
+ int endLeft = endBounds.left;
+ int startTop = startBounds.top;
+ int endTop = endBounds.top;
+ int startRight = startBounds.right;
+ int endRight = endBounds.right;
+ int startBottom = startBounds.bottom;
+ int endBottom = endBounds.bottom;
+ int startWidth = startRight - startLeft;
+ int startHeight = startBottom - startTop;
+ int endWidth = endRight - endLeft;
+ int endHeight = endBottom - endTop;
+ int numChanges = 0;
+ if (startWidth != 0 && startHeight != 0 && endWidth != 0 && endHeight != 0) {
+ if (startLeft != endLeft) ++numChanges;
+ if (startTop != endTop) ++numChanges;
+ if (startRight != endRight) ++numChanges;
+ if (startBottom != endBottom) ++numChanges;
+ }
+ if (numChanges > 0) {
+ if (!mResizeClip) {
+ PropertyValuesHolder pvh[] = new PropertyValuesHolder[numChanges];
+ int pvhIndex = 0;
+ if (startLeft != endLeft) {
+ pvh[pvhIndex++] = PropertyValuesHolder.ofInt("left", startLeft, endLeft);
+ }
+ if (startTop != endTop) {
+ pvh[pvhIndex++] = PropertyValuesHolder.ofInt("top", startTop, endTop);
+ }
+ if (startRight != endRight) {
+ pvh[pvhIndex++] = PropertyValuesHolder.ofInt("right",
+ startRight, endRight);
+ }
+ if (startBottom != endBottom) {
+ pvh[pvhIndex++] = PropertyValuesHolder.ofInt("bottom",
+ startBottom, endBottom);
+ }
+ ObjectAnimator anim = ObjectAnimator.ofPropertyValuesHolder(view, pvh);
+ if (view.getParent() instanceof ViewGroup) {
+ final ViewGroup parent = (ViewGroup) view.getParent();
+ parent.suppressLayout(true);
+ anim.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ parent.suppressLayout(false);
+ }
+ });
+ }
+ return anim;
+ } else {
+ // Animate location with translationX/Y and size with clip bounds
+ float transXDelta = endLeft - startLeft;
+ float transYDelta = endTop - startTop;
+ int widthDelta = endWidth - startWidth;
+ int heightDelta = endHeight - startHeight;
+ numChanges = 0;
+ if (transXDelta != 0) numChanges++;
+ if (transYDelta != 0) numChanges++;
+ if (widthDelta != 0 || heightDelta != 0) numChanges++;
+ PropertyValuesHolder pvh[] = new PropertyValuesHolder[numChanges];
+ int pvhIndex = 0;
+ if (transXDelta != 0) {
+ pvh[pvhIndex++] = PropertyValuesHolder.ofFloat("translationX",
+ view.getTranslationX(), 0);
+ }
+ if (transYDelta != 0) {
+ pvh[pvhIndex++] = PropertyValuesHolder.ofFloat("translationY",
+ view.getTranslationY(), 0);
+ }
+ if (widthDelta != 0 || heightDelta != 0) {
+ Rect tempStartBounds = new Rect(0, 0, startWidth, startHeight);
+ Rect tempEndBounds = new Rect(0, 0, endWidth, endHeight);
+ pvh[pvhIndex++] = PropertyValuesHolder.ofObject("clipBounds",
+ sRectEvaluator, tempStartBounds, tempEndBounds);
+ }
+ ObjectAnimator anim = ObjectAnimator.ofPropertyValuesHolder(view, pvh);
+ if (view.getParent() instanceof ViewGroup) {
+ final ViewGroup parent = (ViewGroup) view.getParent();
+ parent.suppressLayout(true);
+ anim.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ parent.suppressLayout(false);
+ }
+ });
+ }
+ anim.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ view.setClipBounds(null);
+ }
+ });
+ return anim;
+ }
+ }
+ } else {
+ return (ObjectAnimator) endValues.values.get("drawableAnim");
+ }
+ return null;
+ }
+
+ @Override
+ protected boolean prePlay(final ViewGroup sceneRoot, TransitionValues startValues,
+ TransitionValues endValues) {
+ if (startValues == null || endValues == null) {
+ return false;
+ }
+ HashMap<String, Object> startParentVals = startValues.values;
+ HashMap<String, Object> endParentVals = endValues.values;
+ ViewGroup startParent = (ViewGroup) startParentVals.get(PROPNAME_PARENT);
+ ViewGroup endParent = (ViewGroup) endParentVals.get(PROPNAME_PARENT);
+ if (startParent == null || endParent == null) {
+ return false;
+ }
+ final View view = endValues.view;
+ boolean parentsEqual = (startParent == endParent) ||
+ (startParent.getId() == endParent.getId());
+ // TODO: Might want reparenting to be separate/subclass transition, or at least
+ // triggered by a property on Move. Otherwise, we're forcing the requirement that
+ // all parents in layouts have IDs to avoid layout-inflation resulting in a side-effect
+ // of reparenting the views.
+ if (!mReparent || parentsEqual) {
+ Rect startBounds = (Rect) startValues.values.get(PROPNAME_BOUNDS);
+ Rect endBounds = (Rect) endValues.values.get(PROPNAME_BOUNDS);
+ int startLeft = startBounds.left;
+ int endLeft = endBounds.left;
+ int startTop = startBounds.top;
+ int endTop = endBounds.top;
+ int startRight = startBounds.right;
+ int endRight = endBounds.right;
+ int startBottom = startBounds.bottom;
+ int endBottom = endBounds.bottom;
+ int startWidth = startRight - startLeft;
+ int startHeight = startBottom - startTop;
+ int endWidth = endRight - endLeft;
+ int endHeight = endBottom - endTop;
+ int numChanges = 0;
+ if (startWidth != 0 && startHeight != 0 && endWidth != 0 && endHeight != 0) {
+ if (startLeft != endLeft) ++numChanges;
+ if (startTop != endTop) ++numChanges;
+ if (startRight != endRight) ++numChanges;
+ if (startBottom != endBottom) ++numChanges;
+ }
+ if (numChanges > 0) {
+ if (!mResizeClip) {
+ if (startLeft != endLeft) view.setLeft(startLeft);
+ if (startTop != endTop) view.setTop(startTop);
+ if (startRight != endRight) view.setRight(startRight);
+ if (startBottom != endBottom) view.setBottom(startBottom);
+ } else {
+ if (startWidth != endWidth) view.setRight(endLeft +
+ Math.max(startWidth, endWidth));
+ if (startHeight != endHeight) view.setBottom(endTop +
+ Math.max(startHeight, endHeight));
+ // TODO: don't clobber TX/TY
+ if (startLeft != endLeft) view.setTranslationX(startLeft - endLeft);
+ if (startTop != endTop) view.setTranslationY(startTop - endTop);
+ }
+ return true;
+ }
+ } else {
+ int startX = (Integer) startValues.values.get(PROPNAME_WINDOW_X);
+ int startY = (Integer) startValues.values.get(PROPNAME_WINDOW_Y);
+ int endX = (Integer) endValues.values.get(PROPNAME_WINDOW_X);
+ int endY = (Integer) endValues.values.get(PROPNAME_WINDOW_Y);
+ // TODO: also handle size changes: check bounds and animate size changes
+ if (startX != endX || startY != endY) {
+ sceneRoot.getLocationInWindow(tempLocation);
+ Bitmap bitmap = Bitmap.createBitmap(view.getWidth(), view.getHeight(),
+ Bitmap.Config.ARGB_8888);
+ Canvas canvas = new Canvas(bitmap);
+ view.draw(canvas);
+ final BitmapDrawable drawable = new BitmapDrawable(bitmap);
+ view.setVisibility(View.INVISIBLE);
+ sceneRoot.getOverlay().add(drawable);
+ Rect startBounds = new Rect(startX - tempLocation[0], startY - tempLocation[1],
+ startX - tempLocation[0] + view.getWidth(),
+ startY - tempLocation[1] + view.getHeight());
+ Rect endBounds = new Rect(endX - tempLocation[0], endY - tempLocation[1],
+ endX - tempLocation[0] + view.getWidth(),
+ endY - tempLocation[1] + view.getHeight());
+ ObjectAnimator anim = ObjectAnimator.ofObject(drawable, "bounds",
+ sRectEvaluator, startBounds, endBounds);
+ anim.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ sceneRoot.getOverlay().remove(drawable);
+ view.setVisibility(View.VISIBLE);
+ }
+ });
+ endParentVals.put("drawableAnim", anim);
+ return true;
+ }
+ }
+ return false;
+ }
+}
diff --git a/core/java/android/view/transition/Recolor.java b/core/java/android/view/transition/Recolor.java
new file mode 100644
index 0000000..7048be9
--- /dev/null
+++ b/core/java/android/view/transition/Recolor.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2013 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.view.transition;
+
+import android.animation.Animator;
+import android.animation.ArgbEvaluator;
+import android.animation.ObjectAnimator;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import java.util.HashMap;
+
+/**
+ * This transition tracks changes during scene changes to the
+ * {@link View#setBackground(android.graphics.drawable.Drawable) background}
+ * property of its target views (when the background is a
+ * {@link ColorDrawable}, as well as the
+ * {@link TextView#setTextColor(android.content.res.ColorStateList)
+ * color} of the text for target TextViews. If the color changes between
+ * scenes, the color change is animated.
+ */
+public class Recolor extends Transition {
+
+ private static final String PROPNAME_BACKGROUND = "android:recolor:background";
+ private static final String PROPNAME_TEXT_COLOR = "android:recolor:textColor";
+
+ @Override
+ protected void captureValues(TransitionValues values, boolean start) {
+ values.values.put(PROPNAME_BACKGROUND, values.view.getBackground());
+ if (values.view instanceof TextView) {
+ values.values.put(PROPNAME_TEXT_COLOR, ((TextView)values.view).getCurrentTextColor());
+ }
+ }
+
+ @Override
+ protected boolean prePlay(ViewGroup sceneRoot, TransitionValues startValues,
+ TransitionValues endValues) {
+ if (startValues == null || endValues == null) {
+ return false;
+ }
+ final View view = endValues.view;
+ Drawable startBackground = (Drawable) startValues.values.get(PROPNAME_BACKGROUND);
+ Drawable endBackground = (Drawable) endValues.values.get(PROPNAME_BACKGROUND);
+ boolean changed = false;
+ if (startBackground instanceof ColorDrawable && endBackground instanceof ColorDrawable) {
+ ColorDrawable startColor = (ColorDrawable) startBackground;
+ ColorDrawable endColor = (ColorDrawable) endBackground;
+ if (startColor.getColor() != endColor.getColor()) {
+ endColor.setColor(startColor.getColor());
+ changed = true;
+ }
+ }
+ if (view instanceof TextView) {
+ TextView textView = (TextView) view;
+ int start = (Integer) startValues.values.get(PROPNAME_TEXT_COLOR);
+ int end = (Integer) endValues.values.get(PROPNAME_TEXT_COLOR);
+ if (start != end) {
+ textView.setTextColor(end);
+ changed = true;
+ }
+ }
+ return changed;
+ }
+
+ @Override
+ protected Animator play(ViewGroup sceneRoot, TransitionValues startValues,
+ TransitionValues endValues) {
+ if (startValues == null || endValues == null) {
+ return null;
+ }
+ ObjectAnimator anim = null;
+ final View view = endValues.view;
+ HashMap<String, Object> startVals = startValues.values;
+ HashMap<String, Object> endVals = endValues.values;
+ Drawable startBackground = (Drawable) startVals.get(PROPNAME_BACKGROUND);
+ Drawable endBackground = (Drawable) endVals.get(PROPNAME_BACKGROUND);
+ if (startBackground instanceof ColorDrawable && endBackground instanceof ColorDrawable) {
+ ColorDrawable startColor = (ColorDrawable) startBackground;
+ ColorDrawable endColor = (ColorDrawable) endBackground;
+ if (startColor.getColor() != endColor.getColor()) {
+ anim = ObjectAnimator.ofObject(endBackground, "color",
+ new ArgbEvaluator(), startColor.getColor(), endColor.getColor());
+ if (getStartDelay() > 0) {
+ endColor.setColor(startColor.getColor());
+ }
+ }
+ }
+ if (view instanceof TextView) {
+ TextView textView = (TextView) view;
+ int start = (Integer) startValues.values.get(PROPNAME_TEXT_COLOR);
+ int end = (Integer) endValues.values.get(PROPNAME_TEXT_COLOR);
+ if (start != end) {
+ anim = ObjectAnimator.ofObject(textView, "textColor",
+ new ArgbEvaluator(), start, end);
+ if (getStartDelay() > 0) {
+ textView.setTextColor(end);
+ }
+ }
+ }
+ return anim;
+ }
+}
diff --git a/core/java/android/view/transition/Rotate.java b/core/java/android/view/transition/Rotate.java
new file mode 100644
index 0000000..b42fbe5
--- /dev/null
+++ b/core/java/android/view/transition/Rotate.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2013 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.view.transition;
+
+import android.animation.Animator;
+import android.animation.ObjectAnimator;
+import android.view.View;
+import android.view.ViewGroup;
+
+/**
+ * This transition captures the rotation property of targets before and after
+ * the scene change and animates any changes.
+ */
+public class Rotate extends Transition {
+
+ private static final String PROPNAME_ROTATION = "android:rotate:rotation";
+
+ @Override
+ protected void captureValues(TransitionValues values, boolean start) {
+ values.values.put(PROPNAME_ROTATION, values.view.getRotation());
+ }
+
+ @Override
+ protected boolean prePlay(ViewGroup sceneRoot, TransitionValues startValues,
+ TransitionValues endValues) {
+ if (startValues == null || endValues == null) {
+ return false;
+ }
+ final View view = endValues.view;
+ float startRotation = (Float) startValues.values.get(PROPNAME_ROTATION);
+ float endRotation = (Float) endValues.values.get(PROPNAME_ROTATION);
+ if (startRotation != endRotation) {
+ view.setRotation(startRotation);
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ protected Animator play(ViewGroup sceneRoot, TransitionValues startValues,
+ TransitionValues endValues) {
+ if (startValues == null || endValues == null) {
+ return null;
+ }
+ final View view = endValues.view;
+ float startRotation = (Float) startValues.values.get(PROPNAME_ROTATION);
+ float endRotation = (Float) endValues.values.get(PROPNAME_ROTATION);
+ if (startRotation != endRotation) {
+ return ObjectAnimator.ofFloat(view, View.ROTATION,
+ startRotation, endRotation);
+ }
+ return null;
+ }
+}
diff --git a/core/java/android/view/transition/Scene.java b/core/java/android/view/transition/Scene.java
new file mode 100644
index 0000000..62cb9d3
--- /dev/null
+++ b/core/java/android/view/transition/Scene.java
@@ -0,0 +1,191 @@
+/*
+ * Copyright (C) 2013 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.view.transition;
+
+import android.content.Context;
+import android.view.LayoutInflater;
+import android.view.ViewGroup;
+
+/**
+ * A scene represents the collection of values that various properties in the
+ * View hierarchy will have when the scene is applied. A Scene can be
+ * configured to automatically run a Transition when it is applied, which will
+ * animate the various property changes that take place during the
+ * scene change.
+ */
+public final class Scene {
+
+ private Context mContext;
+ private int mLayoutId = -1;
+ private ViewGroup mSceneRoot;
+ private ViewGroup mLayout; // alternative to layoutId
+ Runnable mEnterAction, mExitAction;
+
+ /**
+ * Constructs a Scene with no information about how values will change
+ * when this scene is applied. This constructor might be used when
+ * a Scene is created with the intention of being dynamically configured,
+ * through setting {@link #setEnterAction(Runnable)} and possibly
+ * {@link #setExitAction(Runnable)}.
+ *
+ * @param sceneRoot The root of the hierarchy in which scene changes
+ * and transitions will take place.
+ */
+ public Scene(ViewGroup sceneRoot) {
+ mSceneRoot = sceneRoot;
+ }
+
+ /**
+ * Constructs a Scene which, when entered, will remove any
+ * children from the sceneRoot container and will inflate and add
+ * the hierarchy specified by the layoutId resource file.
+ *
+ * @param sceneRoot The root of the hierarchy in which scene changes
+ * and transitions will take place.
+ * @param layoutId The id of a resource file that defines the view
+ * hierarchy of this scene.
+ * @param context The context used in the process of inflating
+ * the layout resource.
+ */
+ public Scene(ViewGroup sceneRoot, int layoutId, Context context) {
+ mContext = context;
+ mSceneRoot = sceneRoot;
+ mLayoutId = layoutId;
+ }
+
+ /**
+ * Constructs a Scene which, when entered, will remove any
+ * children from the sceneRoot container and add the layout
+ * object as a new child of that container.
+ *
+ * @param sceneRoot The root of the hierarchy in which scene changes
+ * and transitions will take place.
+ * @param layout The view hiearrchy of this scene, added as a child
+ * of sceneRoot when this scene is entered.
+ */
+ public Scene(ViewGroup sceneRoot, ViewGroup layout) {
+ mSceneRoot = sceneRoot;
+ mLayout = layout;
+ }
+
+ /**
+ * Gets the root of the scene, which is the root of the view hierarchy
+ * affected by changes due to this scene, and which will be animated
+ * when this scene is entered.
+ *
+ * @return The root of the view hierarchy affected by this scene.
+ */
+ public ViewGroup getSceneRoot() {
+ return mSceneRoot;
+ }
+
+ /**
+ * Exits this scene, if it is the {@link ViewGroup#getCurrentScene()
+ * currentScene} on the scene's {@link #getSceneRoot() scene root}.
+ * Exiting a scene involves removing the layout added if the scene
+ * has either a layoutId or layout view group (set at construction
+ * time) and running the {@link #setExitAction(Runnable) exit action}
+ * if there is one.
+ */
+ public void exit() {
+ if (mSceneRoot.getCurrentScene() == this) {
+ if (mLayoutId >= 0 || mLayout != null) {
+ // Undo layout change caused by entering this scene
+ getSceneRoot().removeAllViews();
+ }
+ if (mExitAction != null) {
+ mExitAction.run();
+ }
+ }
+ }
+
+ /**
+ * Enters this scene, which entails changing all values that
+ * are specified by this scene. These may be values associated
+ * with a layout view group or layout resource file which will
+ * now be added to the scene root, or it may be values changed by
+ * an {@link #setEnterAction(Runnable)} enter action}, or a
+ * combination of the these. No transition will be run when the
+ * scene is entered. To get transition behavior in scene changes,
+ * use one of the methods in {@link TransitionManager} instead.
+ */
+ public void enter() {
+
+ // Apply layout change, if any
+ if (mLayoutId >= 0 || mLayout != null) {
+ // redundant with exit() action of previous scene, but must
+ // empty out that parent container before adding to it
+ getSceneRoot().removeAllViews();
+
+ if (mLayoutId >= 0) {
+ LayoutInflater.from(mContext).inflate(mLayoutId, mSceneRoot);
+ } else {
+ mSceneRoot.addView(mLayout);
+ }
+ }
+
+ // Notify next scene that it is entering. Subclasses may override to configure scene.
+ if (mEnterAction != null) {
+ mEnterAction.run();
+ }
+
+ mSceneRoot.setCurrentScene(this );
+ }
+
+ /**
+ * Scenes that are not defined with layout resources or
+ * hierarchies, or which need to perform additional steps
+ * after those hierarchies are changed to, should set an enter
+ * action, and possibly an exit action as well. An enter action
+ * will cause Scene to call back into application code to do
+ * anything else the application needs after transitions have
+ * captured pre-change values and after any other scene changes
+ * have been applied, such as the layout (if any) being added to
+ * the view hierarchy. After this method is called, Transitions will
+ * be played.
+ *
+ * @param action The runnable whose {@link Runnable#run() run()} method will
+ * be called when this scene is entered
+ * @see #setExitAction(Runnable)
+ * @see Scene#Scene(ViewGroup, int, Context)
+ * @see Scene#Scene(ViewGroup, ViewGroup)
+ */
+ public void setEnterAction(Runnable action) {
+ mEnterAction = action;
+ }
+
+ /**
+ * Scenes that are not defined with layout resources or
+ * hierarchies, or which need to perform additional steps
+ * after those hierarchies are changed to, should set an enter
+ * action, and possibly an exit action as well. An exit action
+ * will cause Scene to call back into application code to do
+ * anything the application needs to do after applicable transitions have
+ * captured pre-change values, but before any other scene changes
+ * have been applied, such as the new layout (if any) being added to
+ * the view hierarchy. After this method is called, the next scene
+ * will be entered, including a call to {@link #setEnterAction(Runnable)}
+ * if an enter action is set.
+ *
+ * @see #setEnterAction(Runnable)
+ * @see Scene#Scene(ViewGroup, int, Context)
+ * @see Scene#Scene(ViewGroup, ViewGroup)
+ */
+ public void setExitAction(Runnable action) {
+ mExitAction = action;
+ }
+
+} \ No newline at end of file
diff --git a/core/java/android/view/transition/Slide.java b/core/java/android/view/transition/Slide.java
new file mode 100644
index 0000000..8630ee2
--- /dev/null
+++ b/core/java/android/view/transition/Slide.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2013 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.view.transition;
+
+import android.animation.Animator;
+import android.animation.ObjectAnimator;
+import android.animation.TimeInterpolator;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.animation.AccelerateInterpolator;
+import android.view.animation.DecelerateInterpolator;
+
+/**
+ * This transition captures the visibility of target objects before and
+ * after a scene change and animates any changes by sliding the target
+ * objects into or out of place.
+ */
+public class Slide extends Visibility {
+
+ // TODO: Add parameter for sliding factor - it's hard-coded below
+
+ private static final TimeInterpolator sAccelerator = new AccelerateInterpolator();
+ private static final TimeInterpolator sDecelerator = new DecelerateInterpolator();
+
+ @Override
+ protected Animator appear(ViewGroup sceneRoot, View startView, int startVisibility,
+ View endView, int endVisibility) {
+ ObjectAnimator anim = ObjectAnimator.ofFloat(endView, View.TRANSLATION_Y,
+ -2 * endView.getHeight(), 0);
+ anim.setInterpolator(sDecelerator);
+ return anim;
+ }
+
+ @Override
+ protected boolean preAppear(ViewGroup sceneRoot, View startView, int startVisibility,
+ View endView, int endVisibility) {
+ endView.setTranslationY(-2 * endView.getHeight());
+ return true;
+ }
+
+ @Override
+ protected boolean preDisappear(ViewGroup sceneRoot, View startView, int startVisibility,
+ View endView, int endVisibility) {
+ startView.setTranslationY(0);
+ return true;
+ }
+
+ @Override
+ protected Animator disappear(ViewGroup sceneRoot, View startView, int startVisibility,
+ View endView, int endVisibility) {
+ ObjectAnimator anim = ObjectAnimator.ofFloat(startView, View.TRANSLATION_Y, 0,
+ -2 * startView.getHeight());
+ anim.setInterpolator(sAccelerator);
+ return anim;
+ }
+
+}
diff --git a/core/java/android/view/transition/TextChange.java b/core/java/android/view/transition/TextChange.java
new file mode 100644
index 0000000..0ba2412
--- /dev/null
+++ b/core/java/android/view/transition/TextChange.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2013 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.view.transition;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import java.util.HashMap;
+
+/**
+ * This transition tracks changes to the text in TextView targets. If the text
+ * changes between the start and end scenes, the transition ensures that the
+ * starting text stays until the transition ends, at which point it changes
+ * to the end text. This is useful in situations where you want to resize a
+ * text view to its new size before displaying the text that goes there.
+ */
+public class TextChange extends Transition {
+ private static final String PROPNAME_TEXT = "android:textchange:text";
+
+ // TODO: think about other options we could have here, like cross-fading the text, or fading
+ // it out/in. These could be parameters to supply to the constructors (and xml attributes).
+
+ @Override
+ protected void captureValues(TransitionValues values, boolean start) {
+ if (values.view instanceof TextView) {
+ TextView textview = (TextView) values.view;
+ values.values.put(PROPNAME_TEXT, textview.getText());
+ }
+ }
+
+ @Override
+ protected boolean prePlay(ViewGroup sceneRoot, TransitionValues startValues,
+ TransitionValues endValues) {
+ if (startValues == null || endValues == null || !(endValues.view instanceof TextView)) {
+ return false;
+ }
+ final TextView view = (TextView) endValues.view;
+ HashMap<String, Object> startVals = startValues.values;
+ HashMap<String, Object> endVals = endValues.values;
+ String startText = (String) startVals.get(PROPNAME_TEXT);
+ String endText = (String) endVals.get(PROPNAME_TEXT);
+ if (!startText.equals(endText)) {
+ view.setText(startText);
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ protected Animator play(ViewGroup sceneRoot, TransitionValues startValues,
+ TransitionValues endValues) {
+ if (startValues == null || endValues == null || !(endValues.view instanceof TextView)) {
+ return null;
+ }
+ final TextView view = (TextView) endValues.view;
+ HashMap<String, Object> startVals = startValues.values;
+ HashMap<String, Object> endVals = endValues.values;
+ final String startText = (String) startVals.get(PROPNAME_TEXT);
+ final String endText = (String) endVals.get(PROPNAME_TEXT);
+ if (!startText.equals(endText)) {
+ // This noop animation is just used to keep the text in its start state
+ // until the transition ends
+ ValueAnimator anim = ValueAnimator.ofFloat(0, 1);
+ anim.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ view.setText(endText);
+ }
+ });
+ return anim;
+ }
+ return null;
+ }
+}
diff --git a/core/java/android/view/transition/Transition.java b/core/java/android/view/transition/Transition.java
new file mode 100644
index 0000000..150c218
--- /dev/null
+++ b/core/java/android/view/transition/Transition.java
@@ -0,0 +1,911 @@
+/*
+ * Copyright (C) 2013 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.view.transition;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.TimeInterpolator;
+import android.util.LongSparseArray;
+import android.util.SparseArray;
+import android.view.SurfaceView;
+import android.view.TextureView;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewOverlay;
+import android.widget.ListView;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+
+/**
+ * A Transition holds information about animations that will be run on its
+ * targets during a scene change. Subclasses of this abstract class may
+ * choreograph several child transitions ({@link TransitionGroup} or they may
+ * perform custom animations themselves. Any Transition has two main jobs:
+ * (1) capture property values, and (2) play animations based on changes to
+ * captured property values. A custom transition knows what property values
+ * on View objects are of interest to it, and also knows how to animate
+ * changes to those values. For example, the {@link Fade} transition tracks
+ * changes to visibility-related properties and is able to construct and run
+ * animations that fade items in or out based on changes to those properties.
+ *
+ * <p>Note: Transitions may not work correctly with either {@link SurfaceView}
+ * or {@link TextureView}, due to the way that these views are displayed
+ * on the screen. For SurfaceView, the problem is that the view is updated from
+ * a non-UI thread, so changes to the view due to transitions (such as moving
+ * and resizing the view) may be out of sync with the display inside those bounds.
+ * TextureView is more compatible with transitions in general, but some
+ * specific transitions (such as {@link Crossfade}) may not be compatible
+ * with TextureView because they rely on {@link ViewOverlay} functionality,
+ * which does not currently work with TextureView.</p>
+ */
+public abstract class Transition {
+
+ private static final String LOG_TAG = "Transition";
+ static final boolean DBG = false;
+
+ long mStartDelay = -1;
+ long mDuration = -1;
+ TimeInterpolator mInterpolator = null;
+ int[] mTargetIds;
+ View[] mTargets;
+ // TODO: sparse arrays instead of hashmaps?
+ private HashMap<View, TransitionValues> mStartValues =
+ new HashMap<View, TransitionValues>();
+ private SparseArray<TransitionValues> mStartIdValues = new SparseArray<TransitionValues>();
+ private LongSparseArray<TransitionValues> mStartItemIdValues =
+ new LongSparseArray<TransitionValues>();
+ private HashMap<View, TransitionValues> mEndValues =
+ new HashMap<View, TransitionValues>();
+ private SparseArray<TransitionValues> mEndIdValues = new SparseArray<TransitionValues>();
+ private LongSparseArray<TransitionValues> mEndItemIdValues =
+ new LongSparseArray<TransitionValues>();
+
+ // Used to carry data between preplay() and play(), cleared before every scene transition
+ private ArrayList<TransitionValues> mPlayStartValuesList = new ArrayList<TransitionValues>();
+ private ArrayList<TransitionValues> mPlayEndValuesList = new ArrayList<TransitionValues>();
+
+ // Number of per-target instances of this Transition currently running. This count is
+ // determined by calls to startTransition() and endTransition()
+ int mNumInstances = 0;
+
+
+ /**
+ * The set of listeners to be sent transition lifecycle events.
+ */
+ ArrayList<TransitionListener> mListeners = null;
+
+ /**
+ * Constructs a Transition object with no target objects. A transition with
+ * no targets defaults to running on all target objects in the scene hierarchy
+ * (if the transition is not contained in a TransitionGroup), or all target
+ * objects passed down from its parent (if it is in a TransitionGroup).
+ */
+ public Transition() {}
+
+ /**
+ * Sets the duration of this transition. By default, there is no duration
+ * (indicated by a negative number), which means that the Animator created by
+ * the transition will have its own specified duration. If the duration of a
+ * Transition is set, that duration will override the Animator duration.
+ *
+ * @param duration The length of the animation, in milliseconds.
+ * @return This transition object.
+ */
+ public Transition setDuration(long duration) {
+ mDuration = duration;
+ return this;
+ }
+
+ public long getDuration() {
+ return mDuration;
+ }
+
+ /**
+ * Sets the startDelay of this transition. By default, there is no delay
+ * (indicated by a negative number), which means that the Animator created by
+ * the transition will have its own specified startDelay. If the delay of a
+ * Transition is set, that delay will override the Animator delay.
+ *
+ * @param startDelay The length of the delay, in milliseconds.
+ */
+ public void setStartDelay(long startDelay) {
+ mStartDelay = startDelay;
+ }
+
+ public long getStartDelay() {
+ return mStartDelay;
+ }
+
+ /**
+ * Sets the interpolator of this transition. By default, the interpolator
+ * is null, which means that the Animator created by the transition
+ * will have its own specified interpolator. If the interpolator of a
+ * Transition is set, that interpolator will override the Animator interpolator.
+ *
+ * @param interpolator The time interpolator used by the transition
+ */
+ public void setInterpolator(TimeInterpolator interpolator) {
+ mInterpolator = interpolator;
+ }
+
+ public TimeInterpolator getInterpolator() {
+ return mInterpolator;
+ }
+
+ /**
+ * This method is called by the transition's parent (all the way up to the
+ * topmost Transition in the hierarchy) with the sceneRoot and start/end
+ * values that the transition may need to run animations on its target
+ * views. The method is called for every applicable target object, which
+ * is stored in the {@link TransitionValues#view} field. When the method
+ * results in an animation needing to be run, the transition will construct
+ * the appropriate {@link Animator} object and return it. The transition
+ * mechanism will apply any applicable duration, startDelay, and interpolator
+ * to that animation and start it. Returning null from the method tells the
+ * transition engine that there is no animation to be played (TransitionGroup
+ * will return null because any applicable animations were started on its child
+ * transitions already and there is no animation to be run on the group itself).
+ *
+ * @param sceneRoot
+ * @param startValues
+ * @param endValues
+ * @return Animator The animation to run.
+ */
+ protected abstract Animator play(ViewGroup sceneRoot, TransitionValues startValues,
+ TransitionValues endValues);
+
+ /**
+ * This method is called by the transition's parent (all the way up to the
+ * topmost Transition in the hierarchy) with the sceneRoot and start/end
+ * values that the transition may need to set things up at the start of a
+ * Transition. For example, if an overall Transition consists of several
+ * child transitions in sequence, then some of the child transitions may
+ * want to set initial values on target views prior to the overall
+ * Transition commencing, to put them in an appropriate scene for the
+ * delay between that start and the child Transition start time. For
+ * example, a transition that fades an item in may wish to set the starting
+ * alpha value to 0, to avoid it blinking in prior to the transition
+ * actually starting the animation. This is necessary because the scene
+ * change that triggers the Transition will automatically set the end-scene
+ * on all target views, so a Transition that wants to animate from a
+ * different value should set that value in the preplay() method.
+ *
+ * <p>Additionally, a Transition can perform logic to determine whether
+ * the transition needs to run on the given target and start/end values.
+ * For example, a transition that resizes objects on the screen may wish
+ * to avoid running for views which are not present in either the start
+ * or end scenes. A return value of <code>false</code> indicates that
+ * the transition should not run, and there will be no ensuing call to the
+ * {@link #play(ViewGroup, TransitionValues, TransitionValues)} method during
+ * this scene change. The default implementation returns true.</p>
+ *
+ * <p>The method is called for every applicable target object, which is
+ * stored in the {@link TransitionValues#view} field.</p>
+ *
+ * @param sceneRoot
+ * @param startValues
+ * @param endValues
+ * @return True if the Transition's {@link #play(ViewGroup,
+ * TransitionValues, TransitionValues) play()} method should be called
+ * during this scene change, false otherwise.
+ */
+ protected boolean prePlay(ViewGroup sceneRoot, TransitionValues startValues,
+ TransitionValues endValues) {
+ return true;
+ }
+
+ /**
+ * This version of prePlay() is called with the entire set of start/end
+ * values. The implementation in Transition iterates through these lists
+ * and calls {@link #prePlay(ViewGroup, TransitionValues, TransitionValues)}
+ * with each set of start/end values on this transition. The
+ * TransitionGroup subclass overrides this method and delegates it to
+ * each of its children in succession. The intention in splitting
+ * preplay() out from play() is to allow all Transitions in the tree to
+ * set up the appropriate start scene for their target objects prior to
+ * any calls to play(), which is necessary when there is a sequential
+ * Transition, where a child transition which is not the first may want to
+ * set up a target's scene prior to the overall Transition start.
+ *
+ * @hide
+ */
+ protected void prePlay(ViewGroup sceneRoot, HashMap<View, TransitionValues> startValues,
+ SparseArray<TransitionValues> startIdValues,
+ LongSparseArray<TransitionValues> startItemIdValues,
+ HashMap<View, TransitionValues> endValues,
+ SparseArray<TransitionValues> endIdValues,
+ LongSparseArray<TransitionValues> endItemIdValues) {
+ mPlayStartValuesList.clear();
+ mPlayEndValuesList.clear();
+ HashMap<View, TransitionValues> endCopy = new HashMap<View, TransitionValues>(endValues);
+ SparseArray<TransitionValues> endIdCopy =
+ new SparseArray<TransitionValues>(endIdValues.size());
+ for (int i = 0; i < endIdValues.size(); ++i) {
+ int id = endIdValues.keyAt(i);
+ endIdCopy.put(id, endIdValues.valueAt(i));
+ }
+ LongSparseArray<TransitionValues> endItemIdCopy =
+ new LongSparseArray<TransitionValues>(endItemIdValues.size());
+ for (int i = 0; i < endItemIdValues.size(); ++i) {
+ long id = endItemIdValues.keyAt(i);
+ endItemIdCopy.put(id, endItemIdValues.valueAt(i));
+ }
+ // Walk through the start values, playing everything we find
+ // Remove from the end set as we go
+ ArrayList<TransitionValues> startValuesList = new ArrayList<TransitionValues>();
+ ArrayList<TransitionValues> endValuesList = new ArrayList<TransitionValues>();
+ for (View view : startValues.keySet()) {
+ TransitionValues start = null;
+ TransitionValues end = null;
+ boolean isInListView = false;
+ if (view.getParent() instanceof ListView) {
+ isInListView = true;
+ }
+ if (!isInListView) {
+ int id = view.getId();
+ start = startValues.get(view) != null ?
+ startValues.get(view) : startIdValues.get(id);
+ if (endValues.get(view) != null) {
+ end = endValues.get(view);
+ endCopy.remove(view);
+ } else {
+ end = endIdValues.get(id);
+ View removeView = null;
+ for (View viewToRemove : endCopy.keySet()) {
+ if (viewToRemove.getId() == id) {
+ removeView = viewToRemove;
+ }
+ }
+ if (removeView != null) {
+ endCopy.remove(removeView);
+ }
+ }
+ endIdCopy.remove(id);
+ if (isValidTarget(view, id)) {
+ startValuesList.add(start);
+ endValuesList.add(end);
+ }
+ } else {
+ ListView parent = (ListView) view.getParent();
+ if (parent.getAdapter().hasStableIds()) {
+ int position = parent.getPositionForView(view);
+ long itemId = parent.getItemIdAtPosition(position);
+ start = startItemIdValues.get(itemId);
+ endItemIdCopy.remove(itemId);
+ // TODO: deal with targetIDs for itemIDs for ListView items
+ startValuesList.add(start);
+ endValuesList.add(end);
+ }
+ }
+ }
+ int startItemIdCopySize = startItemIdValues.size();
+ for (int i = 0; i < startItemIdCopySize; ++i) {
+ long id = startItemIdValues.keyAt(i);
+ if (isValidTarget(null, id)) {
+ TransitionValues start = startItemIdValues.get(id);
+ TransitionValues end = endItemIdValues.get(id);
+ endItemIdCopy.remove(id);
+ startValuesList.add(start);
+ endValuesList.add(end);
+ }
+ }
+ // Now walk through the remains of the end set
+ for (View view : endCopy.keySet()) {
+ int id = view.getId();
+ if (isValidTarget(view, id)) {
+ TransitionValues start = startValues.get(view) != null ?
+ startValues.get(view) : startIdValues.get(id);
+ TransitionValues end = endCopy.get(view);
+ endIdCopy.remove(id);
+ startValuesList.add(start);
+ endValuesList.add(end);
+ }
+ }
+ int endIdCopySize = endIdCopy.size();
+ for (int i = 0; i < endIdCopySize; ++i) {
+ int id = endIdCopy.keyAt(i);
+ if (isValidTarget(null, id)) {
+ TransitionValues start = startIdValues.get(id);
+ TransitionValues end = endIdCopy.get(id);
+ startValuesList.add(start);
+ endValuesList.add(end);
+ }
+ }
+ int endItemIdCopySize = endItemIdCopy.size();
+ for (int i = 0; i < endItemIdCopySize; ++i) {
+ long id = endItemIdCopy.keyAt(i);
+ // TODO: Deal with targetIDs and itemIDs
+ TransitionValues start = startItemIdValues.get(id);
+ TransitionValues end = endItemIdCopy.get(id);
+ startValuesList.add(start);
+ endValuesList.add(end);
+ }
+ for (int i = 0; i < startValuesList.size(); ++i) {
+ TransitionValues start = startValuesList.get(i);
+ TransitionValues end = endValuesList.get(i);
+ // TODO: what to do about targetIds and itemIds?
+ if (prePlay(sceneRoot, start, end)) {
+ // Note: we've already done the check against targetIDs in these lists
+ mPlayStartValuesList.add(start);
+ mPlayEndValuesList.add(end);
+ }
+ }
+ }
+
+ /**
+ * Internal utility method for checking whether a given view/id
+ * is valid for this transition, where "valid" means that either
+ * the Transition has no target/targetId list (the default, in which
+ * cause the transition should act on all views in the hiearchy), or
+ * the given view is in the target list or the view id is in the
+ * targetId list. If the target parameter is null, then the target list
+ * is not checked (this is in the case of ListView items, where the
+ * views are ignored and only the ids are used).
+ */
+ boolean isValidTarget(View target, long targetId) {
+ if (mTargetIds == null && mTargets == null) {
+ return true;
+ }
+ if (mTargetIds != null) {
+ for (int i = 0; i < mTargetIds.length; ++i) {
+ if (mTargetIds[i] == targetId) {
+ return true;
+ }
+ }
+ }
+ if (target != null && mTargets != null) {
+ for (int i = 0; i < mTargets.length; ++i) {
+ if (mTargets[i] == target) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * This version of play() is called with the entire set of start/end
+ * values. The implementation in Transition iterates through these lists
+ * and calls {@link #play(ViewGroup, TransitionValues, TransitionValues)}
+ * with each set of start/end values on this transition. The
+ * TransitionGroup subclass overrides this method and delegates it to
+ * each of its children in succession.
+ *
+ * @hide
+ */
+ protected void play(ViewGroup sceneRoot,
+ final HashMap<View, TransitionValues> startValues,
+ final SparseArray<TransitionValues> startIdValues,
+ final LongSparseArray<TransitionValues> startItemIdValues,
+ final HashMap<View, TransitionValues> endValues,
+ final SparseArray<TransitionValues> endIdValues,
+ final LongSparseArray<TransitionValues> endItemIdValues) {
+
+ startTransition();
+ // Now walk the list of TransitionValues, calling play for each pair
+ for (int i = 0; i < mPlayStartValuesList.size(); ++i) {
+ TransitionValues start = mPlayStartValuesList.get(i);
+ TransitionValues end = mPlayEndValuesList.get(i);
+ startTransition();
+ animate(play(sceneRoot, start, end));
+ }
+ mPlayStartValuesList.clear();
+ mPlayEndValuesList.clear();
+ endTransition();
+ }
+
+ /**
+ * Captures the current scene of values for the properties that this
+ * transition monitors. These values can be either the start or end
+ * values used in a subsequent call to
+ * {@link #play(ViewGroup, TransitionValues, TransitionValues)}, as indicated by
+ * <code>start</code>. The main concern for an implementation is what the
+ * properties are that the transition cares about and what the values are
+ * for all of those properties. The start and end values will be compared
+ * later during the preplay and play() methods to determine what, if any,
+ * animations, should be run.
+ *
+ * @param transitionValues The holder any values that the Transition
+ * wishes to store. Values are stored in the fields of this
+ * TransitionValues object, according to their type, and are keyed from
+ * a String value. For example, to start a view's rotation value,
+ * a Transition might call
+ * <code>transitionValues.floatValues.put("rotation", view.getRotation())
+ * </code>. The target <code>View</code> will already be stored in
+ * the transitionValues structure when this method is called. The other
+ * fields in TransitionValues, e.g. <code>floatValues</code>,
+ * may need to be instantiated if they have not yet been created.
+ */
+ protected abstract void captureValues(TransitionValues transitionValues, boolean start);
+
+ /**
+ * Sets the ids of target views that this Transition is interested in
+ * animating. By default, there are no targetIds, and a Transition will
+ * listen for changes on every view in the hierarchy below the sceneRoot
+ * of the Scene being transitioned into. Setting targetIDs constrains
+ * the Transition to only listen for, and act on, views with these IDs.
+ * Views with different IDs, or no IDs whatsoever, will be ignored.
+ *
+ * @see View#getId()
+ * @param targetIds A list of IDs which specify the set of Views on which
+ * the Transition will act.
+ * @return Transition The Transition on which the targetIds have been set.
+ * Returning the same object makes it easier to chain calls during
+ * construction, such as
+ * <code>transitionGroup.addTransitions(new Fade()).setTargetIds(someId);</code>
+ */
+ public Transition setTargetIds(int... targetIds) {
+ int numTargets = targetIds.length;
+ mTargetIds = new int[numTargets];
+ System.arraycopy(targetIds, 0, mTargetIds, 0, numTargets);
+ return this;
+ }
+
+ /**
+ * Sets the target view instances that this Transition is interested in
+ * animating. By default, there are no targets, and a Transition will
+ * listen for changes on every view in the hierarchy below the sceneRoot
+ * of the Scene being transitioned into. Setting targets constrains
+ * the Transition to only listen for, and act on, these views.
+ * All other views will be ignored.
+ *
+ * <p>The target list is like the {@link #setTargetIds(int...) targetId}
+ * list except this list specifies the actual View instances, not the ids
+ * of the views. This is an important distinction when scene changes involve
+ * view hierarchies which have been inflated separately; different views may
+ * share the same id but not actually be the same instance. If the transition
+ * should treat those views as the same, then seTargetIds() should be used
+ * instead of setTargets(). If, on the other hand, scene changes involve
+ * changes all within the same view hierarchy, among views which do not
+ * necessary have ids set on them, then the target list may be more
+ * convenient.</p>
+ *
+ * @see #setTargetIds(int...)
+ * @param targets A list of Views on which the Transition will act.
+ * @return Transition The Transition on which the targets have been set.
+ * Returning the same object makes it easier to chain calls during
+ * construction, such as
+ * <code>transitionGroup.addTransitions(new Fade()).setTargets(someView);</code>
+ */
+ public Transition setTargets(View... targets) {
+ int numTargets = targets.length;
+ mTargets = new View[numTargets];
+ System.arraycopy(targets, 0, mTargets, 0, numTargets);
+ return this;
+ }
+
+ /**
+ * Returns the array of target IDs that this transition limits itself to
+ * tracking and animating. If the array is null for both this method and
+ * {@link #getTargets()}, then this transition is
+ * not limited to specific views, and will handle changes to any views
+ * in the hierarchy of a scene change.
+ *
+ * @return the list of target IDs
+ */
+ public int[] getTargetIds() {
+ return mTargetIds;
+ }
+
+ /**
+ * Returns the array of target views that this transition limits itself to
+ * tracking and animating. If the array is null for both this method and
+ * {@link #getTargetIds()}, then this transition is
+ * not limited to specific views, and will handle changes to any views
+ * in the hierarchy of a scene change.
+ *
+ * @return the list of target views
+ */
+ public View[] getTargets() {
+ return mTargets;
+ }
+
+ /**
+ * Recursive method that captures values for the given view and the
+ * hierarchy underneath it.
+ * @param sceneRoot The root of the view hierarchy being captured
+ * @param start true if this capture is happening before the scene change,
+ * false otherwise
+ */
+ void captureValues(ViewGroup sceneRoot, boolean start) {
+ if (mTargetIds != null && mTargetIds.length > 0 ||
+ mTargets != null && mTargets.length > 0) {
+ if (mTargetIds != null) {
+ for (int i = 0; i < mTargetIds.length; ++i) {
+ int id = mTargetIds[i];
+ View view = sceneRoot.findViewById(id);
+ if (view != null) {
+ TransitionValues values = new TransitionValues();
+ values.view = view;
+ captureValues(values, start);
+ if (start) {
+ mStartValues.put(view, values);
+ mStartIdValues.put(id, values);
+ } else {
+ mEndValues.put(view, values);
+ mEndIdValues.put(id, values);
+ }
+ }
+ }
+ }
+ if (mTargets != null) {
+ for (int i = 0; i < mTargets.length; ++i) {
+ View view = mTargets[i];
+ if (view != null) {
+ TransitionValues values = new TransitionValues();
+ values.view = view;
+ captureValues(values, start);
+ if (start) {
+ mStartValues.put(view, values);
+ } else {
+ mEndValues.put(view, values);
+ }
+ }
+ }
+ }
+ } else {
+ captureHierarchy(sceneRoot, start);
+ }
+ }
+
+ /**
+ * Recursive method which captures values for an entire view hierarchy,
+ * starting at some root view. Transitions without targetIDs will use this
+ * method to capture values for all possible views.
+ *
+ * @param view The view for which to capture values. Children of this View
+ * will also be captured, recursively down to the leaf nodes.
+ * @param start true if values are being captured in the start scene, false
+ * otherwise.
+ */
+ private void captureHierarchy(View view, boolean start) {
+ if (view == null) {
+ return;
+ }
+ boolean isListViewItem = false;
+ if (view.getParent() instanceof ListView) {
+ isListViewItem = true;
+ }
+ if (isListViewItem && !((ListView) view.getParent()).getAdapter().hasStableIds()) {
+ // ignore listview children unless we can track them with stable IDs
+ return;
+ }
+ long id;
+ if (!isListViewItem) {
+ id = view.getId();
+ } else {
+ ListView listview = (ListView) view.getParent();
+ int position = listview.getPositionForView(view);
+ id = listview.getItemIdAtPosition(position);
+ view.setHasTransientState(true);
+ }
+ TransitionValues values = new TransitionValues();
+ values.view = view;
+ captureValues(values, start);
+ if (start) {
+ if (!isListViewItem) {
+ mStartValues.put(view, values);
+ mStartIdValues.put((int) id, values);
+ } else {
+ mStartItemIdValues.put(id, values);
+ }
+ } else {
+ if (!isListViewItem) {
+ mEndValues.put(view, values);
+ mEndIdValues.put((int) id, values);
+ } else {
+ mEndItemIdValues.put(id, values);
+ }
+ }
+ if (view instanceof ViewGroup) {
+ ViewGroup parent = (ViewGroup) view;
+ for (int i = 0; i < parent.getChildCount(); ++i) {
+ captureHierarchy(parent.getChildAt(i), start);
+ }
+ }
+ }
+
+ /**
+ * Called by TransitionManager to play the transition. This calls
+ * prePlay() and then play() with the full set of per-view
+ * transitionValues objects
+ */
+ void play(ViewGroup sceneRoot) {
+ // prePlay() must be called on entire transition hierarchy and set of views
+ // before calling play() on anything; every transition needs a chance to set up
+ // target views appropriately before transitions begin running
+ prePlay(sceneRoot, mStartValues, mStartIdValues, mStartItemIdValues,
+ mEndValues, mEndIdValues, mEndItemIdValues);
+ play(sceneRoot, mStartValues, mStartIdValues, mStartItemIdValues,
+ mEndValues, mEndIdValues, mEndItemIdValues);
+ }
+
+ /**
+ * This is a utility method used by subclasses to handle standard parts of
+ * setting up and running an Animator: it sets the {@link #getDuration()
+ * duration} and the {@link #getStartDelay() startDelay}, starts the
+ * animation, and, when the animator ends, calls {@link #endTransition()}.
+ *
+ * @param animator The Animator to be run during this transition.
+ *
+ * @hide
+ */
+ protected void animate(Animator animator) {
+ // TODO: maybe pass auto-end as a boolean parameter?
+ if (animator == null) {
+ endTransition();
+ } else {
+ if (getDuration() >= 0) {
+ animator.setDuration(getDuration());
+ }
+ if (getStartDelay() >= 0) {
+ animator.setStartDelay(getStartDelay());
+ }
+ if (getInterpolator() != null) {
+ animator.setInterpolator(getInterpolator());
+ }
+ animator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ cancelTransition();
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ endTransition();
+ animation.removeListener(this);
+ }
+ });
+ animator.start();
+ }
+ }
+
+ /**
+ * Subclasses may override to receive notice of when the transition starts.
+ * This is equivalent to listening for the
+ * {@link TransitionListener#onTransitionStart(Transition)} callback.
+ */
+ protected void onTransitionStart() {
+ }
+
+ /**
+ * Subclasses may override to receive notice of when the transition is
+ * canceled. This is equivalent to listening for the
+ * {@link TransitionListener#onTransitionCancel(Transition)} callback.
+ */
+ protected void onTransitionCancel() {
+ }
+
+ /**
+ * Subclasses may override to receive notice of when the transition ends.
+ * This is equivalent to listening for the
+ * {@link TransitionListener#onTransitionEnd(Transition)} callback.
+ */
+ protected void onTransitionEnd() {
+ }
+
+ /**
+ * This method is called automatically by the transition and
+ * TransitionGroup classes prior to a Transition subclass starting;
+ * subclasses should not need to call it directly.
+ *
+ * @hide
+ */
+ protected void startTransition() {
+ if (mNumInstances == 0) {
+ onTransitionStart();
+ if (mListeners != null && mListeners.size() > 0) {
+ ArrayList<TransitionListener> tmpListeners =
+ (ArrayList<TransitionListener>) mListeners.clone();
+ int numListeners = tmpListeners.size();
+ for (int i = 0; i < numListeners; ++i) {
+ tmpListeners.get(i).onTransitionStart(this);
+ }
+ }
+ }
+ mNumInstances++;
+ }
+
+ /**
+ * This method is called automatically by the Transition and
+ * TransitionGroup classes when a transition finishes, either because
+ * a transition did nothing (returned a null Animator from
+ * {@link Transition#play(ViewGroup, TransitionValues,
+ * TransitionValues)}) or because the transition returned a valid
+ * Animator and endTransition() was called in the onAnimationEnd()
+ * callback of the AnimatorListener.
+ *
+ * @hide
+ */
+ protected void endTransition() {
+ --mNumInstances;
+ if (mNumInstances == 0) {
+ onTransitionEnd();
+ if (mListeners != null && mListeners.size() > 0) {
+ ArrayList<TransitionListener> tmpListeners =
+ (ArrayList<TransitionListener>) mListeners.clone();
+ int numListeners = tmpListeners.size();
+ for (int i = 0; i < numListeners; ++i) {
+ tmpListeners.get(i).onTransitionEnd(this);
+ }
+ }
+ for (int i = 0; i < mStartItemIdValues.size(); ++i) {
+ TransitionValues tv = mStartItemIdValues.valueAt(i);
+ View v = tv.view;
+ if (v.hasTransientState()) {
+ v.setHasTransientState(false);
+ }
+ }
+ for (int i = 0; i < mEndItemIdValues.size(); ++i) {
+ TransitionValues tv = mEndItemIdValues.valueAt(i);
+ View v = tv.view;
+ if (v.hasTransientState()) {
+ v.setHasTransientState(false);
+ }
+ }
+ mStartValues.clear();
+ mStartIdValues.clear();
+ mStartItemIdValues.clear();
+ mEndValues.clear();
+ mEndIdValues.clear();
+ mEndItemIdValues.clear();
+ }
+ }
+
+ /**
+ * This method cancels a transition that is currently running.
+ * Implementation TBD.
+ */
+ protected void cancelTransition() {
+ // TODO: how does this work with instances?
+ // TODO: this doesn't actually do *anything* yet
+ onTransitionCancel();
+ if (mListeners != null && mListeners.size() > 0) {
+ ArrayList<TransitionListener> tmpListeners =
+ (ArrayList<TransitionListener>) mListeners.clone();
+ int numListeners = tmpListeners.size();
+ for (int i = 0; i < numListeners; ++i) {
+ tmpListeners.get(i).onTransitionCancel(this);
+ }
+ }
+ }
+
+ /**
+ * Adds a listener to the set of listeners that are sent events through the
+ * life of an animation, such as start, repeat, and end.
+ *
+ * @param listener the listener to be added to the current set of listeners
+ * for this animation.
+ */
+ public void addListener(TransitionListener listener) {
+ if (mListeners == null) {
+ mListeners = new ArrayList<TransitionListener>();
+ }
+ mListeners.add(listener);
+ }
+
+ /**
+ * Removes a listener from the set listening to this animation.
+ *
+ * @param listener the listener to be removed from the current set of
+ * listeners for this transition.
+ */
+ public void removeListener(TransitionListener listener) {
+ if (mListeners == null) {
+ return;
+ }
+ mListeners.remove(listener);
+ if (mListeners.size() == 0) {
+ mListeners = null;
+ }
+ }
+
+ /**
+ * Gets the set of {@link TransitionListener} objects that are currently
+ * listening for events on this <code>Transition</code> object.
+ *
+ * @return ArrayList<TransitionListener> The set of listeners.
+ */
+ public ArrayList<TransitionListener> getListeners() {
+ return mListeners;
+ }
+
+ @Override
+ public String toString() {
+ return toString("");
+ }
+
+ String toString(String indent) {
+ String result = indent + getClass().getSimpleName() + "@" +
+ Integer.toHexString(hashCode()) + ": ";
+ result += "dur(" + mDuration + ") ";
+ result += "dly(" + mStartDelay + ") ";
+ result += "interp(" + mInterpolator + ") ";
+ result += "tgts(";
+ if (mTargetIds != null) {
+ for (int i = 0; i < mTargetIds.length; ++i) {
+ if (i > 0) {
+ result += ", ";
+ }
+ result += mTargetIds[i];
+ }
+ }
+ if (mTargets != null) {
+ for (int i = 0; i < mTargets.length; ++i) {
+ if (i > 0) {
+ result += ", ";
+ }
+ result += mTargets[i];
+ }
+ }
+ result += ")";
+ return result;
+ }
+
+ /**
+ * A transition listener receives notifications from a transition.
+ * Notifications indicate transition lifecycle events: when the transition
+ * begins, ends, or is canceled.
+ */
+ public static interface TransitionListener {
+ /**
+ * Notification about the start of the transition.
+ *
+ * @param transition The started transition.
+ */
+ void onTransitionStart(Transition transition);
+
+ /**
+ * Notification about the end of the transition. Canceled transitions
+ * will always notify listeners of both the cancellation and end
+ * events. That is, {@link #onTransitionEnd()} is always called,
+ * regardless of whether the transition was canceled or played
+ * through to completion.
+ *
+ * @param transition The transition which reached its end.
+ */
+ void onTransitionEnd(Transition transition);
+
+ /**
+ * Notification about the cancellation of the transition.
+ *
+ * @param transition The transition which was canceled.
+ */
+ void onTransitionCancel(Transition transition);
+ }
+
+ /**
+ * Utility adapter class to avoid having to override all three methods
+ * whenever someone just wants to listen for a single event.
+ *
+ * @hide
+ * */
+ public static class TransitionListenerAdapter implements TransitionListener {
+ @Override
+ public void onTransitionStart(Transition transition) {
+ }
+
+ @Override
+ public void onTransitionEnd(Transition transition) {
+ }
+
+ @Override
+ public void onTransitionCancel(Transition transition) {
+ }
+ }
+
+}
diff --git a/core/java/android/view/transition/TransitionGroup.java b/core/java/android/view/transition/TransitionGroup.java
new file mode 100644
index 0000000..363872a
--- /dev/null
+++ b/core/java/android/view/transition/TransitionGroup.java
@@ -0,0 +1,292 @@
+/*
+ * Copyright (C) 2013 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.view.transition;
+
+import android.animation.Animator;
+import android.util.AndroidRuntimeException;
+import android.util.LongSparseArray;
+import android.util.SparseArray;
+import android.view.View;
+import android.view.ViewGroup;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+
+/**
+ * A TransitionGroup is a parent of child transitions (including other
+ * TransitionGroups). Using TransitionGroups enables more complex
+ * choreography of transitions, where some groups play {@link #TOGETHER} and
+ * others play {@link #SEQUENTIALLY}. For example, {@link AutoTransition}
+ * uses a TransitionGroup to sequentially play a Fade(Fade.OUT), followed by
+ * a {@link Move}, followed by a Fade(Fade.OUT) transition.
+ */
+public class TransitionGroup extends Transition {
+
+ ArrayList<Transition> mTransitions = new ArrayList<Transition>();
+ private boolean mPlayTogether = true;
+ int mCurrentListeners;
+ boolean mStarted = false;
+
+ /**
+ * A flag used to indicate that the child transitions of this group
+ * should all start at the same time.
+ */
+ public static final int TOGETHER = 0;
+ /**
+ * A flag used to indicate that the child transitions of this group should
+ * play in sequence; when one child transition ends, the next child
+ * transition begins. Note that a transition does not end until all
+ * instances of it (which are playing on all applicable targets of the
+ * transition) end.
+ */
+ public static final int SEQUENTIALLY = 1;
+
+ /**
+ * Constructs an empty transition group. Add child transitions to the
+ * group by calling to {@link #addTransitions(Transition...)} )}. By default,
+ * child transitions will play {@link #TOGETHER}.
+ */
+ public TransitionGroup() {
+ }
+
+ /**
+ * Constructs an empty transition group with the specified ordering.
+ *
+ * @param ordering {@link #TOGETHER} to start this group's child
+ * transitions together, {@link #SEQUENTIALLY} to play the child
+ * transitions in sequence.
+ * @see #setOrdering(int)
+ */
+ public TransitionGroup(int ordering) {
+ setOrdering(ordering);
+ }
+
+ /**
+ * Sets the play order of this group's child transitions.
+ *
+ * @param ordering {@link #TOGETHER} to start this group's child
+ * transitions together, {@link #SEQUENTIALLY} to play the child
+ * transitions in sequence.
+ */
+ public void setOrdering(int ordering) {
+ switch (ordering) {
+ case SEQUENTIALLY:
+ mPlayTogether = false;
+ break;
+ case TOGETHER:
+ mPlayTogether = true;
+ break;
+ default:
+ throw new AndroidRuntimeException("Invalid parameter for TransitionGroup " +
+ "ordering: " + ordering);
+ }
+ }
+
+ /**
+ * Adds child transitions to this group. The order of the child transitions
+ * passed in determines the order in which they are started.
+ *
+ * @param transitions A list of child transition to be added to this group.
+ */
+ public void addTransitions(Transition... transitions) {
+ if (transitions != null) {
+ int numTransitions = transitions.length;
+ for (int i = 0; i < numTransitions; ++i) {
+ mTransitions.add(transitions[i]);
+ }
+ }
+ }
+
+ /**
+ * Removes the specified child transition from this group.
+ *
+ * @param transition The transition to be removed.
+ */
+ public void removeTransition(Transition transition) {
+ mTransitions.remove(transition);
+ }
+
+ /**
+ * Sets up listeners for each of the child transitions. This is used to
+ * determine when this transition group is finished (all child transitions
+ * must finish first).
+ */
+ private void setupStartEndListeners() {
+ for (Transition childTransition : mTransitions) {
+ childTransition.addListener(mListener);
+ }
+ mCurrentListeners = mTransitions.size();
+ }
+
+ /**
+ * This listener is used to detect when all child transitions are done, at
+ * which point this transition group is also done.
+ */
+ private TransitionListener mListener = new TransitionListenerAdapter() {
+ @Override
+ public void onTransitionStart(Transition transition) {
+ if (!mStarted) {
+ startTransition();
+ mStarted = true;
+ }
+ }
+
+ @Override
+ public void onTransitionEnd(Transition transition) {
+ --mCurrentListeners;
+ if (mCurrentListeners == 0) {
+ // All child trans
+ mStarted = false;
+ endTransition();
+ }
+ transition.removeListener(this);
+ }
+ };
+
+ /**
+ * @hide
+ */
+ @Override
+ protected void prePlay(ViewGroup sceneRoot,
+ HashMap<View, TransitionValues> startValues,
+ SparseArray<TransitionValues> startIdValues,
+ LongSparseArray<TransitionValues> startItemIdValues,
+ HashMap<View, TransitionValues> endValues,
+ SparseArray<TransitionValues> endIdValues,
+ LongSparseArray<TransitionValues> endItemIdValues) {
+ for (Transition childTransition : mTransitions) {
+ childTransition.prePlay(sceneRoot, startValues, startIdValues, startItemIdValues,
+ endValues, endIdValues, endItemIdValues);
+ }
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ protected void play(ViewGroup sceneRoot,
+ final HashMap<View, TransitionValues> startValues,
+ final SparseArray<TransitionValues> startIdValues,
+ final LongSparseArray<TransitionValues> startItemIdValues,
+ final HashMap<View, TransitionValues> endValues,
+ final SparseArray<TransitionValues> endIdValues,
+ final LongSparseArray<TransitionValues> endItemIdValues) {
+ setupStartEndListeners();
+ final ViewGroup finalSceneRoot = sceneRoot;
+ if (!mPlayTogether) {
+ // Setup sequence with listeners
+ // TODO: Need to add listeners in such a way that we can remove them later if canceled
+ for (int i = 1; i < mTransitions.size(); ++i) {
+ Transition previousTransition = mTransitions.get(i - 1);
+ final Transition nextTransition = mTransitions.get(i);
+ previousTransition.addListener(new TransitionListenerAdapter() {
+ @Override
+ public void onTransitionEnd(Transition transition) {
+ nextTransition.play(finalSceneRoot,
+ startValues, startIdValues, startItemIdValues,
+ endValues, endIdValues, endItemIdValues);
+ transition.removeListener(this);
+ }
+ });
+ }
+ Transition firstTransition = mTransitions.get(0);
+ if (firstTransition != null) {
+ firstTransition.play(finalSceneRoot, startValues, startIdValues, startItemIdValues,
+ endValues, endIdValues, endItemIdValues);
+ }
+ } else {
+ for (Transition childTransition : mTransitions) {
+ childTransition.play(finalSceneRoot, startValues, startIdValues, startItemIdValues,
+ endValues, endIdValues, endItemIdValues);
+ }
+ }
+ }
+
+ @Override
+ protected Animator play(ViewGroup sceneRoot,
+ TransitionValues startValues, TransitionValues endValues) {
+ final View view = (endValues != null) ? endValues.view :
+ (startValues != null) ? startValues.view : null;
+ final int targetId = (view != null) ? view.getId() : -1;
+ // TODO: not sure this is a valid check - what about auto-targets? No need for ids.
+ if (targetId < 0) {
+ return null;
+ }
+ setupStartEndListeners();
+ if (!mPlayTogether) {
+ final ViewGroup finalSceneRoot = sceneRoot;
+ final TransitionValues finalStartValues = startValues;
+ final TransitionValues finalEndValues = endValues;
+ // Setup sequence with listeners
+ // TODO: Need to add listeners in such a way that we can remove them later if canceled
+ for (int i = 1; i < mTransitions.size(); ++i) {
+ Transition previousTransition = mTransitions.get(i - 1);
+ final Transition nextTransition = mTransitions.get(i);
+ previousTransition.addListener(new TransitionListenerAdapter() {
+ @Override
+ public void onTransitionEnd(Transition transition) {
+ nextTransition.startTransition();
+ if (nextTransition.isValidTarget(view, targetId)) {
+ animate(nextTransition.play(finalSceneRoot, finalStartValues,
+ finalEndValues));
+ } else {
+ nextTransition.endTransition();
+ }
+ }
+ });
+ }
+ Transition firstTransition = mTransitions.get(0);
+ if (firstTransition != null) {
+ firstTransition.startTransition();
+ if (firstTransition.isValidTarget(view, targetId)) {
+ animate(firstTransition.play(finalSceneRoot, finalStartValues, finalEndValues));
+ } else {
+ firstTransition.endTransition();
+ }
+ }
+ } else {
+ for (Transition childTransition : mTransitions) {
+ childTransition.startTransition();
+ if (childTransition.isValidTarget(view, targetId)) {
+ animate(childTransition.play(sceneRoot, startValues, endValues));
+ } else {
+ childTransition.endTransition();
+ }
+ }
+ }
+ return null;
+ }
+
+ @Override
+ protected void captureValues(TransitionValues transitionValues, boolean start) {
+ int targetId = transitionValues.view.getId();
+ for (Transition childTransition : mTransitions) {
+ if (childTransition.isValidTarget(transitionValues.view, targetId)) {
+ childTransition.captureValues(transitionValues, start);
+ }
+ }
+ }
+
+ @Override
+ String toString(String indent) {
+ String result = super.toString(indent);
+ for (int i = 0; i < mTransitions.size(); ++i) {
+ result += "\n" + mTransitions.get(i).toString(indent + " ");
+ }
+ return result;
+ }
+
+}
diff --git a/core/java/android/view/transition/TransitionInflater.java b/core/java/android/view/transition/TransitionInflater.java
new file mode 100644
index 0000000..a5f5836
--- /dev/null
+++ b/core/java/android/view/transition/TransitionInflater.java
@@ -0,0 +1,392 @@
+/*
+ * Copyright (C) 2013 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.view.transition;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.content.res.XmlResourceParser;
+import android.util.AttributeSet;
+import android.util.SparseArray;
+import android.util.Xml;
+import android.view.InflateException;
+import android.view.ViewGroup;
+import android.view.animation.AnimationUtils;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+
+/**
+ * This class inflates scenes and transitions from resource files.
+ */
+public class TransitionInflater {
+
+ // We only need one inflater for any given context. Also, this allows us to associate
+ // ids with unique instances per-Context, used to avoid re-inflating
+ // already-inflated resources into new/different instances
+ private static final HashMap<Context, TransitionInflater> sInflaterMap =
+ new HashMap<Context, TransitionInflater>();
+
+ private Context mContext;
+ // TODO: do we need id maps for transitions and transitionMgrs as well?
+ SparseArray<Scene> mScenes = new SparseArray<Scene>();
+
+ private TransitionInflater(Context context) {
+ mContext = context;
+ }
+
+ /**
+ * Obtains the TransitionInflater from the given context.
+ */
+ public static TransitionInflater from(Context context) {
+ TransitionInflater inflater = sInflaterMap.get(context);
+ if (inflater != null) {
+ return inflater;
+ }
+ inflater = new TransitionInflater(context);
+ sInflaterMap.put(context, inflater);
+ return inflater;
+ }
+
+ /**
+ * Loads a {@link Transition} object from a resource
+ *
+ * @param resource The resource id of the transition to load
+ * @return The loaded Transition object
+ * @throws android.content.res.Resources.NotFoundException when the
+ * transition cannot be loaded
+ */
+ public Transition inflateTransition(int resource) {
+ XmlResourceParser parser = mContext.getResources().getXml(resource);
+ try {
+ return createTransitionFromXml(parser, Xml.asAttributeSet(parser), null);
+ } catch (XmlPullParserException e) {
+ InflateException ex = new InflateException(e.getMessage());
+ ex.initCause(e);
+ throw ex;
+ } catch (IOException e) {
+ InflateException ex = new InflateException(
+ parser.getPositionDescription()
+ + ": " + e.getMessage());
+ ex.initCause(e);
+ throw ex;
+ } finally {
+ parser.close();
+ }
+ }
+
+ /**
+ * Loads a {@link TransitionManager} object from a resource
+ *
+ *
+ *
+ * @param resource The resource id of the transition manager to load
+ * @return The loaded TransitionManager object
+ * @throws android.content.res.Resources.NotFoundException when the
+ * transition manager cannot be loaded
+ */
+ public TransitionManager inflateTransitionManager(int resource, ViewGroup sceneRoot) {
+ XmlResourceParser parser = mContext.getResources().getXml(resource);
+ try {
+ return createTransitionManagerFromXml(parser, Xml.asAttributeSet(parser), sceneRoot);
+ } catch (XmlPullParserException e) {
+ InflateException ex = new InflateException(e.getMessage());
+ ex.initCause(e);
+ throw ex;
+ } catch (IOException e) {
+ InflateException ex = new InflateException(
+ parser.getPositionDescription()
+ + ": " + e.getMessage());
+ ex.initCause(e);
+ throw ex;
+ } finally {
+ parser.close();
+ }
+ }
+
+ /**
+ * Loads a {@link Scene} object from a resource
+ *
+ * @param resource The resource id of the scene to load
+ * @return The loaded Scene object
+ * @throws android.content.res.Resources.NotFoundException when the scene
+ * cannot be loaded
+ */
+ public Scene inflateScene(int resource, ViewGroup parent) {
+ Scene scene = mScenes.get(resource);
+ if (scene != null) {
+ return scene;
+ }
+ XmlResourceParser parser = mContext.getResources().getXml(resource);
+ try {
+ scene = createSceneFromXml(parser, Xml.asAttributeSet(parser), parent);
+ mScenes.put(resource, scene);
+ return scene;
+ } catch (XmlPullParserException e) {
+ InflateException ex = new InflateException(e.getMessage());
+ ex.initCause(e);
+ throw ex;
+ } catch (IOException e) {
+ InflateException ex = new InflateException(
+ parser.getPositionDescription()
+ + ": " + e.getMessage());
+ ex.initCause(e);
+ throw ex;
+ } finally {
+ parser.close();
+ }
+ }
+
+
+ //
+ // Transition loading
+ //
+
+ private Transition createTransitionFromXml(XmlPullParser parser,
+ AttributeSet attrs, TransitionGroup transitionGroup)
+ throws XmlPullParserException, IOException {
+
+ Transition transition = null;
+
+ // Make sure we are on a start tag.
+ int type;
+ int depth = parser.getDepth();
+
+ while (((type=parser.next()) != XmlPullParser.END_TAG || parser.getDepth() > depth)
+ && type != XmlPullParser.END_DOCUMENT) {
+
+ boolean newTransition = false;
+
+ if (type != XmlPullParser.START_TAG) {
+ continue;
+ }
+
+ String name = parser.getName();
+ if ("fade".equals(name)) {
+ transition = new Fade();
+ newTransition = true;
+ } else if ("move".equals(name)) {
+ transition = new Move();
+ newTransition = true;
+ } else if ("slide".equals(name)) {
+ transition = new Slide();
+ newTransition = true;
+ } else if ("autoTransition".equals(name)) {
+ transition = new AutoTransition();
+ newTransition = true;
+ } else if ("recolor".equals(name)) {
+ transition = new Recolor();
+ newTransition = true;
+ } else if ("transitionGroup".equals(name)) {
+ transition = new TransitionGroup();
+ createTransitionFromXml(parser, attrs, ((TransitionGroup) transition));
+ newTransition = true;
+ } else if ("targets".equals(name)) {
+ if (parser.getDepth() - 1 > depth && transition != null) {
+ // We're inside the child tag - add targets to the child
+ getTargetIDs(parser, attrs, transition);
+ } else if (parser.getDepth() - 1 == depth && transitionGroup != null) {
+ // add targets to the group
+ getTargetIDs(parser, attrs, transitionGroup);
+ }
+ }
+ if (transition != null || "targets".equals(name)) {
+ if (newTransition) {
+ loadTransition(transition, attrs);
+ if (transitionGroup != null) {
+ transitionGroup.addTransitions(transition);
+ }
+ }
+ } else {
+ throw new RuntimeException("Unknown scene name: " + parser.getName());
+ }
+ }
+
+ return transition;
+ }
+
+ private void getTargetIDs(XmlPullParser parser,
+ AttributeSet attrs, Transition transition) throws XmlPullParserException, IOException {
+
+ // Make sure we are on a start tag.
+ int type;
+ int depth = parser.getDepth();
+
+ ArrayList<Integer> targetIds = new ArrayList<Integer>();
+ while (((type=parser.next()) != XmlPullParser.END_TAG || parser.getDepth() > depth)
+ && type != XmlPullParser.END_DOCUMENT) {
+
+ if (type != XmlPullParser.START_TAG) {
+ continue;
+ }
+
+ String name = parser.getName();
+ if (name.equals("target")) {
+ TypedArray a = mContext.obtainStyledAttributes(attrs,
+ com.android.internal.R.styleable.Transition);
+ int id = a.getResourceId(com.android.internal.R.styleable.Transition_targetID, -1);
+ if (id >= 0) {
+ targetIds.add(id);
+ }
+ } else {
+ throw new RuntimeException("Unknown scene name: " + parser.getName());
+ }
+ }
+ int numTargets = targetIds.size();
+ if (numTargets > 0) {
+ int[] targetsArray = new int[numTargets];
+ for (int i = 0; i < targetIds.size(); ++i) {
+ targetsArray[i] = targetIds.get(i);
+ }
+ transition.setTargetIds(targetsArray);
+ }
+ }
+
+ private Transition loadTransition(Transition transition, AttributeSet attrs)
+ throws Resources.NotFoundException {
+
+ TypedArray a =
+ mContext.obtainStyledAttributes(attrs, com.android.internal.R.styleable.Transition);
+ long duration = a.getInt(com.android.internal.R.styleable.Transition_duration, -1);
+ if (duration >= 0) {
+ transition.setDuration(duration);
+ }
+ long startOffset = a.getInt(com.android.internal.R.styleable.Transition_startOffset, -1);
+ if (startOffset > 0) {
+ transition.setStartDelay(startOffset);
+ }
+ final int resID =
+ a.getResourceId(com.android.internal.R.styleable.Animator_interpolator, 0);
+ if (resID > 0) {
+ transition.setInterpolator(AnimationUtils.loadInterpolator(mContext, resID));
+ }
+ a.recycle();
+ return transition;
+ }
+
+ //
+ // TransitionManager loading
+ //
+
+ private TransitionManager createTransitionManagerFromXml(XmlPullParser parser,
+ AttributeSet attrs, ViewGroup sceneRoot) throws XmlPullParserException, IOException {
+
+ // Make sure we are on a start tag.
+ int type;
+ int depth = parser.getDepth();
+ TransitionManager transitionManager = null;
+
+ while (((type=parser.next()) != XmlPullParser.END_TAG || parser.getDepth() > depth)
+ && type != XmlPullParser.END_DOCUMENT) {
+
+ if (type != XmlPullParser.START_TAG) {
+ continue;
+ }
+
+ String name = parser.getName();
+ if (name.equals("transitionManager")) {
+ transitionManager = new TransitionManager();
+ } else if (name.equals("transition") && (transitionManager != null)) {
+ loadTransition(attrs, sceneRoot, transitionManager);
+ } else {
+ throw new RuntimeException("Unknown scene name: " + parser.getName());
+ }
+ }
+ return transitionManager;
+ }
+
+ private void loadTransition(AttributeSet attrs, ViewGroup sceneRoot,
+ TransitionManager transitionManager)
+ throws Resources.NotFoundException {
+
+ TypedArray a = mContext.obtainStyledAttributes(attrs,
+ com.android.internal.R.styleable.TransitionManager);
+ int transitionId = attrs.getAttributeResourceValue(
+ com.android.internal.R.styleable.TransitionManager_transition, -1);
+ Scene fromScene = null, toScene = null;
+ int fromId = attrs.getAttributeResourceValue(
+ com.android.internal.R.styleable.TransitionManager_fromScene, -1);
+ if (fromId >= 0) fromScene = inflateScene(fromId, sceneRoot);
+ int toId = attrs.getAttributeResourceValue(
+ com.android.internal.R.styleable.TransitionManager_toScene, -1);
+ if (toId >= 0) toScene = inflateScene(toId, sceneRoot);
+ if (transitionId >= 0) {
+ Transition transition = inflateTransition(transitionId);
+ if (transition != null) {
+ if (fromScene != null) {
+ if (toScene == null){
+ throw new RuntimeException("No matching toScene for given fromScene " +
+ "for transition ID " + transitionId);
+ } else {
+ transitionManager.setTransition(fromScene, toScene, transition);
+ }
+ } else if (toId >= 0) {
+ transitionManager.setTransition(toScene, transition);
+ }
+ }
+ }
+ a.recycle();
+ }
+
+ //
+ // Scene loading
+ //
+
+ private Scene createSceneFromXml(XmlPullParser parser, AttributeSet attrs, ViewGroup parent)
+ throws XmlPullParserException, IOException {
+ Scene scene = null;
+
+ // Make sure we are on a start tag.
+ int type;
+ int depth = parser.getDepth();
+
+ while (((type=parser.next()) != XmlPullParser.END_TAG || parser.getDepth() > depth)
+ && type != XmlPullParser.END_DOCUMENT) {
+
+ if (type != XmlPullParser.START_TAG) {
+ continue;
+ }
+
+ String name = parser.getName();
+ if (name.equals("scene")) {
+ scene = loadScene(attrs, parent);
+ } else {
+ throw new RuntimeException("Unknown scene name: " + parser.getName());
+ }
+ }
+
+ return scene;
+ }
+
+ private Scene loadScene(AttributeSet attrs, ViewGroup parent)
+ throws Resources.NotFoundException {
+
+ Scene scene;
+ TypedArray a = mContext.obtainStyledAttributes(attrs,
+ com.android.internal.R.styleable.Scene);
+ int layoutId = a.getResourceId(com.android.internal.R.styleable.Scene_layout, -1);
+ if (layoutId >= 0) {
+ scene = new Scene(parent, layoutId, mContext);
+ } else {
+ scene = new Scene(parent);
+ }
+ a.recycle();
+ return scene;
+ }
+}
diff --git a/core/java/android/view/transition/TransitionManager.java b/core/java/android/view/transition/TransitionManager.java
new file mode 100644
index 0000000..5a1991c
--- /dev/null
+++ b/core/java/android/view/transition/TransitionManager.java
@@ -0,0 +1,261 @@
+/*
+ * Copyright (C) 2013 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.view.transition;
+
+import android.view.ViewGroup;
+import android.view.ViewTreeObserver;
+
+import java.util.HashMap;
+
+/**
+ * This class manages the set of transitions that fire when there is a
+ * change of {@link Scene}. To use the manager, add scenes along with
+ * transition objects with calls to {@link #setTransition(Scene, Transition)}
+ * or {@link #setTransition(Scene, Scene, Transition)}. Setting specific
+ * transitions for scene changes is not required; by default, a Scene change
+ * will use {@link AutoTransition} to do something reasonable for most
+ * situations. Specifying other transitions for particular scene changes is
+ * only necessary if the application wants different transition behavior
+ * in these situations.
+ */
+public class TransitionManager {
+ // TODO: how to handle enter/exit?
+
+ private static final Transition sDefaultTransition = new AutoTransition();
+ private Transition mDefaultTransition = new AutoTransition();
+
+ HashMap<Scene, Transition> mSceneTransitions = new HashMap<Scene, Transition>();
+ HashMap<Scene, HashMap<Scene, Transition>> mScenePairTransitions =
+ new HashMap<Scene, HashMap<Scene, Transition>>();
+
+ /**
+ * Sets the transition to be used for any scene change for which no
+ * other transition is explicitly set. The initial value is
+ * an {@link AutoTransition} instance.
+ *
+ * @param transition The default transition to be used for scene changes.
+ */
+ public void setDefaultTransition(Transition transition) {
+ mDefaultTransition = transition;
+ }
+
+ /**
+ * Gets the current default transition. The initial value is an {@link
+ * AutoTransition} instance.
+ *
+ * @return The current default transition.
+ * @see #setDefaultTransition(Transition)
+ */
+ public Transition getDefaultTransition() {
+ return mDefaultTransition;
+ }
+
+ /**
+ * Sets a specific transition to occur when the given scene is entered.
+ *
+ * @param scene The scene which, when applied, will cause the given
+ * transition to run.
+ * @param transition The transition that will play when the given scene is
+ * entered. A value of null will result in the default behavior of
+ * using {@link AutoTransition}.
+ */
+ public void setTransition(Scene scene, Transition transition) {
+ mSceneTransitions.put(scene, transition);
+ }
+
+ /**
+ * Sets a specific transition to occur when the given pair of scenes is
+ * exited/entered.
+ *
+ * @param fromScene The scene being exited when the given transition will
+ * be run
+ * @param toScene The scene being entered when the given transition will
+ * be run
+ * @param transition The transition that will play when the given scene is
+ * entered. A value of null will result in the default behavior of
+ * using {@link AutoTransition}.
+ */
+ public void setTransition(Scene fromScene, Scene toScene, Transition transition) {
+ HashMap<Scene, Transition> sceneTransitionMap = mScenePairTransitions.get(toScene);
+ if (sceneTransitionMap == null) {
+ sceneTransitionMap = new HashMap<Scene, Transition>();
+ mScenePairTransitions.put(toScene, sceneTransitionMap);
+ }
+ sceneTransitionMap.put(fromScene, transition);
+ }
+
+ /**
+ * Returns the Transition for the given scene being entered. The result
+ * depends not only on the given scene, but also the scene which the
+ * {@link Scene#getSceneRoot() sceneRoot} of the Scene is currently in.
+ *
+ * @param scene The scene being entered
+ * @return The Transition to be used for the given scene change. If no
+ * Transition was specified for this scene change, {@link AutoTransition}
+ * will be used instead.
+ */
+ private Transition getTransition(Scene scene) {
+ Transition transition = null;
+ ViewGroup sceneRoot = scene.getSceneRoot();
+ if (sceneRoot != null) {
+ // TODO: cached in Scene instead? long-term, cache in View itself
+ Scene currScene = sceneRoot.getCurrentScene();
+ if (currScene != null) {
+ HashMap<Scene, Transition> sceneTransitionMap = mScenePairTransitions.get(scene);
+ if (sceneTransitionMap != null) {
+ transition = sceneTransitionMap.get(currScene);
+ if (transition != null) {
+ return transition;
+ }
+ }
+ }
+ }
+ transition = mSceneTransitions.get(scene);
+ return (transition != null) ? transition : new AutoTransition();
+ }
+
+ /**
+ * This is where all of the work of a transition/scene-change is
+ * orchestrated. This method captures the start values for the given
+ * transition, exits the current Scene, enters the new scene, captures
+ * the end values for the transition, and finally plays the
+ * resulting values-populated transition.
+ *
+ * @param scene The scene being entered
+ * @param transition The transition to play for this scene change
+ */
+ private static void changeScene(Scene scene, final Transition transition) {
+
+ final ViewGroup sceneRoot = scene.getSceneRoot();
+
+ // Capture current values
+ if (transition != null) {
+ transition.captureValues(sceneRoot, true);
+ }
+
+ // Notify previous scene that it is being exited
+ Scene previousScene = sceneRoot.getCurrentScene();
+ if (previousScene != null) {
+ previousScene.exit();
+ }
+
+ scene.enter();
+
+ if (transition != null) {
+ final ViewTreeObserver observer = sceneRoot.getViewTreeObserver();
+ observer.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
+ public boolean onPreDraw() {
+ sceneRoot.getViewTreeObserver().removeOnPreDrawListener(this);
+ transition.captureValues(sceneRoot, false);
+ transition.play(sceneRoot);
+ return true;
+ }
+ });
+ }
+ }
+
+ /**
+ * Change to the given scene, using the
+ * appropriate transition for this particular scene change
+ * (as specified to the TransitionManager, or the default
+ * if no such transition exists).
+ *
+ * @param scene The Scene to change to
+ */
+ public void transitionTo(Scene scene) {
+ // Auto transition if there is no transition declared for the Scene, but there is
+ // a root or parent view
+ changeScene(scene, getTransition(scene));
+
+ }
+
+ /**
+ * Static utility method to simply change to the given scene using
+ * the default transition for TransitionManager.
+ *
+ * @param scene The Scene to change to
+ */
+ public static void go(Scene scene) {
+ changeScene(scene, sDefaultTransition);
+ }
+
+ /**
+ * Static utility method to simply change to the given scene using
+ * the given transition.
+ *
+ * <p>Passing in <code>null</code> for the transition parameter will
+ * result in the scene changing without any transition running, and is
+ * equivalent to calling {@link Scene#exit()} on the scene root's
+ * {@link ViewGroup#getCurrentScene() current scene}, followed by
+ * {@link Scene#enter()} on the scene specified by the <code>scene</code>
+ * parameter.</p>
+ *
+ * @param scene The Scene to change to
+ * @param transition The transition to use for this scene change. A
+ * value of null causes the scene change to happen with no transition.
+ */
+ public static void go(Scene scene, Transition transition) {
+ changeScene(scene, transition);
+ }
+
+ /**
+ * Static utility method to simply change to a scene defined by the
+ * code in the given runnable, which will be executed after
+ * the current values have been captured for the transition.
+ * This is equivalent to creating a Scene and calling {@link
+ * Scene#setEnterAction(Runnable)} with the runnable, then calling
+ * {@link #go(Scene, Transition)}. The transition used will be the
+ * default provided by TransitionManager.
+ *
+ * @param sceneRoot The root of the View hierarchy used when this scene
+ * runs a transition automatically.
+ * @param action The runnable whose {@link Runnable#run() run()} method will
+ * be called.
+ */
+ public static void go(ViewGroup sceneRoot, Runnable action) {
+ Scene scene = new Scene(sceneRoot);
+ scene.setEnterAction(action);
+ changeScene(scene, sDefaultTransition);
+ }
+
+ /**
+ * Static utility method to simply change to a scene defined by the
+ * code in the given runnable, which will be executed after
+ * the current values have been captured for the transition.
+ * This is equivalent to creating a Scene and calling {@link
+ * Scene#setEnterAction(Runnable)} with the runnable, then calling
+ * {@link #go(Scene, Transition)}. The given transition will be
+ * used to animate the changes.
+ *
+ * <p>Passing in <code>null</code> for the transition parameter will
+ * result in the scene changing without any transition running, and is
+ * equivalent to calling {@link Scene#exit()} on the scene root's
+ * {@link ViewGroup#getCurrentScene() current scene}, followed by
+ * {@link Scene#enter()} on a new scene specified by the
+ * <code>action</code> parameter.</p>
+ *
+ * @param sceneRoot The root of the View hierarchy to run the transition on.
+ * @param action The runnable whose {@link Runnable#run() run()} method will
+ * be called.
+ * @param transition The transition to use for this change. A
+ * value of null causes the change to happen with no transition.
+ */
+ public static void go(ViewGroup sceneRoot, Runnable action, Transition transition) {
+ Scene scene = new Scene(sceneRoot);
+ scene.setEnterAction(action);
+ changeScene(scene, transition);
+ }
+}
diff --git a/core/java/android/view/transition/TransitionValues.java b/core/java/android/view/transition/TransitionValues.java
new file mode 100644
index 0000000..120ace8
--- /dev/null
+++ b/core/java/android/view/transition/TransitionValues.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2013 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.view.transition;
+
+import android.view.View;
+import android.view.ViewGroup;
+
+import java.util.HashMap;
+
+/**
+ * Data structure which holds cached values for the transition.
+ * The view field is the target which all of the values pertain to.
+ * The values field is a hashmap which holds information for fields
+ * according to names selected by the transitions. These names should
+ * be unique to avoid clobbering values stored by other transitions,
+ * such as the convention project:transition_name:property_name. For
+ * example, the platform might store a property "alpha" in a transition
+ * "Fader" as "android:fader:alpha".
+ *
+ * <p>These values are cached during the
+ * {@link Transition#captureValues(TransitionValues, boolean)}
+ * capture} phases of a scene change, once when the start values are captured
+ * and again when the end values are captured. These start/end values are then
+ * passed into the transitions during the play phase of the scene change,
+ * for {@link Transition#prePlay(ViewGroup, TransitionValues, TransitionValues)} and
+ * for {@link Transition#play(ViewGroup, TransitionValues, TransitionValues)}.</p>
+ */
+public class TransitionValues {
+
+ /**
+ * The View with these values
+ */
+ public View view;
+
+ /**
+ * The set of values tracked by transitions for this scene
+ */
+ public final HashMap<String, Object> values = new HashMap<String, Object>();
+
+ @Override
+ public String toString() {
+ String returnValue = "TransitionValues@" + Integer.toHexString(hashCode()) + ":\n";
+ returnValue += " view = " + view + "\n";
+ returnValue += " values = " + values + "\n";
+ return returnValue;
+ }
+} \ No newline at end of file
diff --git a/core/java/android/view/transition/Visibility.java b/core/java/android/view/transition/Visibility.java
new file mode 100644
index 0000000..a3e6e77
--- /dev/null
+++ b/core/java/android/view/transition/Visibility.java
@@ -0,0 +1,243 @@
+/*
+ * Copyright (C) 2013 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.view.transition;
+
+import android.animation.Animator;
+import android.view.View;
+import android.view.ViewGroup;
+
+/**
+ * This transition tracks changes to the visibility of target views in the
+ * start and end scenes. Visibility is determined not just by the
+ * {@link View#setVisibility(int)} state of views, but also whether
+ * views exist in the current view hierarchy. The class is intended to be a
+ * utility for subclasses such as {@link Fade}, which use this visibility
+ * information to determine the specific animations to run when visibility
+ * changes occur. Subclasses should implement one or more of the methods
+ * {@link #preAppear(ViewGroup, View, int, View, int)},
+ * {@link #preDisappear(ViewGroup, View, int, View, int)},
+ * {@link #appear(ViewGroup, View, int, View, int)}, and
+ * {@link #disappear(ViewGroup, View, int, View, int)}.
+ */
+public abstract class Visibility extends Transition {
+
+ private static final String PROPNAME_VISIBILITY = "android:visibility:visibility";
+ private static final String PROPNAME_PARENT = "android:visibility:parent";
+
+ @Override
+ protected void captureValues(TransitionValues values, boolean start) {
+ int visibility = values.view.getVisibility();
+ values.values.put(PROPNAME_VISIBILITY, visibility);
+ values.values.put(PROPNAME_PARENT, values.view.getParent());
+ }
+
+ @Override
+ protected boolean prePlay(ViewGroup sceneRoot, TransitionValues startValues,
+ TransitionValues endValues) {
+ boolean visibilityChange = false;
+ boolean fadeIn = false;
+ int startVisibility, endVisibility;
+ View startParent, endParent;
+ if (startValues != null) {
+ startVisibility = (Integer) startValues.values.get(PROPNAME_VISIBILITY);
+ startParent = (View) startValues.values.get(PROPNAME_PARENT);
+ } else {
+ startVisibility = -1;
+ startParent = null;
+ }
+ if (endValues != null) {
+ endVisibility = (Integer) endValues.values.get(PROPNAME_VISIBILITY);
+ endParent = (View) endValues.values.get(PROPNAME_PARENT);
+ } else {
+ endVisibility = -1;
+ endParent = null;
+ }
+ boolean existenceChange = false;
+ if (startValues != null && endValues != null) {
+ if (startVisibility == endVisibility && startParent == endParent) {
+ return false;
+ } else {
+ if (startVisibility != endVisibility) {
+ if (startVisibility == View.VISIBLE) {
+ fadeIn = false;
+ visibilityChange = true;
+ } else if (endVisibility == View.VISIBLE) {
+ fadeIn = true;
+ visibilityChange = true;
+ }
+ // no visibilityChange if going between INVISIBLE and GONE
+ } else if (startParent != endParent) {
+ existenceChange = true;
+ if (endParent == null) {
+ fadeIn = false;
+ visibilityChange = true;
+ } else if (startParent == null) {
+ fadeIn = true;
+ visibilityChange = true;
+ }
+ }
+ }
+ }
+ if (startValues == null) {
+ existenceChange = true;
+ fadeIn = true;
+ visibilityChange = true;
+ } else if (endValues == null) {
+ existenceChange = true;
+ fadeIn = false;
+ visibilityChange = true;
+ }
+ if (visibilityChange) {
+ if (fadeIn) {
+ return preAppear(sceneRoot, existenceChange ? null : startValues.view,
+ startVisibility, endValues.view, endVisibility);
+ } else {
+ return preDisappear(sceneRoot, startValues.view, startVisibility,
+ existenceChange ? null : endValues.view, endVisibility);
+ }
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ protected Animator play(ViewGroup sceneRoot, TransitionValues startValues,
+ TransitionValues endValues) {
+ boolean visibilityChange = false;
+ boolean fadeIn = false;
+ int startVisibility, endVisibility;
+ View startParent, endParent;
+ if (startValues != null) {
+ startVisibility = (Integer) startValues.values.get(PROPNAME_VISIBILITY);
+ startParent = (View) startValues.values.get(PROPNAME_PARENT);
+ } else {
+ startVisibility = -1;
+ startParent = null;
+ }
+ if (endValues != null) {
+ endVisibility = (Integer) endValues.values.get(PROPNAME_VISIBILITY);
+ endParent = (View) endValues.values.get(PROPNAME_PARENT);
+ } else {
+ endVisibility = -1;
+ endParent = null;
+ }
+ boolean existenceChange = false;
+ if (startValues != null && endValues != null) {
+ if (startVisibility == endVisibility && startParent == endParent) {
+ return null;
+ } else {
+ if (startVisibility != endVisibility) {
+ if (startVisibility == View.VISIBLE) {
+ fadeIn = false;
+ visibilityChange = true;
+ } else if (endVisibility == View.VISIBLE) {
+ fadeIn = true;
+ visibilityChange = true;
+ }
+ // no visibilityChange if going between INVISIBLE and GONE
+ } else if (startParent != endParent) {
+ existenceChange = true;
+ if (endParent == null) {
+ fadeIn = false;
+ visibilityChange = true;
+ } else if (startParent == null) {
+ fadeIn = true;
+ visibilityChange = true;
+ }
+ }
+ }
+ }
+ if (startValues == null) {
+ existenceChange = true;
+ fadeIn = true;
+ visibilityChange = true;
+ } else if (endValues == null) {
+ existenceChange = true;
+ fadeIn = false;
+ visibilityChange = true;
+ }
+ if (visibilityChange) {
+ if (fadeIn) {
+ return appear(sceneRoot, existenceChange ? null : startValues.view, startVisibility,
+ endValues.view, endVisibility);
+ } else {
+ return disappear(sceneRoot, startValues.view, startVisibility,
+ existenceChange ? null : endValues.view, endVisibility);
+ }
+ }
+ return null;
+ }
+
+ /**
+ * The default implementation of this method does nothing. Subclasses
+ * should override if they need to set up anything prior to the
+ * transition starting.
+ *
+ * @param sceneRoot
+ * @param startView
+ * @param startVisibility
+ * @param endView
+ * @param endVisibility
+ * @return
+ */
+ protected boolean preAppear(ViewGroup sceneRoot, View startView, int startVisibility,
+ View endView, int endVisibility) {
+ return true;
+ }
+
+ /**
+ * The default implementation of this method does nothing. Subclasses
+ * should override if they need to set up anything prior to the
+ * transition starting.
+ * @param sceneRoot
+ * @param startView
+ * @param startVisibility
+ * @param endView
+ * @param endVisibility
+ * @return
+ */
+ protected boolean preDisappear(ViewGroup sceneRoot, View startView, int startVisibility,
+ View endView, int endVisibility) {
+ return true;
+ }
+
+ /**
+ * The default implementation of this method does nothing. Subclasses
+ * should override if they need to do anything when target objects
+ * appear during the scene change.
+ * @param sceneRoot
+ * @param startView
+ * @param startVisibility
+ * @param endView
+ * @param endVisibility
+ */
+ protected Animator appear(ViewGroup sceneRoot, View startView, int startVisibility,
+ View endView, int endVisibility) { return null; }
+
+ /**
+ * The default implementation of this method does nothing. Subclasses
+ * should override if they need to do anything when target objects
+ * disappear during the scene change.
+ * @param sceneRoot
+ * @param startView
+ * @param startVisibility
+ * @param endView
+ * @param endVisibility
+ */
+ protected Animator disappear(ViewGroup sceneRoot, View startView, int startVisibility,
+ View endView, int endVisibility) { return null; }
+
+}
diff --git a/core/java/android/view/transition/package.html b/core/java/android/view/transition/package.html
new file mode 100644
index 0000000..37dc0ec
--- /dev/null
+++ b/core/java/android/view/transition/package.html
@@ -0,0 +1,25 @@
+<html>
+<body>
+<p>The classes in this package enable "scenes & transitions" functionality for
+view hiearchies.</p>
+
+<p>A <b>Scene</b> is an encapsulation of the state of a view hiearchy,
+including the views in that hierarchy and the various values (layout-related
+and otherwise) that those views have. A scene be defined by a layout hierarchy
+directly or some code which sets up the scene dynamically as it is entered.</p>
+
+<p>A <b>Transition</b> is a mechanism to automatically animate changes that occur
+when a new scene is entered. Some transition capabilities are automatic. That
+is, entering a scene may cause animations to run which fade out views that
+go away, move and resize existing views that change, and fade in views that
+become visible. There are additional transitions that can animate other
+attributes, such as color changes, and which can optionally be specified
+to take place during particular scene changes. Finally, developers can
+define their own Transition subclasses which monitor particular property
+changes and which run custom animations when those properties change values.</p>
+
+<p><b>TransitionManager</b> is used to specify custom transitions for particular
+scene changes, and to cause scene changes with transitions to take place.</p>
+
+</body>
+</html>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 8c7a374..939d435 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -4378,6 +4378,28 @@
</declare-styleable>
<!-- ========================== -->
+ <!-- State class attributes -->
+ <!-- ========================== -->
+ <eat-comment />
+
+ <declare-styleable name="Scene">
+ <attr name="layout" />
+ </declare-styleable>
+
+ <declare-styleable name="Transition">
+ <attr name="duration" />
+ <attr name="startOffset" />
+ <attr name="interpolator" />
+ <attr name="targetID" format="reference" />
+ </declare-styleable>
+
+ <declare-styleable name="TransitionManager">
+ <attr name="transition" format="reference" />
+ <attr name="fromScene" format="reference" />
+ <attr name="toScene" format="reference" />
+ </declare-styleable>
+
+ <!-- ========================== -->
<!-- ValueAnimator class attributes -->
<!-- ========================== -->
<eat-comment />
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 03d7207..1f088a5 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2058,5 +2058,9 @@
<eat-comment />
<public type="attr" name="keyset" />
+ <public type="attr" name="targetID" />
+ <public type="attr" name="fromScene" />
+ <public type="attr" name="toScene" />
+ <public type="attr" name="transition" />
</resources>
diff --git a/tests/TransitionTests/Android.mk b/tests/TransitionTests/Android.mk
new file mode 100644
index 0000000..22fa638
--- /dev/null
+++ b/tests/TransitionTests/Android.mk
@@ -0,0 +1,18 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+
+# Only compile source java files in this apk.
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := TransitionTests
+
+LOCAL_STATIC_JAVA_LIBRARIES += android-common
+
+LOCAL_PROGUARD_ENABLED := disabled
+
+include $(BUILD_PACKAGE)
+
+# Use the following include to make our test apk.
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tests/TransitionTests/AndroidManifest.xml b/tests/TransitionTests/AndroidManifest.xml
new file mode 100644
index 0000000..8cd36bf
--- /dev/null
+++ b/tests/TransitionTests/AndroidManifest.xml
@@ -0,0 +1,211 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.transitiontests"
+ android:versionCode="1"
+ android:versionName="1.0">
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+ <application
+ android:icon="@drawable/icon"
+ android:label="@string/app_name"
+ android:hardwareAccelerated="true"
+ android:theme="@style/AppTheme">
+ <activity android:label="@string/states_test1"
+ android:name="ScenesTestv21">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ <activity android:label="@string/states_test_auto_targets"
+ android:name="ScenesTestAutoTargets">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ <activity android:label="@string/states_test_auto_transition"
+ android:name="ScenesTestAutoTransition">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ <activity android:label="@string/states_test_auto_transition2"
+ android:name="ScenesTestAutoTransition2">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ <activity android:label="@string/contacts_expansion"
+ android:name="ContactsExpansion">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ <activity android:label="Demo0"
+ android:name="Demo0">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ <activity android:label="Demo1"
+ android:name="Demo1">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ <activity android:label="Demo2"
+ android:name="Demo2">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ <activity android:label="Demo3"
+ android:name="Demo3">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ <activity android:label="Demo4"
+ android:name="Demo4">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ <activity android:label="Demo5"
+ android:name="Demo5">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ <activity android:label="LoginActivity"
+ android:name="LoginActivity">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ <activity android:label="LoginActivityFromResources"
+ android:name="LoginActivityFromResources">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ <activity android:label="OverlayTest"
+ android:name="OverlayTest">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ <activity android:label="ResourceLoadingTest"
+ android:name="ResourceLoadingTest">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ <activity android:label="FadingTest"
+ android:name="FadingTest">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ <activity android:label="UniqueIds"
+ android:name="UniqueIds">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ <activity android:label="HitRectBug"
+ android:name="HitRectBug">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ <activity android:label="SequenceTest"
+ android:name="SequenceTest">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ <activity android:label="SequenceTestSimple"
+ android:name="SequenceTestSimple">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ <activity android:label="ChangingText"
+ android:name="ChangingText">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ <activity android:label="ClippingText"
+ android:name="ClippingText">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ <activity android:label="ListViewAddRemove"
+ android:name="ListViewAddRemove">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ <activity android:label="ListViewAddRemoveNoTransition"
+ android:name="ListViewAddRemoveNoTransition">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ <activity android:label="CrossFadeDemo"
+ android:name="CrossFadeDemo">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ <activity android:label="Reparenting"
+ android:name="Reparenting">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ <activity android:label="SurfaceAndTextureViews"
+ android:name="SurfaceAndTextureViews">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ <activity android:label="InstanceTargets"
+ android:name="InstanceTargets">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+
+ </application>
+
+</manifest>
diff --git a/tests/TransitionTests/res/drawable-hdpi/icon.png b/tests/TransitionTests/res/drawable-hdpi/icon.png
new file mode 100644
index 0000000..8074c4c
--- /dev/null
+++ b/tests/TransitionTests/res/drawable-hdpi/icon.png
Binary files differ
diff --git a/tests/TransitionTests/res/drawable-ldpi/icon.png b/tests/TransitionTests/res/drawable-ldpi/icon.png
new file mode 100644
index 0000000..1095584
--- /dev/null
+++ b/tests/TransitionTests/res/drawable-ldpi/icon.png
Binary files differ
diff --git a/tests/TransitionTests/res/drawable-mdpi/icon.png b/tests/TransitionTests/res/drawable-mdpi/icon.png
new file mode 100644
index 0000000..a07c69f
--- /dev/null
+++ b/tests/TransitionTests/res/drawable-mdpi/icon.png
Binary files differ
diff --git a/tests/TransitionTests/res/drawable-nodpi/arrow_thumbnail.png b/tests/TransitionTests/res/drawable-nodpi/arrow_thumbnail.png
new file mode 100644
index 0000000..5cae8f2
--- /dev/null
+++ b/tests/TransitionTests/res/drawable-nodpi/arrow_thumbnail.png
Binary files differ
diff --git a/tests/TransitionTests/res/drawable-nodpi/self_portrait_square.jpg b/tests/TransitionTests/res/drawable-nodpi/self_portrait_square.jpg
new file mode 100644
index 0000000..8cce1c1
--- /dev/null
+++ b/tests/TransitionTests/res/drawable-nodpi/self_portrait_square.jpg
Binary files differ
diff --git a/tests/TransitionTests/res/drawable-nodpi/self_portrait_square_100.jpg b/tests/TransitionTests/res/drawable-nodpi/self_portrait_square_100.jpg
new file mode 100644
index 0000000..26c0a85
--- /dev/null
+++ b/tests/TransitionTests/res/drawable-nodpi/self_portrait_square_100.jpg
Binary files differ
diff --git a/tests/TransitionTests/res/drawable-nodpi/self_portrait_square_200.jpg b/tests/TransitionTests/res/drawable-nodpi/self_portrait_square_200.jpg
new file mode 100644
index 0000000..f18ae5b
--- /dev/null
+++ b/tests/TransitionTests/res/drawable-nodpi/self_portrait_square_200.jpg
Binary files differ
diff --git a/tests/TransitionTests/res/layout/activity_login.xml b/tests/TransitionTests/res/layout/activity_login.xml
new file mode 100644
index 0000000..2aaafc0
--- /dev/null
+++ b/tests/TransitionTests/res/layout/activity_login.xml
@@ -0,0 +1,86 @@
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/container"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <TextView
+ android:id="@+id/password"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignRight="@+id/username"
+ android:layout_below="@+id/username"
+ android:layout_marginTop="30dp"
+ android:textColor="#7f7f7f"
+ android:text="@string/password"
+ android:textAppearance="?android:attr/textAppearanceLarge" />
+
+ <EditText
+ android:id="@+id/usernameEdit"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignTop="@+id/username"
+ android:layout_marginLeft="14dp"
+ android:layout_toRightOf="@+id/username"
+ android:ems="10" />
+
+ <TextView
+ android:id="@+id/username"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentLeft="true"
+ android:layout_alignParentTop="true"
+ android:layout_marginLeft="20dp"
+ android:layout_marginTop="51dp"
+ android:text="@string/username"
+ android:textAppearance="?android:attr/textAppearanceLarge" />
+
+ <EditText
+ android:id="@+id/passwordEdit"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignBaseline="@+id/password"
+ android:layout_alignBottom="@+id/password"
+ android:layout_alignLeft="@+id/usernameEdit"
+ android:layout_alignParentRight="true"
+ android:editable="false"
+ android:ems="10" >
+
+ <requestFocus />
+ </EditText>
+
+ <Button
+ android:id="@+id/cancel"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentBottom="true"
+ android:layout_marginBottom="14dp"
+ android:layout_toLeftOf="@+id/passwordEdit"
+ android:onClick="sendMessage"
+ android:text="@string/cancel" />
+
+ <Button
+ android:id="@+id/submit"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignBaseline="@+id/cancel"
+ android:layout_alignBottom="@+id/cancel"
+ android:layout_alignLeft="@+id/passwordEdit"
+ android:layout_marginLeft="41dp"
+ android:onClick="sendMessage"
+ android:text="@string/submit" />
+
+ <TextView
+ android:id="@+id/newuser"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@+id/passwordEdit"
+ android:layout_centerHorizontal="true"
+ android:layout_marginTop="16dp"
+ android:textColor="#0000ff"
+ android:text="@string/new_user"
+ android:clickable="true"
+ android:onClick="sendMessage"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textStyle="italic" />
+
+</RelativeLayout> \ No newline at end of file
diff --git a/tests/TransitionTests/res/layout/button_template.xml b/tests/TransitionTests/res/layout/button_template.xml
new file mode 100644
index 0000000..9b867f2
--- /dev/null
+++ b/tests/TransitionTests/res/layout/button_template.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<Button xmlns:android="http://schemas.android.com/apk/res/android"
+ android:onClick="sendMessage"
+ android:id="@+id/button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content">
+
+</Button> \ No newline at end of file
diff --git a/tests/TransitionTests/res/layout/changing_text_1.xml b/tests/TransitionTests/res/layout/changing_text_1.xml
new file mode 100644
index 0000000..88086a3
--- /dev/null
+++ b/tests/TransitionTests/res/layout/changing_text_1.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:id="@+id/container"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/submit"
+ android:onClick="sendMessage"
+ android:id="@+id/sceneSwitchButton"/>
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/shortText1"
+ android:background="#8f8f8f"
+ android:id="@+id/textview1"/>
+ <Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:id="@+id/buttona"
+ android:text="@string/button"/>
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/longText1"
+ android:background="#8f8f8f"
+ android:id="@+id/textview2"/>
+
+ <Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:id="@+id/buttonb"
+ android:text="@string/button"/>
+
+</LinearLayout> \ No newline at end of file
diff --git a/tests/TransitionTests/res/layout/changing_text_2.xml b/tests/TransitionTests/res/layout/changing_text_2.xml
new file mode 100644
index 0000000..91fdfef
--- /dev/null
+++ b/tests/TransitionTests/res/layout/changing_text_2.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:id="@+id/container"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/submit"
+ android:onClick="sendMessage"
+ android:id="@+id/sceneSwitchButton"/>
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/longText2"
+ android:background="#8f8f8f"
+ android:id="@+id/textview1"/>
+ <Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:id="@+id/buttona"
+ android:text="@string/button"/>
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/shortText2"
+ android:background="#8f8f8f"
+ android:id="@+id/textview2"/>
+
+ <Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:id="@+id/buttonb"
+ android:text="@string/button"/>
+
+</LinearLayout> \ No newline at end of file
diff --git a/tests/TransitionTests/res/layout/clipping_text_1.xml b/tests/TransitionTests/res/layout/clipping_text_1.xml
new file mode 100644
index 0000000..5fe45ab
--- /dev/null
+++ b/tests/TransitionTests/res/layout/clipping_text_1.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:id="@+id/container"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/submit"
+ android:onClick="sendMessage"
+ android:id="@+id/sceneSwitchButton"/>
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/shortText1"
+ android:background="#8f8f8f"
+ android:id="@+id/textview1"/>
+
+</LinearLayout> \ No newline at end of file
diff --git a/tests/TransitionTests/res/layout/clipping_text_2.xml b/tests/TransitionTests/res/layout/clipping_text_2.xml
new file mode 100644
index 0000000..3a0e3f4
--- /dev/null
+++ b/tests/TransitionTests/res/layout/clipping_text_2.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:id="@+id/container"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <Button
+ android:layout_width="500dip"
+ android:layout_height="wrap_content"
+ android:text="@string/submit"
+ android:onClick="sendMessage"
+ android:id="@+id/sceneSwitchButton"/>
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/longText2"
+ android:background="#8f8f8f"
+ android:id="@+id/textview1"/>
+</LinearLayout> \ No newline at end of file
diff --git a/tests/TransitionTests/res/layout/contact_collapsed.xml b/tests/TransitionTests/res/layout/contact_collapsed.xml
new file mode 100644
index 0000000..bfa97df
--- /dev/null
+++ b/tests/TransitionTests/res/layout/contact_collapsed.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="horizontal"
+ android:background="#fff"
+ android:layout_width="fill_parent"
+ android:id="@+id/topContainer"
+ android:layout_height="wrap_content">
+ <ImageView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:id="@+id/contact_arrow"
+ android:src="@drawable/arrow_thumbnail"/>
+ <ImageView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:id="@+id/contact_picture"/>
+ <LinearLayout android:orientation="vertical"
+ android:layout_width="0dip"
+ android:id="@+id/itemContainer"
+ android:background="#ccc"
+ android:layout_weight="1"
+ android:layout_height="wrap_content">
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:id="@+id/contact_name"/>
+ <LinearLayout android:orientation="vertical"
+ android:visibility="gone"
+ android:id="@+id/expanded_info"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content">
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:id="@+id/contact_street"/>
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:id="@+id/contact_city"/>
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:id="@+id/contact_phone"/>
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:id="@+id/contact_email"/>
+ </LinearLayout>
+ </LinearLayout>
+</LinearLayout> \ No newline at end of file
diff --git a/tests/TransitionTests/res/layout/contact_expanded.xml b/tests/TransitionTests/res/layout/contact_expanded.xml
new file mode 100644
index 0000000..4007d4a
--- /dev/null
+++ b/tests/TransitionTests/res/layout/contact_expanded.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="horizontal"
+ android:background="#fff"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent">
+ <ImageView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:id="@+id/contact_arrow"
+ android:src="@drawable/arrow_thumbnail"/>
+ <LinearLayout android:orientation="vertical"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent">
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:id="@+id/contact_name"/>
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:id="@+id/contact_street"/>
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:id="@+id/contact_city"/>
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:id="@+id/contact_phone"/>
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:id="@+id/contact_email"/>
+ </LinearLayout>
+ <ImageView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:id="@+id/contact_picture"/>
+</LinearLayout> \ No newline at end of file
diff --git a/tests/TransitionTests/res/layout/contacts_list.xml b/tests/TransitionTests/res/layout/contacts_list.xml
new file mode 100644
index 0000000..d38704c
--- /dev/null
+++ b/tests/TransitionTests/res/layout/contacts_list.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:id="@+id/contactsContainer"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent">
+
+
+
+</LinearLayout> \ No newline at end of file
diff --git a/tests/TransitionTests/res/layout/crossfade.xml b/tests/TransitionTests/res/layout/crossfade.xml
new file mode 100644
index 0000000..d766ce1
--- /dev/null
+++ b/tests/TransitionTests/res/layout/crossfade.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:id="@+id/container">
+ <Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:onClick="sendMessage"
+ android:id="@+id/button"/>
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/shortText1"
+ android:id="@+id/textview"/>
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/longText1"
+ android:id="@+id/textview1"/>
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/someText"
+ android:id="@+id/textview2"/>
+
+</LinearLayout> \ No newline at end of file
diff --git a/tests/TransitionTests/res/layout/crossfade_1.xml b/tests/TransitionTests/res/layout/crossfade_1.xml
new file mode 100644
index 0000000..4cc5bc9
--- /dev/null
+++ b/tests/TransitionTests/res/layout/crossfade_1.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:id="@+id/container">
+ <Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:onClick="sendMessage"
+ android:id="@+id/button"/>
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/shortText2"
+ android:id="@+id/textview"/>
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/longText2"
+ android:id="@+id/textview1"/>
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/someText"
+ android:id="@+id/textview2"/>
+
+</LinearLayout> \ No newline at end of file
diff --git a/tests/TransitionTests/res/layout/fading_test.xml b/tests/TransitionTests/res/layout/fading_test.xml
new file mode 100644
index 0000000..3728b5e
--- /dev/null
+++ b/tests/TransitionTests/res/layout/fading_test.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:id="@+id/container"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/submit"
+ android:onClick="sendMessage"
+ android:id="@+id/sceneSwitchButton"/>
+ <Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/removingButton"
+ android:id="@+id/removingButton"/>
+ <Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/invisibleButton"
+ android:id="@+id/invisibleButton"/>
+ <Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/goneButton"
+ android:id="@+id/goneButton"/>
+
+ <Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:id="@+id/button"
+ android:text="@string/button"/>
+
+</LinearLayout> \ No newline at end of file
diff --git a/tests/TransitionTests/res/layout/fading_test_scene_2.xml b/tests/TransitionTests/res/layout/fading_test_scene_2.xml
new file mode 100644
index 0000000..baf5b4d
--- /dev/null
+++ b/tests/TransitionTests/res/layout/fading_test_scene_2.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:id="@+id/container"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/submit"
+ android:onClick="sendMessage"
+ android:id="@+id/sceneSwitchButton"/>
+ <Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/invisibleButton"
+ android:visibility="invisible"
+ android:id="@+id/invisibleButton"/>
+ <Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/goneButton"
+ android:visibility="gone"
+ android:id="@+id/goneButton"/>
+
+ <Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:id="@+id/button"
+ android:text="@string/button"/>
+
+</LinearLayout> \ No newline at end of file
diff --git a/tests/TransitionTests/res/layout/fading_test_simple.xml b/tests/TransitionTests/res/layout/fading_test_simple.xml
new file mode 100644
index 0000000..d201eca
--- /dev/null
+++ b/tests/TransitionTests/res/layout/fading_test_simple.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:id="@+id/container"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/submit"
+ android:onClick="sendMessage"
+ android:id="@+id/sceneSwitchButton"/>
+ <Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/removingButton"
+ android:id="@+id/removingButton"/>
+
+</LinearLayout> \ No newline at end of file
diff --git a/tests/TransitionTests/res/layout/fading_test_simple2.xml b/tests/TransitionTests/res/layout/fading_test_simple2.xml
new file mode 100644
index 0000000..80f3f94
--- /dev/null
+++ b/tests/TransitionTests/res/layout/fading_test_simple2.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:id="@+id/container"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="50dip"
+ android:text="@string/submit"
+ android:onClick="sendMessage"
+ android:id="@+id/sceneSwitchButton"/>
+ <Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/removingButton"
+ android:visibility="invisible"
+ android:id="@+id/removingButton"/>
+
+</LinearLayout> \ No newline at end of file
diff --git a/tests/TransitionTests/res/layout/incorrect_password.xml b/tests/TransitionTests/res/layout/incorrect_password.xml
new file mode 100644
index 0000000..af59618
--- /dev/null
+++ b/tests/TransitionTests/res/layout/incorrect_password.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/container"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" >
+
+ <Button
+ android:id="@+id/okay"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentBottom="true"
+ android:layout_centerHorizontal="true"
+ android:layout_marginBottom="164dp"
+ android:onClick="sendMessage"
+ android:text="@string/okay" />
+
+ <TextView
+ android:id="@+id/incorrectpassword"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_above="@+id/okay"
+ android:layout_centerHorizontal="true"
+ android:layout_marginBottom="93dp"
+ android:text="@string/incorrect_password"
+ android:textAppearance="?android:attr/textAppearanceLarge" />
+
+ <TextView
+ android:id="@+id/tryagain"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignTop="@+id/incorrectpassword"
+ android:layout_centerHorizontal="true"
+ android:layout_marginTop="35dp"
+ android:text="@string/try_again"
+ android:textAppearance="?android:attr/textAppearanceLarge" />
+
+</RelativeLayout> \ No newline at end of file
diff --git a/tests/TransitionTests/res/layout/instance_targets.xml b/tests/TransitionTests/res/layout/instance_targets.xml
new file mode 100644
index 0000000..5677d52
--- /dev/null
+++ b/tests/TransitionTests/res/layout/instance_targets.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:id="@+id/container">
+
+ <Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentLeft="true"
+ android:onClick="sendMessage"
+ android:id="@+id/button0"/>
+
+ <Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@+id/button0"
+ android:onClick="sendMessage"
+ android:id="@+id/button1"/>
+
+ <Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@+id/button1"
+ android:onClick="sendMessage"
+ android:id="@+id/button2"/>
+
+ <Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@+id/button2"
+ android:onClick="sendMessage"
+ android:id="@+id/button3"/>
+
+
+</RelativeLayout> \ No newline at end of file
diff --git a/tests/TransitionTests/res/layout/list_view_add_remove.xml b/tests/TransitionTests/res/layout/list_view_add_remove.xml
new file mode 100644
index 0000000..230511f
--- /dev/null
+++ b/tests/TransitionTests/res/layout/list_view_add_remove.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:id="@+id/container"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <ListView
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:id="@+id/listview"/>
+
+</LinearLayout> \ No newline at end of file
diff --git a/tests/TransitionTests/res/layout/login_password.xml b/tests/TransitionTests/res/layout/login_password.xml
new file mode 100644
index 0000000..1e75694
--- /dev/null
+++ b/tests/TransitionTests/res/layout/login_password.xml
@@ -0,0 +1,86 @@
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:id="@+id/container"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ tools:context=".LoginActivity" >
+
+ <TextView
+ android:id="@+id/password"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignRight="@+id/username"
+ android:layout_below="@+id/username"
+ android:layout_marginTop="30dp"
+ android:text="@string/password"
+ android:textAppearance="?android:attr/textAppearanceLarge" />
+
+ <EditText
+ android:id="@+id/usernameEdit"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignTop="@+id/username"
+ android:layout_marginLeft="14dp"
+ android:layout_toRightOf="@+id/username"
+ android:ems="10" />
+
+ <TextView
+ android:id="@+id/username"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentLeft="true"
+ android:layout_alignParentTop="true"
+ android:layout_marginLeft="20dp"
+ android:layout_marginTop="51dp"
+ android:text="@string/username"
+ android:textAppearance="?android:attr/textAppearanceLarge" />
+
+ <EditText
+ android:id="@+id/passwordEdit"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignBaseline="@+id/password"
+ android:layout_alignBottom="@+id/password"
+ android:layout_alignLeft="@+id/usernameEdit"
+ android:layout_alignParentRight="true"
+ android:ems="10" >
+
+ <requestFocus />
+ </EditText>
+
+ <Button
+ android:id="@+id/cancel"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentBottom="true"
+ android:layout_marginBottom="14dp"
+ android:layout_toLeftOf="@+id/passwordEdit"
+ android:onClick="sendMessage"
+ android:text="@string/cancel" />
+
+ <Button
+ android:id="@+id/submit"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignBaseline="@+id/cancel"
+ android:layout_alignBottom="@+id/cancel"
+ android:layout_alignLeft="@+id/passwordEdit"
+ android:layout_marginLeft="41dp"
+ android:onClick="sendMessage"
+ android:text="@string/submit" />
+
+ <TextView
+ android:id="@+id/newuser"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@+id/passwordEdit"
+ android:layout_centerHorizontal="true"
+ android:layout_marginTop="16dp"
+ android:textColor="#0000ff"
+ android:text="@string/new_user"
+ android:clickable="true"
+ android:onClick="sendMessage"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textStyle="italic" />
+
+</RelativeLayout> \ No newline at end of file
diff --git a/tests/TransitionTests/res/layout/main.xml b/tests/TransitionTests/res/layout/main.xml
new file mode 100644
index 0000000..b42318e
--- /dev/null
+++ b/tests/TransitionTests/res/layout/main.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:id="@+id/container">
+ <Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:id="@+id/button"/>
+</LinearLayout> \ No newline at end of file
diff --git a/tests/TransitionTests/res/layout/new_user.xml b/tests/TransitionTests/res/layout/new_user.xml
new file mode 100644
index 0000000..f8dfab0
--- /dev/null
+++ b/tests/TransitionTests/res/layout/new_user.xml
@@ -0,0 +1,92 @@
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:id="@+id/container"
+ tools:context=".LoginActivity" >
+
+ <TextView
+ android:id="@+id/password"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignRight="@+id/username"
+ android:layout_below="@+id/username"
+ android:layout_marginTop="30dp"
+ android:text="@string/password"
+ android:textAppearance="?android:attr/textAppearanceLarge" />
+
+ <EditText
+ android:id="@+id/usernameEdit"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignTop="@+id/username"
+ android:layout_marginLeft="14dp"
+ android:layout_toRightOf="@+id/username"
+ android:ems="10" />
+
+ <TextView
+ android:id="@+id/username"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentLeft="true"
+ android:layout_alignParentTop="true"
+ android:layout_marginLeft="20dp"
+ android:layout_marginTop="51dp"
+ android:text="@string/username"
+ android:textAppearance="?android:attr/textAppearanceLarge" />
+
+ <EditText
+ android:id="@+id/passwordEdit"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignBaseline="@+id/password"
+ android:layout_alignBottom="@+id/password"
+ android:layout_alignLeft="@+id/usernameEdit"
+ android:layout_alignParentRight="true"
+ android:ems="10" >
+
+ <requestFocus />
+ </EditText>
+
+ <Button
+ android:id="@+id/cancel"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentBottom="true"
+ android:layout_marginBottom="14dp"
+ android:layout_toLeftOf="@+id/passwordEdit"
+ android:onClick="sendMessage"
+ android:text="@string/cancel" />
+
+ <Button
+ android:id="@+id/submit"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignBaseline="@+id/cancel"
+ android:layout_alignBottom="@+id/cancel"
+ android:layout_alignLeft="@+id/passwordEdit"
+ android:layout_marginLeft="41dp"
+ android:onClick="sendMessage"
+ android:text="@string/submit" />
+
+ <EditText
+ android:id="@+id/retypeEdit"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignBaseline="@+id/retype"
+ android:layout_alignBottom="@+id/retype"
+ android:layout_alignLeft="@+id/passwordEdit"
+ android:layout_alignParentRight="true"
+ android:ems="10" />
+
+ <TextView
+ android:id="@+id/retype"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@+id/passwordEdit"
+ android:layout_marginTop="26dp"
+ android:layout_toLeftOf="@+id/usernameEdit"
+ android:text="@string/retype"
+ android:textAppearance="?android:attr/textAppearanceLarge" />
+
+</RelativeLayout> \ No newline at end of file
diff --git a/tests/TransitionTests/res/layout/overlay_test.xml b/tests/TransitionTests/res/layout/overlay_test.xml
new file mode 100644
index 0000000..edd0393
--- /dev/null
+++ b/tests/TransitionTests/res/layout/overlay_test.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:id="@+id/container"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent">
+
+ <Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:id="@+id/button"
+ android:text="@string/start"
+ android:onClick="onClick"/>
+
+ <Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/fadingButton"
+ android:id="@+id/fadingButton"/>
+
+</LinearLayout> \ No newline at end of file
diff --git a/tests/TransitionTests/res/layout/reparenting.xml b/tests/TransitionTests/res/layout/reparenting.xml
new file mode 100644
index 0000000..b3bfbb9
--- /dev/null
+++ b/tests/TransitionTests/res/layout/reparenting.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:id="@+id/container">
+ <LinearLayout
+ android:orientation="horizontal"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:id="@+id/container1"/>
+ <LinearLayout
+ android:orientation="vertical"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:id="@+id/container2"/>
+</LinearLayout> \ No newline at end of file
diff --git a/tests/TransitionTests/res/layout/resources_test_layout.xml b/tests/TransitionTests/res/layout/resources_test_layout.xml
new file mode 100644
index 0000000..48affa0
--- /dev/null
+++ b/tests/TransitionTests/res/layout/resources_test_layout.xml
@@ -0,0 +1,3 @@
+<?xml version="1.0" encoding="utf-8"?>
+<ImageView
+ src="@drawable/icon"/> \ No newline at end of file
diff --git a/tests/TransitionTests/res/layout/results_screen.xml b/tests/TransitionTests/res/layout/results_screen.xml
new file mode 100644
index 0000000..8550a5e
--- /dev/null
+++ b/tests/TransitionTests/res/layout/results_screen.xml
@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:background="#7f7f7f"
+ android:id="@+id/container">
+ <LinearLayout android:orientation="horizontal"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="top|right"
+ android:id="@+id/searchContainer">
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/searchText"
+ android:id="@+id/searchText"/>
+ <Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/searchButton"
+ android:onClick="sendMessage"
+ android:id="@+id/searchButton"/>
+ </LinearLayout>
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:text="@string/resultsTitle"
+ android:id="@+id/resultsText"/>
+ <LinearLayout android:layout_width="match_parent"
+ android:layout_height="0dip"
+ android:layout_weight="1"
+ android:orientation="vertical"
+ android:id="@+id/resultsList">
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/placeholder"/>
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/placeholder"/>
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/placeholder"/>
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/placeholder"/>
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/placeholder"/>
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/placeholder"/>
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/placeholder"/>
+
+ </LinearLayout>
+</LinearLayout> \ No newline at end of file
diff --git a/tests/TransitionTests/res/layout/search_screen.xml b/tests/TransitionTests/res/layout/search_screen.xml
new file mode 100644
index 0000000..947702b
--- /dev/null
+++ b/tests/TransitionTests/res/layout/search_screen.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:background="#000000"
+ android:id="@+id/container">
+ <LinearLayout android:orientation="horizontal"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:id="@+id/searchContainer">
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/searchText"
+ android:id="@+id/searchText"/>
+ <Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/searchButton"
+ android:onClick="sendMessage"
+ android:id="@+id/searchButton"/>
+ </LinearLayout>
+</LinearLayout> \ No newline at end of file
diff --git a/tests/TransitionTests/res/layout/success.xml b/tests/TransitionTests/res/layout/success.xml
new file mode 100644
index 0000000..9c265ef
--- /dev/null
+++ b/tests/TransitionTests/res/layout/success.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/container"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" >
+
+ <TextView
+ android:id="@+id/loginsuccessful"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_centerHorizontal="true"
+ android:layout_marginBottom="93dp"
+ android:text="@string/login_successful"
+ android:textAppearance="?android:attr/textAppearanceLarge" />
+
+ <TextView
+ android:id="@+id/firstactivityscreen"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignTop="@+id/loginsuccessful"
+ android:layout_centerHorizontal="true"
+ android:layout_marginTop="35dp"
+ android:text="@string/first_activity_screen"
+ android:textAppearance="?android:attr/textAppearanceLarge" />
+
+ <Button
+ android:id="@+id/reset"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentBottom="true"
+ android:layout_centerHorizontal="true"
+ android:layout_marginBottom="164dp"
+ android:onClick="sendMessage"
+ android:text="@string/reset" />
+
+</RelativeLayout> \ No newline at end of file
diff --git a/tests/TransitionTests/res/layout/surface_texture_views.xml b/tests/TransitionTests/res/layout/surface_texture_views.xml
new file mode 100644
index 0000000..9260bc0
--- /dev/null
+++ b/tests/TransitionTests/res/layout/surface_texture_views.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:id="@+id/container"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <Button
+ android:text="@string/toggle"
+ android:id="@+id/toggleButton"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"/>
+
+</LinearLayout> \ No newline at end of file
diff --git a/tests/TransitionTests/res/layout/unique_id_test.xml b/tests/TransitionTests/res/layout/unique_id_test.xml
new file mode 100644
index 0000000..9b7eb10
--- /dev/null
+++ b/tests/TransitionTests/res/layout/unique_id_test.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:id="@+id/container"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+</LinearLayout> \ No newline at end of file
diff --git a/tests/TransitionTests/res/layout/username_taken.xml b/tests/TransitionTests/res/layout/username_taken.xml
new file mode 100644
index 0000000..9484e69
--- /dev/null
+++ b/tests/TransitionTests/res/layout/username_taken.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/container"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" >
+
+ <Button
+ android:id="@+id/okay"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentBottom="true"
+ android:layout_centerHorizontal="true"
+ android:layout_marginBottom="164dp"
+ android:onClick="sendMessage"
+ android:text="@string/okay" />
+
+ <TextView
+ android:id="@+id/usernametaken"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_above="@+id/okay"
+ android:layout_centerHorizontal="true"
+ android:layout_marginBottom="93dp"
+ android:text="@string/username_taken"
+ android:textAppearance="?android:attr/textAppearanceLarge" />
+
+ <TextView
+ android:id="@+id/textView2"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignTop="@+id/usernametaken"
+ android:layout_centerHorizontal="true"
+ android:layout_marginTop="35dp"
+ android:text="@string/try_again"
+ android:textAppearance="?android:attr/textAppearanceLarge" />
+
+</RelativeLayout> \ No newline at end of file
diff --git a/tests/TransitionTests/res/scene/incorrect_password_scene.xml b/tests/TransitionTests/res/scene/incorrect_password_scene.xml
new file mode 100644
index 0000000..a31ad22
--- /dev/null
+++ b/tests/TransitionTests/res/scene/incorrect_password_scene.xml
@@ -0,0 +1,2 @@
+<scene xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout="@layout/incorrect_password"/> \ No newline at end of file
diff --git a/tests/TransitionTests/res/scene/login_scene.xml b/tests/TransitionTests/res/scene/login_scene.xml
new file mode 100644
index 0000000..b258303
--- /dev/null
+++ b/tests/TransitionTests/res/scene/login_scene.xml
@@ -0,0 +1,2 @@
+<scene xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout="@layout/activity_login"/> \ No newline at end of file
diff --git a/tests/TransitionTests/res/scene/my_scene.xml b/tests/TransitionTests/res/scene/my_scene.xml
new file mode 100644
index 0000000..b8278c9
--- /dev/null
+++ b/tests/TransitionTests/res/scene/my_scene.xml
@@ -0,0 +1,3 @@
+<scene >
+
+</scene> \ No newline at end of file
diff --git a/tests/TransitionTests/res/scene/new_user_scene.xml b/tests/TransitionTests/res/scene/new_user_scene.xml
new file mode 100644
index 0000000..d6e5f0f
--- /dev/null
+++ b/tests/TransitionTests/res/scene/new_user_scene.xml
@@ -0,0 +1,2 @@
+<scene xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout="@layout/new_user"/> \ No newline at end of file
diff --git a/tests/TransitionTests/res/scene/password_scene.xml b/tests/TransitionTests/res/scene/password_scene.xml
new file mode 100644
index 0000000..99a0038
--- /dev/null
+++ b/tests/TransitionTests/res/scene/password_scene.xml
@@ -0,0 +1,2 @@
+<scene xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout="@layout/login_password"/> \ No newline at end of file
diff --git a/tests/TransitionTests/res/scene/results_scene.xml b/tests/TransitionTests/res/scene/results_scene.xml
new file mode 100644
index 0000000..9c9fc69
--- /dev/null
+++ b/tests/TransitionTests/res/scene/results_scene.xml
@@ -0,0 +1,3 @@
+<scene xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout="@layout/results_screen">
+</scene> \ No newline at end of file
diff --git a/tests/TransitionTests/res/scene/search_scene.xml b/tests/TransitionTests/res/scene/search_scene.xml
new file mode 100644
index 0000000..742cd57
--- /dev/null
+++ b/tests/TransitionTests/res/scene/search_scene.xml
@@ -0,0 +1,3 @@
+<scene xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout="@layout/search_screen">
+</scene> \ No newline at end of file
diff --git a/tests/TransitionTests/res/scene/success_scene.xml b/tests/TransitionTests/res/scene/success_scene.xml
new file mode 100644
index 0000000..3d76d89
--- /dev/null
+++ b/tests/TransitionTests/res/scene/success_scene.xml
@@ -0,0 +1,2 @@
+<scene xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout="@layout/success"/> \ No newline at end of file
diff --git a/tests/TransitionTests/res/scene/username_taken_scene.xml b/tests/TransitionTests/res/scene/username_taken_scene.xml
new file mode 100644
index 0000000..b2f050e
--- /dev/null
+++ b/tests/TransitionTests/res/scene/username_taken_scene.xml
@@ -0,0 +1,2 @@
+<scene xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout="@layout/username_taken"/> \ No newline at end of file
diff --git a/tests/TransitionTests/res/transition/colorizer_transition.xml b/tests/TransitionTests/res/transition/colorizer_transition.xml
new file mode 100644
index 0000000..731d7ee
--- /dev/null
+++ b/tests/TransitionTests/res/transition/colorizer_transition.xml
@@ -0,0 +1,6 @@
+<recolor xmlns:android="http://schemas.android.com/apk/res/android">>
+ <targets>
+ <target android:targetID="@id/password"/>
+ <target android:targetID="@id/passwordEdit"/>
+ </targets>
+</recolor> \ No newline at end of file
diff --git a/tests/TransitionTests/res/transition/fader.xml b/tests/TransitionTests/res/transition/fader.xml
new file mode 100644
index 0000000..c71fd94
--- /dev/null
+++ b/tests/TransitionTests/res/transition/fader.xml
@@ -0,0 +1 @@
+<fade/> \ No newline at end of file
diff --git a/tests/TransitionTests/res/transition/login_slider_transition.xml b/tests/TransitionTests/res/transition/login_slider_transition.xml
new file mode 100644
index 0000000..dbdd6e9
--- /dev/null
+++ b/tests/TransitionTests/res/transition/login_slider_transition.xml
@@ -0,0 +1,22 @@
+<transitionGroup xmlns:android="http://schemas.android.com/apk/res/android">
+ <slide>
+ <targets>
+ <target android:targetID="@id/retype"/>
+ <target android:targetID="@id/retypeEdit"/>
+ </targets>
+ </slide>
+ <recolor>
+ <targets>
+ <target android:targetID="@id/password"/>
+ <target android:targetID="@id/passwordEdit"/>
+ </targets>
+ </recolor>
+ <fade/>
+</transitionGroup>
+
+<!--
+ TransitionGroup slider = new TransitionGroup();
+ slider.addTransition(new Slide(R.id.retype, R.id.retypeEdit));
+ slider.addTransition(new Recolor(R.id.password, R.id.passwordEdit));
+ slider.addTransition(new Fade());
+--> \ No newline at end of file
diff --git a/tests/TransitionTests/res/transition/login_transition_mgr.xml b/tests/TransitionTests/res/transition/login_transition_mgr.xml
new file mode 100644
index 0000000..8a8b9e9
--- /dev/null
+++ b/tests/TransitionTests/res/transition/login_transition_mgr.xml
@@ -0,0 +1,39 @@
+<transitionManager xmlns:android="http://schemas.android.com/apk/res/android">
+ <transition fromScene="@scene/login_scene" toScene="@scene/new_user_scene"
+ transition="@transition/login_slider_transition"/>
+ <transition fromScene="@scene/password_scene" toScene="@scene/new_user_scene"
+ transition="@transition/login_slider_transition"/>
+ <transition fromScene="@scene/new_user_scene" toScene="@scene/login_scene"
+ transition="@transition/login_slider_transition"/>
+ <transition fromScene="@scene/new_user_scene" toScene="@scene/password_scene"
+ transition="@transition/login_slider_transition"/>
+ <transition fromScene="@scene/login_scene" toScene="@scene/password_scene"
+ transition="@transition/colorizer_transition"/>
+ <transition fromScene="@scene/password_scene" toScene="@scene/login_scene"
+ transition="@transition/colorizer_transition"/>
+</transitionManager>
+
+ <!--
+ mLoginScene = new Scene(this, mSceneRoot, R.layout.activity_login);
+ mPasswordScene = new Scene(this, mSceneRoot, R.layout.login_password);
+ mIncorrectPasswordScene = new Scene(this, mSceneRoot, R.layout.incorrect_password);
+ mUsernameTakenScene = new Scene(this, mSceneRoot, R.layout.username_taken);
+ mSuccessScene = new Scene(this, mSceneRoot, R.layout.success);
+ mNewUserScene = new Scene(this, mSceneRoot, R.layout.new_user);
+
+ mTransitionManager = new TransitionManager();
+ // Custom transitions in/out of NewUser screen - slide in the 2nd password UI
+ TransitionGroup slider = new TransitionGroup();
+ slider.addTransition(new Slide(R.id.retype, R.id.retypeEdit));
+ slider.addTransition(new Recolor(R.id.password, R.id.passwordEdit));
+ slider.addTransition(new Fade());
+ mTransitionManager.setTransition(mLoginScene, mNewUserScene, slider);
+ mTransitionManager.setTransition(mPasswordScene, mNewUserScene, slider);
+ mTransitionManager.setTransition(mNewUserScene, mLoginScene, slider);
+ mTransitionManager.setTransition(mNewUserScene, mPasswordScene, slider);
+
+ // Custom transitions with recoloring password field
+ Transition colorizer = new Recolor(R.id.password, R.id.passwordEdit);
+ mTransitionManager.setTransition(mLoginScene, mPasswordScene, colorizer);
+ mTransitionManager.setTransition(mPasswordScene, mLoginScene, colorizer);
+--> \ No newline at end of file
diff --git a/tests/TransitionTests/res/transition/mover.xml b/tests/TransitionTests/res/transition/mover.xml
new file mode 100644
index 0000000..3c47606
--- /dev/null
+++ b/tests/TransitionTests/res/transition/mover.xml
@@ -0,0 +1 @@
+<move/> \ No newline at end of file
diff --git a/tests/TransitionTests/res/transition/mover_fader.xml b/tests/TransitionTests/res/transition/mover_fader.xml
new file mode 100644
index 0000000..8b805e9
--- /dev/null
+++ b/tests/TransitionTests/res/transition/mover_fader.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<transitionGroup xmlns:android="http://schemas.android.com/apk/res/android">
+ <fade/>
+ <move/>
+</transitionGroup> \ No newline at end of file
diff --git a/tests/TransitionTests/res/transition/my_transition.xml b/tests/TransitionTests/res/transition/my_transition.xml
new file mode 100644
index 0000000..14c91b9
--- /dev/null
+++ b/tests/TransitionTests/res/transition/my_transition.xml
@@ -0,0 +1,20 @@
+<transitionGroup xmlns:android="http://schemas.android.com/apk/res/android">
+ <fade></fade>
+ <transitionGroup>
+ <move android:duration="500">
+ <targets>
+ <target android:targetID="@id/container"/>
+ <target android:targetID="@id/resultsList"/>
+ </targets>
+ </move>
+ <transitionGroup>
+ <targets>
+ <target android:targetID="@id/container"/>
+ <target android:targetID="@id/resultsList"/>
+ </targets>
+ <fade android:startOffset="25"/>
+ </transitionGroup>
+ <recolor/>
+ </transitionGroup>
+ <move/>
+</transitionGroup> \ No newline at end of file
diff --git a/tests/TransitionTests/res/transition/my_transition_mgr.xml b/tests/TransitionTests/res/transition/my_transition_mgr.xml
new file mode 100644
index 0000000..ca9705a
--- /dev/null
+++ b/tests/TransitionTests/res/transition/my_transition_mgr.xml
@@ -0,0 +1,6 @@
+<transitionManager xmlns:android="http://schemas.android.com/apk/res/android">
+ <transition fromScene="@scene/search_scene" toScene="@scene/results_scene"
+ transition="@transition/mover_fader"/>
+ <transition fromScene="@scene/results_scene" toScene="@scene/search_scene"
+ transition="@transition/mover_fader"/>
+</transitionManager> \ No newline at end of file
diff --git a/tests/TransitionTests/res/values-v11/styles.xml b/tests/TransitionTests/res/values-v11/styles.xml
new file mode 100644
index 0000000..541752f
--- /dev/null
+++ b/tests/TransitionTests/res/values-v11/styles.xml
@@ -0,0 +1,11 @@
+<resources>
+
+ <!--
+ Base application theme for API 11+. This theme completely replaces
+ AppBaseTheme from res/values/styles.xml on API 11+ devices.
+ -->
+ <style name="AppBaseTheme" parent="android:Theme.Holo.Light">
+ <!-- API 11 theme customizations can go here. -->
+ </style>
+
+</resources> \ No newline at end of file
diff --git a/tests/TransitionTests/res/values-v14/styles.xml b/tests/TransitionTests/res/values-v14/styles.xml
new file mode 100644
index 0000000..f20e015
--- /dev/null
+++ b/tests/TransitionTests/res/values-v14/styles.xml
@@ -0,0 +1,12 @@
+<resources>
+
+ <!--
+ Base application theme for API 14+. This theme completely replaces
+ AppBaseTheme from BOTH res/values/styles.xml and
+ res/values-v11/styles.xml on API 14+ devices.
+ -->
+ <style name="AppBaseTheme" parent="android:Theme.Holo.Light.DarkActionBar">
+ <!-- API 14 theme customizations can go here. -->
+ </style>
+
+</resources> \ No newline at end of file
diff --git a/tests/TransitionTests/res/values/strings.xml b/tests/TransitionTests/res/values/strings.xml
new file mode 100644
index 0000000..e251d5c
--- /dev/null
+++ b/tests/TransitionTests/res/values/strings.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="app_name">StatesTest</string>
+ <string name="states_test1">StatesTestv21</string>
+ <string name="states_test_auto_targets">StatesTestAutoTargets</string>
+ <string name="states_test_auto_transition">StatesTestAutoTransition</string>
+ <string name="states_test_auto_transition2">StatesTestAutoTransition2</string>
+ <string name="contacts_expansion">ContactsExpansion</string>
+ <string name="states_test3">StatesTest3</string>
+ <string name="states_test4">StatesTest4</string>
+ <string name="states_test5">StatesTest5</string>
+ <string name="states_test6">StatesTest6</string>
+ <string name="button">Button</string>
+ <string name="searchButton">Search</string>
+ <string name="searchText">This is some text</string>
+ <string name="resultsTitle">Search Results</string>
+ <string name="placeholder">Blah Blah Blah</string>
+ <string name="username">Username:</string>
+ <string name="password">Password:</string>
+ <string name="retype">Retype:</string>
+ <string name="new_user">New User?</string>
+ <string name="incorrect_password">Incorrect password:</string>
+ <string name="try_again">Please try again.</string>
+ <string name="login_successful">Success!</string>
+ <string name="first_activity_screen">First activity screen</string>
+ <string name="username_taken">Username taken:</string>
+ <string name="cancel">Cancel</string>
+ <string name="submit">Submit</string>
+ <string name="okay">Okay</string>
+ <string name="reset">Reset</string>
+ <string name="fadingButton">Fading Button</string>
+ <string name="removingButton">Removing Button</string>
+ <string name="invisibleButton">invisible Button</string>
+ <string name="goneButton">Gone Button</string>
+ <string name="start">Start</string>
+ <string name="toggle">Toggle State</string>
+ <string name="someText">This is some text</string>
+ <string name="shortText1">This is some short text</string>
+ <string name="shortText2">Not much text here</string>
+ <string name="longText1">This is the beginning of the Spring of my discontent. In the event of a real emergency, you would be notified by email. Fear not, for death comes swiftly.</string>
+ <string name="longText2">When do we get to eat? I like all things, especially following strong leaders, and mangy cats. Break glass in emergency. The purpose of a framework is to provide the facilities and functionality of a powerful toolkit with the simplicity of a refrigerator.</string>
+</resources>
diff --git a/tests/TransitionTests/res/values/styles.xml b/tests/TransitionTests/res/values/styles.xml
new file mode 100644
index 0000000..4a10ca4
--- /dev/null
+++ b/tests/TransitionTests/res/values/styles.xml
@@ -0,0 +1,20 @@
+<resources>
+
+ <!--
+ Base application theme, dependent on API level. This theme is replaced
+ by AppBaseTheme from res/values-vXX/styles.xml on newer devices.
+ -->
+ <style name="AppBaseTheme" parent="android:Theme.Light">
+ <!--
+ Theme customizations available in newer API levels can go in
+ res/values-vXX/styles.xml, while customizations related to
+ backward-compatibility can go here.
+ -->
+ </style>
+
+ <!-- Application theme. -->
+ <style name="AppTheme" parent="AppBaseTheme">
+ <!-- All customizations that are NOT specific to a particular API-level can go here. -->
+ </style>
+
+</resources> \ No newline at end of file
diff --git a/tests/TransitionTests/src/com/android/transitiontests/ChangingText.java b/tests/TransitionTests/src/com/android/transitiontests/ChangingText.java
new file mode 100644
index 0000000..ed9b46a
--- /dev/null
+++ b/tests/TransitionTests/src/com/android/transitiontests/ChangingText.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2013 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 com.android.transitiontests;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.transition.Scene;
+import android.widget.Button;
+import android.view.transition.Fade;
+import android.view.transition.Move;
+import android.view.transition.TextChange;
+import android.view.transition.TransitionGroup;
+import android.view.transition.TransitionManager;
+import com.android.transitiontest.R;
+
+public class ChangingText extends Activity {
+
+ Button mRemovingButton, mInvisibleButton, mGoneButton;
+ Scene mScene1, mScene2;
+ ViewGroup mSceneRoot;
+ Fade fader;
+ TransitionGroup mChanger;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.changing_text_1);
+
+ View container = (View) findViewById(R.id.container);
+ mSceneRoot = (ViewGroup) container.getParent();
+
+ mScene1 = new Scene(mSceneRoot, R.layout.changing_text_1, this);
+ mScene2 = new Scene(mSceneRoot, R.layout.changing_text_2, this);
+
+ mChanger = new TransitionGroup(TransitionGroup.TOGETHER);
+ mChanger.addTransitions(new Move(), new TextChange());
+
+ mSceneRoot.setCurrentScene(mScene1);
+ }
+
+ public void sendMessage(View view) {
+ if (mSceneRoot.getCurrentScene() == mScene1) {
+ TransitionManager.go(mScene2, mChanger);
+ } else {
+ TransitionManager.go(mScene1, mChanger);
+ }
+ }
+}
diff --git a/tests/TransitionTests/src/com/android/transitiontests/ClippingText.java b/tests/TransitionTests/src/com/android/transitiontests/ClippingText.java
new file mode 100644
index 0000000..0ecf1f4
--- /dev/null
+++ b/tests/TransitionTests/src/com/android/transitiontests/ClippingText.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2013 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 com.android.transitiontests;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.transition.Scene;
+import android.widget.Button;
+import android.view.transition.Fade;
+import android.view.transition.Move;
+import android.view.transition.TextChange;
+import android.view.transition.TransitionGroup;
+import android.view.transition.TransitionManager;
+import com.android.transitiontest.R;
+
+public class ClippingText extends Activity {
+
+ Button mRemovingButton, mInvisibleButton, mGoneButton;
+ Scene mScene1, mScene2;
+ ViewGroup mSceneRoot;
+ // static Fade sFade = new Fade(R.id.removingButton, R.id.invisibleButton, R.id.goneButton);
+ Fade fader;
+ TransitionGroup mChanger;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.clipping_text_1);
+
+ View container = (View) findViewById(R.id.container);
+ mSceneRoot = (ViewGroup) container.getParent();
+
+ mScene1 = new Scene(mSceneRoot, R.layout.clipping_text_1, this);
+ mScene2 = new Scene(mSceneRoot, R.layout.clipping_text_2, this);
+
+ mChanger = new TransitionGroup(TransitionGroup.TOGETHER);
+ Move move = new Move();
+ move.setResizeClip(true);
+ mChanger.addTransitions(move, new TextChange());
+
+ mSceneRoot.setCurrentScene(mScene1);
+ }
+
+ public void sendMessage(View view) {
+ if (mSceneRoot.getCurrentScene() == mScene1) {
+ TransitionManager.go(mScene2, mChanger);
+ } else {
+ TransitionManager.go(mScene1, mChanger);
+ }
+ }
+}
diff --git a/tests/TransitionTests/src/com/android/transitiontests/ContactsExpansion.java b/tests/TransitionTests/src/com/android/transitiontests/ContactsExpansion.java
new file mode 100644
index 0000000..55a96a5
--- /dev/null
+++ b/tests/TransitionTests/src/com/android/transitiontests/ContactsExpansion.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2013 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 com.android.transitiontests;
+
+import android.app.Activity;
+import android.content.Context;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.transition.Fade;
+import android.view.transition.Scene;
+import android.view.transition.Transition;
+import android.widget.ImageView;
+import android.widget.TextView;
+import android.view.transition.Crossfade;
+import android.view.transition.Move;
+import android.view.transition.Rotate;
+import android.view.transition.TransitionGroup;
+import android.view.transition.TransitionManager;
+import com.android.transitiontest.R;
+
+public class ContactsExpansion extends Activity {
+
+ String contactsData[] = {
+ "Alan Green", "56 Bob Street", "Boston, MA 02134", "617-555-5555", "blatt@blatt.com",
+ "Bob Foonman", "92 The Avenue", "Chico, CA 78456", "510-555-5556", "bob@jerk.com",
+ "Tracey Sue", "95 Houses Street", "San Jose, CA 96504", "415-555-5557", "ts@thing.com",
+ };
+
+ View currentItem = null;
+
+ TransitionGroup mMyAutoTransition = new TransitionGroup(TransitionGroup.SEQUENTIALLY);
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.contacts_list);
+ ViewGroup contactsContainer = (ViewGroup) findViewById(R.id.contactsContainer);
+
+ int contactsIndex = 0;
+ addContact(contactsContainer, contactsIndex, R.drawable.self_portrait_square_100);
+ contactsIndex += 5;
+ addContact(contactsContainer, contactsIndex, R.drawable.self_portrait_square_100);
+ contactsIndex += 5;
+ addContact(contactsContainer, contactsIndex, R.drawable.self_portrait_square_100);
+
+ }
+
+ private void addContact(ViewGroup container, int dataIndex, int thumbnailID) {
+ LayoutInflater inflater = (LayoutInflater)
+ getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ View contactItem = inflater.inflate(R.layout.contact_collapsed, container, false);
+ ImageView thumbnailView = (ImageView) contactItem.findViewById(R.id.contact_picture);
+ thumbnailView.setImageResource(thumbnailID);
+ ((TextView)contactItem.findViewById(R.id.contact_name)).setText(contactsData[dataIndex++]);
+ ((TextView)contactItem.findViewById(R.id.contact_street)).
+ setText(contactsData[dataIndex++]);
+ ((TextView)contactItem.findViewById(R.id.contact_city)).setText(contactsData[dataIndex++]);
+ ((TextView)contactItem.findViewById(R.id.contact_phone)).setText(contactsData[dataIndex++]);
+ ((TextView)contactItem.findViewById(R.id.contact_email)).setText(contactsData[dataIndex++]);
+ container.addView(contactItem);
+
+ final TransitionGroup myTransition = new TransitionGroup();
+ myTransition.addTransitions(new Fade(Fade.IN),
+ new Rotate().setTargetIds(R.id.contact_arrow),
+ new Move(), new Fade(Fade.OUT),
+ new Crossfade().setTargetIds(R.id.contact_picture));
+ final ToggleScene toggleScene = new ToggleScene(container, myTransition);
+ contactItem.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ currentItem = v;
+ toggleScene.changeToScene();
+ }
+ });
+ }
+
+ class ToggleScene {
+ boolean expanded = false;
+ Scene mScene;
+ Transition mTransition;
+
+ ToggleScene(ViewGroup rootView, Transition transition) {
+ mScene = new Scene(rootView);
+ mTransition = transition;
+ mScene.setEnterAction(new Runnable() {
+ @Override
+ public void run() {
+ if (currentItem != null) {
+ System.out.println("onsceneChanged: currentItem = " + currentItem);
+ View expandedContainer = currentItem.findViewById(R.id.expanded_info);
+ expandedContainer.setVisibility(expanded ? View.GONE : View.VISIBLE);
+ ImageView thumbnailView =
+ (ImageView) currentItem.findViewById(R.id.contact_picture);
+ thumbnailView.setImageResource(expanded ? R.drawable.self_portrait_square_100 :
+ R.drawable.self_portrait_square_200);
+ ImageView arrow = (ImageView) currentItem.findViewById(R.id.contact_arrow);
+ arrow.setRotation(expanded ? 0 : 90);
+ expanded = !expanded;
+ }
+ }
+ });
+ }
+
+ void changeToScene() {
+ TransitionManager.go(mScene, mTransition);
+ }
+ };
+}
diff --git a/tests/TransitionTests/src/com/android/transitiontests/CrossFadeDemo.java b/tests/TransitionTests/src/com/android/transitiontests/CrossFadeDemo.java
new file mode 100644
index 0000000..c428a73
--- /dev/null
+++ b/tests/TransitionTests/src/com/android/transitiontests/CrossFadeDemo.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2013 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 com.android.transitiontests;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.transition.Crossfade;
+import android.view.transition.Move;
+import android.view.transition.Scene;
+import android.view.transition.TransitionGroup;
+import android.view.transition.TransitionManager;
+import com.android.transitiontest.R;
+
+
+public class CrossFadeDemo extends Activity {
+
+ ViewGroup mSceneRoot;
+ static int mCurrentScene;
+ Scene mScene1, mScene2;
+ TransitionManager mTransitionManager;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.crossfade);
+
+ View container = (View) findViewById(R.id.container);
+ mSceneRoot = (ViewGroup) container.getParent();
+
+ mScene1 = new Scene(mSceneRoot, R.layout.crossfade, this);
+ mScene2 = new Scene(mSceneRoot, R.layout.crossfade_1, this);
+
+ Crossfade crossfade = new Crossfade();
+ crossfade.setTargetIds(R.id.textview, R.id.textview1, R.id.textview2);
+ mTransitionManager = new TransitionManager();
+ TransitionGroup moveCrossFade = new TransitionGroup();
+ moveCrossFade.addTransitions(crossfade, new Move());
+ mTransitionManager.setTransition(mScene1, moveCrossFade);
+ mTransitionManager.setTransition(mScene2, moveCrossFade);
+ mCurrentScene = 1;
+ }
+
+ public void sendMessage(View view) {
+ if (mCurrentScene == 1) {
+ mTransitionManager.transitionTo(mScene2);
+ mCurrentScene = 2;
+ } else {
+ mTransitionManager.transitionTo(mScene1);
+ mCurrentScene = 1;
+ }
+ }
+}
diff --git a/tests/TransitionTests/src/com/android/transitiontests/Demo0.java b/tests/TransitionTests/src/com/android/transitiontests/Demo0.java
new file mode 100644
index 0000000..55bf956
--- /dev/null
+++ b/tests/TransitionTests/src/com/android/transitiontests/Demo0.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2013 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 com.android.transitiontests;
+
+import android.app.Activity;
+import android.content.Context;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import com.android.transitiontest.R;
+
+
+public class Demo0 extends Activity {
+
+ private static final int SEARCH_SCREEN = 0;
+ private static final int RESULTS_SCREEN = 1;
+ ViewGroup mSceneRoot;
+ static int mCurrentScene;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.search_screen);
+
+ View container = (View) findViewById(R.id.container);
+ mSceneRoot = (ViewGroup) container.getParent();
+
+ mCurrentScene = SEARCH_SCREEN;
+ }
+
+ public void sendMessage(View view) {
+ if (mCurrentScene == RESULTS_SCREEN) {
+ mSceneRoot.removeAllViews();
+ LayoutInflater inflater = (LayoutInflater)
+ getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ inflater.inflate(R.layout.search_screen, mSceneRoot);
+ mCurrentScene = SEARCH_SCREEN;
+ } else {
+ mSceneRoot.removeAllViews();
+ LayoutInflater inflater = (LayoutInflater)
+ getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ inflater.inflate(R.layout.results_screen, mSceneRoot);
+ mCurrentScene = RESULTS_SCREEN;
+ }
+ }
+}
diff --git a/tests/TransitionTests/src/com/android/transitiontests/Demo1.java b/tests/TransitionTests/src/com/android/transitiontests/Demo1.java
new file mode 100644
index 0000000..360a764
--- /dev/null
+++ b/tests/TransitionTests/src/com/android/transitiontests/Demo1.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2013 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 com.android.transitiontests;
+
+import android.app.Activity;
+import android.content.Context;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.transition.Fade;
+import android.view.transition.Move;
+import android.view.transition.Scene;
+import android.view.transition.TransitionGroup;
+import android.view.transition.TransitionManager;
+import com.android.transitiontest.R;
+
+
+public class Demo1 extends Activity {
+ ViewGroup mSceneRoot;
+ static Scene mCurrentScene;
+ boolean mFirstTime = true;
+ Scene mSearchScreen, mResultsScreen;
+ TransitionManager mTransitionManager = null;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.search_screen);
+
+ View container = (View) findViewById(R.id.container);
+ mSceneRoot = (ViewGroup) container.getParent();
+
+// mResultsScreen = new MyScene(mSceneRoot, R.layout.results_screen);
+// mSearchScreen = new MyScene(mSceneRoot, R.layout.search_screen);
+ mResultsScreen = new Scene(mSceneRoot);
+ mResultsScreen.setEnterAction(new Runnable() {
+ @Override
+ public void run() {
+ LayoutInflater inflater = (LayoutInflater)
+ getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ inflater.inflate(R.layout.results_screen, mSceneRoot);
+ }
+ });
+ mSearchScreen = new Scene(mSceneRoot);
+ mSearchScreen.setEnterAction(new Runnable() {
+ @Override
+ public void run() {
+ LayoutInflater inflater = (LayoutInflater)
+ getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ inflater.inflate(R.layout.search_screen, mSceneRoot);
+ }
+ });
+
+ }
+
+ public void sendMessage(View view) {
+ if (mFirstTime) {
+ mFirstTime = false;
+ TransitionGroup transition = new TransitionGroup();
+ transition.addTransitions(new Fade().setTargetIds(R.id.resultsText, R.id.resultsList),
+ new Move().setTargetIds(R.id.searchContainer));
+ mTransitionManager = new TransitionManager();
+ mTransitionManager.setTransition(mSearchScreen, transition);
+ mTransitionManager.setTransition(mResultsScreen, transition);
+ }
+ if (mCurrentScene == mResultsScreen) {
+ mTransitionManager.transitionTo(mSearchScreen);
+ mCurrentScene = mSearchScreen;
+ } else {
+ mTransitionManager.transitionTo(mResultsScreen);
+ mCurrentScene = mResultsScreen;
+ }
+ }
+}
diff --git a/tests/TransitionTests/src/com/android/transitiontests/Demo2.java b/tests/TransitionTests/src/com/android/transitiontests/Demo2.java
new file mode 100644
index 0000000..40f8a08
--- /dev/null
+++ b/tests/TransitionTests/src/com/android/transitiontests/Demo2.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2013 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 com.android.transitiontests;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.transition.Fade;
+import android.view.transition.Move;
+import android.view.transition.Recolor;
+import android.view.transition.Scene;
+import android.view.transition.TransitionInflater;
+import android.view.transition.TransitionGroup;
+import android.view.transition.TransitionManager;
+import com.android.transitiontest.R;
+
+public class Demo2 extends Activity {
+ ViewGroup mSceneRoot;
+ static Scene mCurrentScene;
+ boolean mFirstTime = true;
+ Scene mSearchScreen, mResultsScreen;
+ TransitionManager mTransitionManager = null;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.search_screen);
+
+ View container = (View) findViewById(R.id.container);
+ mSceneRoot = (ViewGroup) container.getParent();
+
+ }
+
+ public void sendMessage(View view) {
+ if (mFirstTime) {
+ mFirstTime = false;
+ // Non-resource approach of creating scenes
+// mSearchScreen = new Scene(this, mSceneRoot, R.layout.search_screen);
+// mResultsScreen = new Scene(this, mSceneRoot, R.layout.results_screen);
+ try {
+ mSearchScreen = TransitionInflater.from(this).
+ inflateScene(R.scene.search_scene, mSceneRoot);
+ mResultsScreen = TransitionInflater.from(this).
+ inflateScene(R.scene.results_scene, mSceneRoot);
+ } catch (Exception e) {
+ System.out.println("Problem loading scene resource: " + e);
+ }
+
+ TransitionGroup transition = new TransitionGroup();
+ transition.addTransitions(new Fade().setTargetIds(R.id.resultsText, R.id.resultsList),
+ new Move().setTargetIds(R.id.searchContainer),
+ new Recolor().setTargetIds(R.id.container));
+ mTransitionManager = new TransitionManager();
+ mTransitionManager.setTransition(mSearchScreen, transition);
+ mTransitionManager.setTransition(mResultsScreen, transition);
+ }
+ if (mCurrentScene == mResultsScreen) {
+ mTransitionManager.transitionTo(mSearchScreen);
+ mCurrentScene = mSearchScreen;
+ } else {
+ mTransitionManager.transitionTo(mResultsScreen);
+ mCurrentScene = mResultsScreen;
+ }
+ }
+}
diff --git a/tests/TransitionTests/src/com/android/transitiontests/Demo3.java b/tests/TransitionTests/src/com/android/transitiontests/Demo3.java
new file mode 100644
index 0000000..f30f502
--- /dev/null
+++ b/tests/TransitionTests/src/com/android/transitiontests/Demo3.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2013 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 com.android.transitiontests;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.transition.Fade;
+import android.view.transition.Move;
+import android.view.transition.Recolor;
+import android.view.transition.Scene;
+import android.view.transition.TransitionGroup;
+import android.view.transition.TransitionManager;
+import com.android.transitiontest.R;
+
+
+public class Demo3 extends Activity {
+ ViewGroup mSceneRoot;
+ static Scene mCurrentScene;
+ Scene mSearchScreen, mResultsScreen;
+ TransitionManager mTransitionManager = null;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.search_screen);
+
+ View container = (View) findViewById(R.id.container);
+ mSceneRoot = (ViewGroup) container.getParent();
+
+ mSearchScreen = new Scene(mSceneRoot, R.layout.search_screen, this);
+ mResultsScreen = new Scene(mSceneRoot, R.layout.results_screen, this);
+
+ TransitionGroup transition = new TransitionGroup();
+ transition.addTransitions(new Fade(), new Move(), new Recolor());
+
+ mTransitionManager = new TransitionManager();
+ mTransitionManager.setTransition(mSearchScreen, transition);
+ mTransitionManager.setTransition(mResultsScreen, transition);
+ }
+
+ public void sendMessage(View view) {
+ if (mCurrentScene == mResultsScreen) {
+ mTransitionManager.transitionTo(mSearchScreen);
+ mCurrentScene = mSearchScreen;
+ } else {
+ mTransitionManager.transitionTo(mResultsScreen);
+ mCurrentScene = mResultsScreen;
+ }
+ }
+}
diff --git a/tests/TransitionTests/src/com/android/transitiontests/Demo4.java b/tests/TransitionTests/src/com/android/transitiontests/Demo4.java
new file mode 100644
index 0000000..41d6d08
--- /dev/null
+++ b/tests/TransitionTests/src/com/android/transitiontests/Demo4.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2013 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 com.android.transitiontests;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.transition.Fade;
+import android.view.transition.Move;
+import android.view.transition.Recolor;
+import android.view.transition.Scene;
+import android.view.transition.TransitionGroup;
+import android.view.transition.TransitionManager;
+import com.android.transitiontest.R;
+
+
+public class Demo4 extends Activity {
+ ViewGroup mSceneRoot;
+ static Scene mCurrentScene;
+ Scene mSearchScreen, mResultsScreen;
+ TransitionManager mTransitionManager = null;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.search_screen);
+
+ View container = (View) findViewById(R.id.container);
+ mSceneRoot = (ViewGroup) container.getParent();
+
+ mSearchScreen = new Scene(mSceneRoot, R.layout.search_screen, this);
+ mResultsScreen = new Scene(mSceneRoot, R.layout.results_screen, this);
+
+ TransitionGroup transitionToResults = new TransitionGroup();
+ Fade fade = new Fade();
+ fade.setTargetIds(R.id.resultsText, R.id.resultsList);
+ fade.setStartDelay(300);
+ fade.setDuration(1000);
+ transitionToResults.addTransitions(fade, new Move().setTargetIds(R.id.searchContainer),
+ new Recolor().setTargetIds(R.id.container));
+
+ TransitionGroup transitionToSearch = new TransitionGroup();
+ transitionToSearch.addTransitions(fade, new Move().setTargetIds(R.id.searchContainer),
+ new Recolor().setTargetIds(R.id.container));
+
+ mTransitionManager = new TransitionManager();
+ mTransitionManager.setTransition(mSearchScreen, transitionToSearch);
+ mTransitionManager.setTransition(mResultsScreen, transitionToResults);
+ }
+
+ public void sendMessage(View view) {
+ if (mCurrentScene == mResultsScreen) {
+ mTransitionManager.transitionTo(mSearchScreen);
+ mCurrentScene = mSearchScreen;
+ } else {
+ mTransitionManager.transitionTo(mResultsScreen);
+ mCurrentScene = mResultsScreen;
+ }
+ }
+}
diff --git a/tests/TransitionTests/src/com/android/transitiontests/Demo5.java b/tests/TransitionTests/src/com/android/transitiontests/Demo5.java
new file mode 100644
index 0000000..9d64f07
--- /dev/null
+++ b/tests/TransitionTests/src/com/android/transitiontests/Demo5.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2013 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 com.android.transitiontests;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.transition.Scene;
+import android.view.transition.TransitionManager;
+import com.android.transitiontest.R;
+
+
+public class Demo5 extends Activity {
+ ViewGroup mSceneRoot;
+ static Scene mCurrentScene;
+ Scene mSearchScreen, mResultsScreen;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.search_screen);
+
+ View container = (View) findViewById(R.id.container);
+ mSceneRoot = (ViewGroup) container.getParent();
+
+ mSearchScreen = new Scene(mSceneRoot, R.layout.search_screen, this);
+ mResultsScreen = new Scene(mSceneRoot, R.layout.results_screen, this);
+
+ }
+
+ public void sendMessage(View view) {
+ if (mCurrentScene == mResultsScreen) {
+ TransitionManager.go(mSearchScreen);
+ mCurrentScene = mSearchScreen;
+ } else {
+ TransitionManager.go(mResultsScreen);
+ mCurrentScene = mResultsScreen;
+ }
+ }
+}
diff --git a/tests/TransitionTests/src/com/android/transitiontests/FadingTest.java b/tests/TransitionTests/src/com/android/transitiontests/FadingTest.java
new file mode 100644
index 0000000..7d30dfd
--- /dev/null
+++ b/tests/TransitionTests/src/com/android/transitiontests/FadingTest.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2013 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 com.android.transitiontests;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.transition.Scene;
+import android.widget.Button;
+import android.view.transition.Fade;
+import android.view.transition.TransitionManager;
+import com.android.transitiontest.R;
+
+
+public class FadingTest extends Activity {
+
+ Button mRemovingButton, mInvisibleButton, mGoneButton;
+ Scene mScene1, mScene2;
+ ViewGroup mSceneRoot;
+ static Fade sFade = new Fade();
+
+ static {
+ sFade.setTargetIds(R.id.removingButton, R.id.invisibleButton, R.id.goneButton);
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.fading_test);
+
+ View container = (View) findViewById(R.id.container);
+ mSceneRoot = (ViewGroup) container.getParent();
+
+
+ mRemovingButton = (Button) findViewById(R.id.removingButton);
+ mInvisibleButton = (Button) findViewById(R.id.invisibleButton);
+ mGoneButton = (Button) findViewById(R.id.goneButton);
+
+ mGoneButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ mGoneButton.setAlpha(mGoneButton.getAlpha() < 1 ? 1 : .6f);
+ }
+ });
+
+ mScene1 = new Scene(mSceneRoot, R.layout.fading_test, this);
+ mScene2 = new Scene(mSceneRoot, R.layout.fading_test_scene_2, this);
+
+ mSceneRoot.setCurrentScene(mScene1);
+ }
+
+ public void sendMessage(View view) {
+ if (mSceneRoot.getCurrentScene() == mScene1) {
+ TransitionManager.go(mScene2);
+ } else {
+ TransitionManager.go(mScene1);
+ }
+ }
+
+}
diff --git a/tests/TransitionTests/src/com/android/transitiontests/HitRectBug.java b/tests/TransitionTests/src/com/android/transitiontests/HitRectBug.java
new file mode 100644
index 0000000..33e00a8
--- /dev/null
+++ b/tests/TransitionTests/src/com/android/transitiontests/HitRectBug.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2013 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 com.android.transitiontests;
+
+import android.animation.ObjectAnimator;
+import android.animation.ValueAnimator;
+import android.app.Activity;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.os.Bundle;
+import android.view.View;
+import android.widget.ImageView;
+import android.widget.RelativeLayout;
+import com.android.transitiontest.R;
+
+
+public class HitRectBug extends Activity {
+ @Override
+ protected void onCreate(Bundle savedInstanceState)
+ {
+ super.onCreate(savedInstanceState);
+ setContentView(new TestDrawingView(this));
+ }
+
+ public static class TestDrawingView extends RelativeLayout
+ {
+ private Rect mRect = new Rect();
+ private Paint mPaint;
+ private ImageView mImageView;
+
+ public TestDrawingView(Context context)
+ {
+ super(context);
+ setWillNotDraw(false);
+
+ mPaint = new Paint();
+ mPaint.setColor(Color.RED);
+ mPaint.setStyle(Paint.Style.STROKE);
+
+ mImageView = new ImageView(context);
+ mImageView.setLeft(100);
+ mImageView.setRight(200);
+ mImageView.setImageResource(R.drawable.self_portrait_square);
+ mImageView.setScaleX(3);
+ mImageView.setScaleY(3);
+// mImageView.setRotation(145);
+
+ ObjectAnimator anim = ObjectAnimator.ofFloat(mImageView, View.ROTATION, 0, 360);
+ anim.setRepeatCount(ValueAnimator.INFINITE);
+ anim.setDuration(5000);
+ anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ invalidate();
+ }
+ });
+ anim.start();
+ RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(128, 128);
+ params.addRule(RelativeLayout.CENTER_IN_PARENT);
+ addView(mImageView, params);
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas)
+ {
+ super.onDraw(canvas);
+ }
+
+ @Override
+ protected void dispatchDraw(Canvas canvas) {
+ super.dispatchDraw(canvas);
+ mImageView.getHitRect(mRect);
+ canvas.drawRect(mRect, mPaint);
+ }
+ }
+}
diff --git a/tests/TransitionTests/src/com/android/transitiontests/InstanceTargets.java b/tests/TransitionTests/src/com/android/transitiontests/InstanceTargets.java
new file mode 100644
index 0000000..efccfa9
--- /dev/null
+++ b/tests/TransitionTests/src/com/android/transitiontests/InstanceTargets.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2013 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 com.android.transitiontests;
+
+import android.app.Activity;
+import android.content.Context;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.transition.Move;
+import android.view.transition.Scene;
+import android.view.transition.TransitionManager;
+import android.widget.Button;
+import android.widget.RelativeLayout;
+import com.android.transitiontest.R;
+
+import static android.widget.RelativeLayout.ALIGN_PARENT_LEFT;
+import static android.widget.RelativeLayout.ALIGN_PARENT_RIGHT;
+import static android.widget.RelativeLayout.LayoutParams;
+
+public class InstanceTargets extends Activity {
+
+ ViewGroup mSceneRoot;
+ static int mCurrentScene;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.instance_targets);
+
+ View container = (View) findViewById(R.id.container);
+ mSceneRoot = (ViewGroup) container;
+ }
+
+ public void sendMessage(final View view) {
+ TransitionManager.go(mSceneRoot, new Runnable() {
+ @Override
+ public void run() {
+ for (int i = 0; i < mSceneRoot.getChildCount(); ++i) {
+ Button button = (Button) mSceneRoot.getChildAt(i);
+ LayoutParams params = (LayoutParams) button.getLayoutParams();
+ int rules[] = params.getRules();
+ if (rules[ALIGN_PARENT_RIGHT] != 0) {
+ params.removeRule(ALIGN_PARENT_RIGHT);
+ params.addRule(ALIGN_PARENT_LEFT);
+ } else {
+ params.removeRule(ALIGN_PARENT_LEFT);
+ params.addRule(ALIGN_PARENT_RIGHT);
+ }
+ button.setLayoutParams(params);
+ }
+ }
+ }, new Move().setTargets(view));
+ }
+}
diff --git a/tests/TransitionTests/src/com/android/transitiontests/ListViewAddRemove.java b/tests/TransitionTests/src/com/android/transitiontests/ListViewAddRemove.java
new file mode 100644
index 0000000..f0864dc
--- /dev/null
+++ b/tests/TransitionTests/src/com/android/transitiontests/ListViewAddRemove.java
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2013 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 com.android.transitiontests;
+
+import android.app.Activity;
+import android.content.Context;
+import android.os.Bundle;
+import android.view.View;
+import android.view.ViewTreeObserver;
+import android.view.transition.Fade;
+import android.view.transition.Scene;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
+import android.widget.LinearLayout;
+import android.widget.ListView;
+import android.widget.TextView;
+import android.view.transition.AutoTransition;
+import android.view.transition.Move;
+import android.view.transition.Transition;
+import android.view.transition.TransitionGroup;
+import android.view.transition.TransitionManager;
+import com.android.transitiontest.R;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+public class ListViewAddRemove extends Activity {
+
+ final ArrayList<String> numList = new ArrayList<String>();
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.list_view_add_remove);
+
+ final LinearLayout container = (LinearLayout) findViewById(R.id.container);
+
+ final ListView listview = (ListView) findViewById(R.id.listview);
+ for (int i = 0; i < 200; ++i) {
+ numList.add(Integer.toString(i));
+ }
+ final StableArrayAdapter adapter = new StableArrayAdapter(this,
+ android.R.layout.simple_list_item_1, numList);
+ listview.setAdapter(adapter);
+
+ final ViewTreeObserver observer = container.getViewTreeObserver();
+ observer.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
+ public void onGlobalLayout() {
+ System.out.println("-------------------------------------");
+ System.out.println("onLayoutListener: listview view tops: ");
+ for (int i = 0; i < listview.getChildCount(); ++i) {
+ TextView view = (TextView) listview.getChildAt(i);
+ System.out.println(" " + view.getText() + ": " + view.getTop());
+ }
+ }
+ });
+
+ final Scene mySceneChanger = new Scene(listview);
+
+ mySceneChanger.setEnterAction(new Runnable() {
+ @Override
+ public void run() {
+ numList.remove(mItemToDelete);
+ adapter.notifyDataSetChanged();
+ }
+ });
+ final Transition myTransition = new AutoTransition();
+ final TransitionGroup noFadeIn = new TransitionGroup(TransitionGroup.SEQUENTIALLY);
+ Fade fadeIn = new Fade(Fade.IN);
+ fadeIn.setDuration(50);
+ noFadeIn.addTransitions(new Fade(Fade.OUT), new Move(), fadeIn);
+
+ myTransition.addListener(new Transition.TransitionListenerAdapter() {
+ @Override
+ public void onTransitionStart(Transition transition) {
+ System.out.println("---------ListView Tops: Before--------");
+ for (int i = 0; i < listview.getChildCount(); ++i) {
+ TextView view = (TextView) listview.getChildAt(i);
+ int position = listview.getPositionForView(view);
+ }
+ }
+
+ @Override
+ public void onTransitionEnd(Transition transition) {
+ System.out.println("---------ListView Tops: After--------");
+ for (int i = 0; i < listview.getChildCount(); ++i) {
+ TextView view = (TextView) listview.getChildAt(i);
+ int position = listview.getPositionForView(view);
+ if (view.hasTransientState()) {
+// view.setHasTransientState(false);
+ }
+ }
+ myTransition.removeListener(this);
+ }
+ });
+
+ listview.setOnItemClickListener(new AdapterView.OnItemClickListener() {
+
+ @Override
+ public void onItemClick(AdapterView<?> parent, final View view, int position, long id) {
+ System.out.println("---------ListView Tops: OnClick--------");
+ String item = (String) parent.getItemAtPosition(position);
+ for (int i = 0; i < listview.getChildCount(); ++i) {
+ TextView v = (TextView) listview.getChildAt(i);
+ if (!item.equals(v.getText())) {
+// v.setHasTransientState(true);
+ }
+ }
+// listview.setHasTransientState(true);
+ mItemToDelete = item;
+// numList.remove(item);
+ TransitionManager.go(mySceneChanger, noFadeIn);
+// view.postDelayed(new Runnable() {
+// @Override
+// public void run() {
+// for (int i = 0; i < listview.getChildCount(); ++i) {
+// TextView v = (TextView) listview.getChildAt(i);
+// v.setHasTransientState(false);
+// }
+// }
+// }, 200);
+ }
+
+ });
+ }
+
+ String mItemToDelete = null;
+
+ private class StableArrayAdapter extends ArrayAdapter<String> {
+
+ HashMap<String, Integer> mIdMap = new HashMap<String, Integer>();
+
+ public StableArrayAdapter(Context context, int textViewResourceId,
+ List<String> objects) {
+ super(context, textViewResourceId, objects);
+ for (int i = 0; i < objects.size(); ++i) {
+ mIdMap.put(objects.get(i), i);
+ }
+ }
+
+ @Override
+ public long getItemId(int position) {
+ String item = getItem(position);
+ return mIdMap.get(item);
+ }
+
+ @Override
+ public boolean hasStableIds() {
+ return true;
+ }
+
+ }
+}
diff --git a/tests/TransitionTests/src/com/android/transitiontests/ListViewAddRemoveNoTransition.java b/tests/TransitionTests/src/com/android/transitiontests/ListViewAddRemoveNoTransition.java
new file mode 100644
index 0000000..93d3d97
--- /dev/null
+++ b/tests/TransitionTests/src/com/android/transitiontests/ListViewAddRemoveNoTransition.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2013 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 com.android.transitiontests;
+
+import android.app.Activity;
+import android.content.Context;
+import android.os.Bundle;
+import android.view.View;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
+import android.widget.LinearLayout;
+import android.widget.ListView;
+import android.widget.TextView;
+import com.android.transitiontest.R;
+
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+public class ListViewAddRemoveNoTransition extends Activity {
+
+ final ArrayList<String> numList = new ArrayList<String>();
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.list_view_add_remove);
+
+ final LinearLayout container = (LinearLayout) findViewById(R.id.container);
+
+ final ListView listview = (ListView) findViewById(R.id.listview);
+ for (int i = 0; i < 200; ++i) {
+ numList.add(Integer.toString(i));
+ }
+ final StableArrayAdapter adapter = new StableArrayAdapter(this,
+ android.R.layout.simple_list_item_1, numList);
+ listview.setAdapter(adapter);
+
+ listview.setOnItemClickListener(new AdapterView.OnItemClickListener() {
+
+ @Override
+ public void onItemClick(AdapterView<?> parent, final View view, int position, long id) {
+ String item = (String) parent.getItemAtPosition(position);
+ for (int i = 0; i < listview.getChildCount(); ++i) {
+ TextView v = (TextView) listview.getChildAt(i);
+ if (!item.equals(v.getText())) {
+ v.setHasTransientState(true);
+ }
+ }
+ numList.remove(item);
+ adapter.notifyDataSetChanged();
+ view.postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ for (int i = 0; i < listview.getChildCount(); ++i) {
+ TextView v = (TextView) listview.getChildAt(i);
+ v.setHasTransientState(false);
+ }
+ }
+ }, 200);
+ }
+
+ });
+ }
+
+ private class StableArrayAdapter extends ArrayAdapter<String> {
+
+ HashMap<String, Integer> mIdMap = new HashMap<String, Integer>();
+
+ public StableArrayAdapter(Context context, int textViewResourceId,
+ List<String> objects) {
+ super(context, textViewResourceId, objects);
+ for (int i = 0; i < objects.size(); ++i) {
+ mIdMap.put(objects.get(i), i);
+ }
+ }
+
+ @Override
+ public long getItemId(int position) {
+ String item = getItem(position);
+ return mIdMap.get(item);
+ }
+
+ @Override
+ public boolean hasStableIds() {
+ return true;
+ }
+
+ }
+}
diff --git a/tests/TransitionTests/src/com/android/transitiontests/LoginActivity.java b/tests/TransitionTests/src/com/android/transitiontests/LoginActivity.java
new file mode 100644
index 0000000..d3c5174
--- /dev/null
+++ b/tests/TransitionTests/src/com/android/transitiontests/LoginActivity.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2013 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 com.android.transitiontests;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.transition.Scene;
+import android.widget.TextView;
+import android.view.transition.Fade;
+import android.view.transition.Recolor;
+import android.view.transition.Slide;
+import android.view.transition.Transition;
+import android.view.transition.TransitionGroup;
+import android.view.transition.TransitionManager;
+import com.android.transitiontest.R;
+
+
+public class LoginActivity extends Activity {
+ ViewGroup mSceneRoot;
+ Scene mCurrentScene;
+ TransitionManager mTransitionManager;
+ Scene mLoginScene, mPasswordScene, mIncorrectPasswordScene, mSuccessScene, mUsernameTakenScene,
+ mNewUserScene;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_login);
+ View container = (View) findViewById(R.id.container);
+ mSceneRoot = (ViewGroup) container.getParent();
+
+ mLoginScene = new Scene(mSceneRoot, R.layout.activity_login, this);
+ mPasswordScene = new Scene(mSceneRoot, R.layout.login_password, this);
+ mIncorrectPasswordScene = new Scene(mSceneRoot, R.layout.incorrect_password, this);
+ mUsernameTakenScene = new Scene(mSceneRoot, R.layout.username_taken, this);
+ mSuccessScene = new Scene(mSceneRoot, R.layout.success, this);
+ mNewUserScene = new Scene(mSceneRoot, R.layout.new_user, this);
+
+ mTransitionManager = new TransitionManager();
+
+ // Custom transitions in/out of NewUser screen - slide in the 2nd password UI
+ TransitionGroup slider = new TransitionGroup();
+ slider.addTransitions(new Slide().setTargetIds(R.id.retype, R.id.retypeEdit));
+ slider.addTransitions(new Recolor().setTargetIds(R.id.password, R.id.passwordEdit));
+ slider.addTransitions(new Fade());
+ mTransitionManager.setTransition(mLoginScene, mNewUserScene, slider);
+ mTransitionManager.setTransition(mPasswordScene, mNewUserScene, slider);
+ mTransitionManager.setTransition(mNewUserScene, mLoginScene, slider);
+ mTransitionManager.setTransition(mNewUserScene, mPasswordScene, slider);
+
+ // Custom transitions with recoloring password field
+ Transition colorizer = new Recolor().setTargetIds(R.id.password, R.id.passwordEdit);
+ mTransitionManager.setTransition(mLoginScene, mPasswordScene, colorizer);
+ mTransitionManager.setTransition(mPasswordScene, mLoginScene, colorizer);
+
+ mCurrentScene = mLoginScene;
+ mSceneRoot.setCurrentScene(mLoginScene);
+ }
+
+ public void applyScene(Scene scene) {
+ mTransitionManager.transitionTo(scene);
+ mCurrentScene = scene;
+ }
+
+ public void sendMessage(View view) {
+ TextView textView = (TextView) view;
+ CharSequence text = textView.getText();
+ if (text.equals("Cancel")) {
+ applyScene(mLoginScene);
+ } else if (text.equals("Submit")) {
+ if (mCurrentScene == mLoginScene) {
+ applyScene(mPasswordScene);
+ } else if (mCurrentScene == mPasswordScene) {
+ applyScene(Math.random() < .5 ? mSuccessScene : mIncorrectPasswordScene);
+ } else if (mCurrentScene == mNewUserScene) {
+ applyScene(Math.random() < .5 ? mSuccessScene : mUsernameTakenScene);
+ }
+ } else if (text.equals("New User?")) {
+ applyScene(mNewUserScene);
+ } else if (text.equals("Okay")) {
+ if (mCurrentScene == mIncorrectPasswordScene) {
+ applyScene(mPasswordScene);
+ } else { // username taken scene
+ applyScene(mNewUserScene);
+ }
+ } else if (text.equals("Reset")) {
+ applyScene(mLoginScene);
+ }
+ }
+}
diff --git a/tests/TransitionTests/src/com/android/transitiontests/LoginActivityFromResources.java b/tests/TransitionTests/src/com/android/transitiontests/LoginActivityFromResources.java
new file mode 100644
index 0000000..fc8aa9b
--- /dev/null
+++ b/tests/TransitionTests/src/com/android/transitiontests/LoginActivityFromResources.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2013 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 com.android.transitiontests;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.transition.Scene;
+import android.view.transition.TransitionInflater;
+import android.widget.TextView;
+import android.view.transition.TransitionManager;
+import com.android.transitiontest.R;
+
+
+public class LoginActivityFromResources extends Activity {
+ ViewGroup mSceneRoot;
+ Scene mCurrentScene;
+ TransitionManager mTransitionManager = null;
+ Scene mLoginScene, mPasswordScene, mIncorrectPasswordScene, mSuccessScene, mUsernameTakenScene,
+ mNewUserScene;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_login);
+ View container = (View) findViewById(R.id.container);
+ mSceneRoot = (ViewGroup) container.getParent();
+
+ }
+
+ public void applyScene(Scene scene) {
+ mTransitionManager.transitionTo(scene);
+ mCurrentScene = scene;
+ }
+
+ public void sendMessage(View view) {
+ if (mTransitionManager == null) {
+ TransitionInflater inflater = TransitionInflater.from(this);
+
+ mLoginScene = inflater.inflateScene(R.scene.login_scene, mSceneRoot);
+ mPasswordScene = inflater.inflateScene(R.scene.password_scene, mSceneRoot);
+ mIncorrectPasswordScene =
+ inflater.inflateScene(R.scene.incorrect_password_scene,mSceneRoot);
+ mUsernameTakenScene =
+ inflater.inflateScene(R.scene.username_taken_scene, mSceneRoot);
+ mSuccessScene = inflater.inflateScene(R.scene.success_scene, mSceneRoot);
+ mNewUserScene = inflater.inflateScene(R.scene.new_user_scene, mSceneRoot);
+
+ mTransitionManager =
+ inflater.inflateTransitionManager(R.transition.login_transition_mgr,
+ mSceneRoot);
+
+ mCurrentScene = mLoginScene;
+ mSceneRoot.setCurrentScene(mLoginScene);
+ }
+ TextView textView = (TextView) view;
+ CharSequence text = textView.getText();
+ if (text.equals("Cancel")) {
+ applyScene(mLoginScene);
+ } else if (text.equals("Submit")) {
+ if (mCurrentScene == mLoginScene) {
+ applyScene(mPasswordScene);
+ } else if (mCurrentScene == mPasswordScene) {
+ applyScene(Math.random() < .5 ? mSuccessScene : mIncorrectPasswordScene);
+ } else if (mCurrentScene == mNewUserScene) {
+ applyScene(Math.random() < .5 ? mSuccessScene : mUsernameTakenScene);
+ }
+ } else if (text.equals("New User?")) {
+ applyScene(mNewUserScene);
+ } else if (text.equals("Okay")) {
+ if (mCurrentScene == mIncorrectPasswordScene) {
+ applyScene(mPasswordScene);
+ } else { // username taken scene
+ applyScene(mNewUserScene);
+ }
+ } else if (text.equals("Reset")) {
+ applyScene(mLoginScene);
+ }
+ }
+}
diff --git a/tests/TransitionTests/src/com/android/transitiontests/OverlayTest.java b/tests/TransitionTests/src/com/android/transitiontests/OverlayTest.java
new file mode 100644
index 0000000..2f8224a
--- /dev/null
+++ b/tests/TransitionTests/src/com/android/transitiontests/OverlayTest.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2013 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 com.android.transitiontests;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+import com.android.transitiontest.R;
+
+
+public class OverlayTest extends Activity {
+
+ ViewGroup mContainer;
+ ViewGroup mRoot;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.overlay_test);
+
+ mContainer = (ViewGroup) findViewById(R.id.container);
+ mRoot = (ViewGroup) mContainer.getParent();
+ }
+
+ public void onClick(View view) {
+ final Button fadingButton = (Button) findViewById(R.id.fadingButton);
+ if (fadingButton != null) {
+ mContainer.removeView(fadingButton);
+ mRoot.getOverlay().add(fadingButton);
+ fadingButton.animate().alpha(0).setDuration(1000).withEndAction(new Runnable() {
+ @Override
+ public void run() {
+ fadingButton.setAlpha(1);
+ mRoot.getOverlay().remove(fadingButton);
+ mContainer.addView(fadingButton);
+ }
+ });
+ }
+ }
+}
diff --git a/tests/TransitionTests/src/com/android/transitiontests/Reparenting.java b/tests/TransitionTests/src/com/android/transitiontests/Reparenting.java
new file mode 100644
index 0000000..8ee9d3f
--- /dev/null
+++ b/tests/TransitionTests/src/com/android/transitiontests/Reparenting.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2013 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 com.android.transitiontests;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.transition.Move;
+import android.view.transition.Scene;
+import android.view.transition.TransitionManager;
+import android.widget.Button;
+import com.android.transitiontest.R;
+
+public class Reparenting extends Activity {
+
+ ViewGroup mSceneRoot;
+ ViewGroup mContainer1, mContainer2;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.reparenting);
+
+ ViewGroup container = (ViewGroup) findViewById(R.id.container);
+ mContainer1 = (ViewGroup) findViewById(R.id.container1);
+ mContainer2 = (ViewGroup) findViewById(R.id.container2);
+ System.out.println("container 1 and 2 " + mContainer1 + ", " + mContainer2);
+
+ setupButtons(0, mContainer1);
+ setupButtons(3, mContainer2);
+
+ mSceneRoot = container;
+ }
+
+ private void setupButtons(int startIndex, ViewGroup parent) {
+ for (int i = startIndex; i < (startIndex + 3); ++i) {
+ Button button = new Button(this);
+ button.setText(Integer.toString(i));
+ button.setOnClickListener(mButtonListener);
+ parent.addView(button);
+ }
+ }
+
+ private View.OnClickListener mButtonListener = new View.OnClickListener() {
+ @Override
+ public void onClick(final View v) {
+ Scene newScene = new Scene(mSceneRoot);
+ newScene.setEnterAction(new Runnable() {
+ @Override
+ public void run() {
+ ViewGroup oldParent = (ViewGroup) v.getParent();
+ ViewGroup newParent = oldParent == mContainer1 ? mContainer2 : mContainer1;
+ oldParent.removeView(v);
+ newParent.addView(v);
+ }
+ });
+ Move reparent = new Move();
+ reparent.setReparent(true);
+ TransitionManager.go(newScene, reparent);
+ }
+ };
+}
diff --git a/tests/TransitionTests/src/com/android/transitiontests/ResourceLoadingTest.java b/tests/TransitionTests/src/com/android/transitiontests/ResourceLoadingTest.java
new file mode 100644
index 0000000..c05f898
--- /dev/null
+++ b/tests/TransitionTests/src/com/android/transitiontests/ResourceLoadingTest.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2013 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 com.android.transitiontests;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.transition.Scene;
+import android.view.transition.TransitionInflater;
+import android.view.transition.Transition;
+import android.view.transition.TransitionManager;
+import com.android.transitiontest.R;
+
+
+public class ResourceLoadingTest extends Activity {
+
+ private static final int SEARCH_SCREEN = 0;
+ private static final int RESULTS_SCREEN = 1;
+ ViewGroup mSceneRoot;
+ static int mCurrentScene;
+ TransitionManager mTransitionManager = null;
+ TransitionInflater mInflater;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.search_screen);
+
+ View container = (View) findViewById(R.id.container);
+ mSceneRoot = (ViewGroup) container.getParent();
+
+ mCurrentScene = SEARCH_SCREEN;
+
+ mInflater = TransitionInflater.from(this);
+ }
+
+ public void sendMessage(View view) {
+ if (mTransitionManager == null) {
+ try {
+ TransitionInflater inflater = TransitionInflater.from(this);
+ mTransitionManager =
+ inflater.inflateTransitionManager(R.transition.my_transition_mgr,
+ mSceneRoot);
+ Scene loadedScene = inflater.inflateScene(R.scene.my_scene, mSceneRoot);
+ System.out.println("loadedScene = " + loadedScene);
+ Transition loadedTransition = inflater.inflateTransition(R.transition.my_transition);
+ System.out.println("loadedTransition = " + loadedTransition);
+ } catch (Exception e) {
+ System.out.println("Problem loading scene resource: " + e);
+ }
+ }
+ if (mCurrentScene == RESULTS_SCREEN) {
+ Scene scene = mInflater.inflateScene(R.scene.search_scene, mSceneRoot);
+ mTransitionManager.transitionTo(scene);
+ mCurrentScene = SEARCH_SCREEN;
+ } else {
+ Scene scene = mInflater.inflateScene(R.scene.results_scene, mSceneRoot);
+ mTransitionManager.transitionTo(scene);
+ mCurrentScene = RESULTS_SCREEN;
+ }
+ }
+}
diff --git a/tests/TransitionTests/src/com/android/transitiontests/ScenesTestAutoTargets.java b/tests/TransitionTests/src/com/android/transitiontests/ScenesTestAutoTargets.java
new file mode 100644
index 0000000..ae8ee5b
--- /dev/null
+++ b/tests/TransitionTests/src/com/android/transitiontests/ScenesTestAutoTargets.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2013 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 com.android.transitiontests;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.transition.Fade;
+import android.view.transition.Move;
+import android.view.transition.Recolor;
+import android.view.transition.Scene;
+import android.view.transition.TransitionGroup;
+import android.view.transition.TransitionManager;
+import com.android.transitiontest.R;
+
+
+public class ScenesTestAutoTargets extends Activity {
+ ViewGroup mSceneRoot;
+ static Scene mCurrentScene;
+ TransitionManager mTransitionManager = null;
+ Scene mResultsScreen, mSearchScreen;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.search_screen);
+
+ View container = (View) findViewById(R.id.container);
+ mSceneRoot = (ViewGroup) container.getParent();
+
+ mSearchScreen = new Scene(mSceneRoot, R.layout.search_screen, this);
+ mResultsScreen = new Scene(mSceneRoot, R.layout.results_screen, this);
+
+ TransitionGroup transition = new TransitionGroup();
+ transition.addTransitions(new Fade(), new Move(), new Recolor());
+
+ mTransitionManager = new TransitionManager();
+ mTransitionManager.setTransition(mSearchScreen, transition);
+ mTransitionManager.setTransition(mResultsScreen, transition);
+ }
+
+ public void sendMessage(View view) {
+ if (mCurrentScene == mResultsScreen) {
+ mTransitionManager.transitionTo(mSearchScreen);
+ mCurrentScene = mSearchScreen;
+ } else {
+ mTransitionManager.transitionTo(mResultsScreen);
+ mCurrentScene = mResultsScreen;
+ }
+ }
+}
diff --git a/tests/TransitionTests/src/com/android/transitiontests/ScenesTestAutoTransition.java b/tests/TransitionTests/src/com/android/transitiontests/ScenesTestAutoTransition.java
new file mode 100644
index 0000000..9184e87
--- /dev/null
+++ b/tests/TransitionTests/src/com/android/transitiontests/ScenesTestAutoTransition.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2013 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 com.android.transitiontests;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.transition.AutoTransition;
+import android.view.transition.Scene;
+import android.view.transition.Transition;
+import android.view.transition.TransitionManager;
+import com.android.transitiontest.R;
+
+
+public class ScenesTestAutoTransition extends Activity {
+ ViewGroup mSceneRoot;
+ static Scene mCurrentScene;
+ Transition mTransition = new AutoTransition();
+ Scene mResultsScreen, mSearchScreen;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.search_screen);
+
+ View container = (View) findViewById(R.id.container);
+ mSceneRoot = (ViewGroup) container.getParent();
+
+ mSearchScreen = new Scene(mSceneRoot, R.layout.search_screen, this);
+ mResultsScreen = new Scene(mSceneRoot, R.layout.results_screen, this);
+ }
+
+ public void sendMessage(View view) {
+ if (mCurrentScene == mResultsScreen) {
+ TransitionManager.go(mSearchScreen, mTransition);
+ mCurrentScene = mSearchScreen;
+ } else {
+ TransitionManager.go(mResultsScreen, mTransition);
+ mCurrentScene = mResultsScreen;
+ }
+ }
+}
diff --git a/tests/TransitionTests/src/com/android/transitiontests/ScenesTestAutoTransition2.java b/tests/TransitionTests/src/com/android/transitiontests/ScenesTestAutoTransition2.java
new file mode 100644
index 0000000..fc8acc1
--- /dev/null
+++ b/tests/TransitionTests/src/com/android/transitiontests/ScenesTestAutoTransition2.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2013 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 com.android.transitiontests;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.transition.Scene;
+import android.view.transition.TransitionManager;
+import com.android.transitiontest.R;
+
+
+public class ScenesTestAutoTransition2 extends Activity {
+ ViewGroup mSceneRoot;
+ static Scene mCurrentScene;
+
+ Scene mResultsScreen, mSearchScreen;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.search_screen);
+
+ View container = (View) findViewById(R.id.container);
+ mSceneRoot = (ViewGroup) container.getParent();
+
+ mSearchScreen = new Scene(mSceneRoot, R.layout.search_screen, this);
+ mResultsScreen = new Scene(mSceneRoot, R.layout.results_screen, this);
+ }
+
+ public void sendMessage(View view) {
+ if (mCurrentScene == mResultsScreen) {
+ TransitionManager.go(mSearchScreen);
+ mCurrentScene = mSearchScreen;
+ } else {
+ TransitionManager.go(mResultsScreen);
+ mCurrentScene = mResultsScreen;
+ }
+ }
+}
diff --git a/tests/TransitionTests/src/com/android/transitiontests/ScenesTestv21.java b/tests/TransitionTests/src/com/android/transitiontests/ScenesTestv21.java
new file mode 100644
index 0000000..2dae463
--- /dev/null
+++ b/tests/TransitionTests/src/com/android/transitiontests/ScenesTestv21.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2013 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 com.android.transitiontests;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.transition.Fade;
+import android.view.transition.Move;
+import android.view.transition.Recolor;
+import android.view.transition.Scene;
+import android.view.transition.TransitionGroup;
+import android.view.transition.TransitionManager;
+import com.android.transitiontest.R;
+
+
+public class ScenesTestv21 extends Activity {
+ ViewGroup mSceneRoot;
+ static Scene mCurrentScene;
+ TransitionManager mTransitionManager = null;
+ Scene mResultsScreen, mSearchScreen;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.search_screen);
+
+ View container = (View) findViewById(R.id.container);
+ mSceneRoot = (ViewGroup) container.getParent();
+
+ mSearchScreen = new Scene(mSceneRoot, R.layout.search_screen, this);
+ mResultsScreen = new Scene(mSceneRoot, R.layout.results_screen, this);
+
+ TransitionGroup transitionToResults = new TransitionGroup();
+ Fade fade = new Fade();
+ fade.setTargetIds(R.id.resultsText, R.id.resultsList);
+ fade.setStartDelay(300);
+ transitionToResults.addTransitions(fade);
+ transitionToResults.addTransitions(new Move().setTargetIds(R.id.searchContainer));
+ transitionToResults.addTransitions(new Recolor().setTargetIds(R.id.container));
+
+ TransitionGroup transitionToSearch = new TransitionGroup();
+ transitionToSearch.addTransitions(new Fade().setTargetIds(R.id.resultsText, R.id.resultsList));
+ transitionToSearch.addTransitions(new Move().setTargetIds(R.id.searchContainer));
+ transitionToSearch.addTransitions(new Recolor().setTargetIds(R.id.container));
+ mTransitionManager = new TransitionManager();
+ mTransitionManager.setTransition(mSearchScreen, transitionToSearch);
+ mTransitionManager.setTransition(mResultsScreen, transitionToResults);
+ }
+
+ public void sendMessage(View view) {
+ if (mCurrentScene == mResultsScreen) {
+ mTransitionManager.transitionTo(mSearchScreen);
+ mCurrentScene = mSearchScreen;
+ } else {
+ mTransitionManager.transitionTo(mResultsScreen);
+ mCurrentScene = mResultsScreen;
+ }
+ }
+}
diff --git a/tests/TransitionTests/src/com/android/transitiontests/SequenceTest.java b/tests/TransitionTests/src/com/android/transitiontests/SequenceTest.java
new file mode 100644
index 0000000..8cb6a1a
--- /dev/null
+++ b/tests/TransitionTests/src/com/android/transitiontests/SequenceTest.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2013 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 com.android.transitiontests;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.transition.Scene;
+import android.view.transition.Transition;
+import android.widget.Button;
+import android.view.transition.Fade;
+import android.view.transition.Move;
+import android.view.transition.TransitionGroup;
+import android.view.transition.TransitionManager;
+import com.android.transitiontest.R;
+
+
+public class SequenceTest extends Activity {
+
+ Button mRemovingButton, mInvisibleButton, mGoneButton;
+ Scene mScene1, mScene2;
+ ViewGroup mSceneRoot;
+ TransitionGroup sequencedFade, reverseSequencedFade;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.fading_test);
+
+ View container = (View) findViewById(R.id.container);
+ mSceneRoot = (ViewGroup) container.getParent();
+
+ mRemovingButton = (Button) findViewById(R.id.removingButton);
+ mInvisibleButton = (Button) findViewById(R.id.invisibleButton);
+ mGoneButton = (Button) findViewById(R.id.goneButton);
+
+ mScene1 = new Scene(mSceneRoot, R.layout.fading_test, this);
+ mScene2 = new Scene(mSceneRoot, R.layout.fading_test_scene_2, this);
+
+ Transition fade1 = new Fade().setTargetIds(R.id.removingButton);
+ Transition fade2 = new Fade().setTargetIds(R.id.invisibleButton);
+ Transition fade3 = new Fade().setTargetIds(R.id.goneButton);
+ TransitionGroup fader = new TransitionGroup(TransitionGroup.SEQUENTIALLY);
+ fader.addTransitions(fade1, fade2, fade3, new Move());
+ sequencedFade = fader;
+
+ reverseSequencedFade = new TransitionGroup(TransitionGroup.SEQUENTIALLY);
+ reverseSequencedFade.addTransitions(new Move(), fade3, fade2, fade1);
+
+ mSceneRoot.setCurrentScene(mScene1);
+ }
+
+ public void sendMessage(View view) {
+ if (mSceneRoot.getCurrentScene() == mScene1) {
+ TransitionManager.go(mScene2, sequencedFade);
+ } else {
+ TransitionManager.go(mScene1, reverseSequencedFade);
+ }
+ }
+}
diff --git a/tests/TransitionTests/src/com/android/transitiontests/SequenceTestSimple.java b/tests/TransitionTests/src/com/android/transitiontests/SequenceTestSimple.java
new file mode 100644
index 0000000..93bfdb4
--- /dev/null
+++ b/tests/TransitionTests/src/com/android/transitiontests/SequenceTestSimple.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2013 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 com.android.transitiontests;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.transition.Scene;
+import android.widget.Button;
+import android.view.transition.Fade;
+import android.view.transition.Move;
+import android.view.transition.Transition;
+import android.view.transition.TransitionGroup;
+import android.view.transition.TransitionManager;
+import com.android.transitiontest.R;
+
+
+public class SequenceTestSimple extends Activity {
+
+ Button mRemovingButton, mInvisibleButton, mGoneButton;
+ Scene mScene1, mScene2;
+ ViewGroup mSceneRoot;
+ Transition sequencedFade;
+ TransitionGroup sequencedFadeReverse;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.fading_test_simple);
+
+ View container = (View) findViewById(R.id.container);
+ mSceneRoot = (ViewGroup) container.getParent();
+
+ mRemovingButton = (Button) findViewById(R.id.removingButton);
+
+ mScene1 = new Scene(mSceneRoot, R.layout.fading_test_simple, this);
+ mScene2 = new Scene(mSceneRoot, R.layout.fading_test_simple2, this);
+
+ TransitionGroup fader = new TransitionGroup(TransitionGroup.SEQUENTIALLY);
+ fader.addTransitions(new Fade().setTargetIds(R.id.removingButton));
+ fader.addTransitions(new Move().setTargetIds(R.id.sceneSwitchButton));
+ sequencedFade = fader;
+
+ sequencedFadeReverse = new TransitionGroup(TransitionGroup.SEQUENTIALLY);
+ sequencedFadeReverse.addTransitions(new Move().setTargetIds(R.id.sceneSwitchButton));
+ sequencedFadeReverse.addTransitions(new Fade().setTargetIds(R.id.removingButton));
+
+ mSceneRoot.setCurrentScene(mScene1);
+ }
+
+ public void sendMessage(View view) {
+ if (mSceneRoot.getCurrentScene() == mScene1) {
+ TransitionManager.go(mScene2, sequencedFade);
+ } else {
+ TransitionManager.go(mScene1, sequencedFadeReverse);
+ }
+ }}
diff --git a/tests/TransitionTests/src/com/android/transitiontests/SurfaceAndTextureViews.java b/tests/TransitionTests/src/com/android/transitiontests/SurfaceAndTextureViews.java
new file mode 100644
index 0000000..f8829c9
--- /dev/null
+++ b/tests/TransitionTests/src/com/android/transitiontests/SurfaceAndTextureViews.java
@@ -0,0 +1,195 @@
+/*
+ * Copyright (C) 2013 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 com.android.transitiontests;
+
+import android.app.Activity;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.SurfaceTexture;
+import android.os.Bundle;
+import android.util.AttributeSet;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
+import android.view.TextureView;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.transition.Crossfade;
+import android.view.transition.Move;
+import android.view.transition.Scene;
+import android.view.transition.TransitionGroup;
+import android.view.transition.TransitionManager;
+import android.widget.Button;
+import com.android.transitiontest.R;
+
+import static android.widget.LinearLayout.LayoutParams;
+
+public class SurfaceAndTextureViews extends Activity {
+
+ SimpleView mView;
+ SimpleSurfaceView mSurfaceView;
+ SimpleTextureView mTextureView;
+ private static final int SMALL_SIZE = 200;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.surface_texture_views);
+
+ final ViewGroup container = (ViewGroup) findViewById(R.id.container);
+ Button toggleButton = (Button) findViewById(R.id.toggleButton);
+
+ mView = new SimpleView(this);
+ mView.setId(0);
+ mView.setLayoutParams(new LayoutParams(SMALL_SIZE, SMALL_SIZE));
+ container.addView(mView);
+
+ mSurfaceView = new SimpleSurfaceView(this);
+ mSurfaceView.setId(1);
+ mSurfaceView.setLayoutParams(new LayoutParams(SMALL_SIZE, SMALL_SIZE));
+ container.addView(mSurfaceView);
+
+ mTextureView = new SimpleTextureView(this);
+ mTextureView.setId(2);
+ mTextureView.setLayoutParams(new LayoutParams(SMALL_SIZE, SMALL_SIZE));
+ container.addView(mTextureView);
+
+ final TransitionGroup transition = new TransitionGroup();
+ transition.addTransitions(new Move(), new Crossfade().setTargetIds(0, 1, 2));
+
+ toggleButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ Scene newScene = new Scene(container);
+ newScene.setEnterAction(new Runnable() {
+ @Override
+ public void run() {
+ if (mView.getWidth() <= SMALL_SIZE) {
+ mView.setLayoutParams(new LayoutParams(SMALL_SIZE * 2, SMALL_SIZE));
+ mSurfaceView.setLayoutParams(new LayoutParams(SMALL_SIZE * 2, SMALL_SIZE));
+ mTextureView.setLayoutParams(new LayoutParams(SMALL_SIZE * 2, SMALL_SIZE));
+ mView.mColor = SimpleView.LARGE_COLOR;
+ mSurfaceView.mColor = SimpleSurfaceView.LARGE_COLOR;
+ mTextureView.mColor = SimpleTextureView.LARGE_COLOR;
+ } else {
+ mView.setLayoutParams(new LayoutParams(SMALL_SIZE, SMALL_SIZE));
+ mSurfaceView.setLayoutParams(new LayoutParams(SMALL_SIZE, SMALL_SIZE));
+ mTextureView.setLayoutParams(new LayoutParams(SMALL_SIZE, SMALL_SIZE));
+ mView.mColor = SimpleView.SMALL_COLOR;
+ mSurfaceView.mColor = SimpleSurfaceView.SMALL_COLOR;
+ mTextureView.mColor = SimpleTextureView.SMALL_COLOR;
+ }
+ }
+ });
+ TransitionManager.go(newScene, transition);
+ }
+ });
+
+ }
+
+ static private class SimpleView extends View {
+ static final int SMALL_COLOR = Color.BLUE;
+ static final int LARGE_COLOR = Color.YELLOW;
+ int mColor = SMALL_COLOR;
+
+ private SimpleView(Context context) {
+ super(context);
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ canvas.drawColor(mColor);
+ }
+ }
+
+ static private class SimpleSurfaceView extends SurfaceView implements SurfaceHolder.Callback {
+
+ static final int SMALL_COLOR = Color.GREEN;
+ static final int LARGE_COLOR = Color.GRAY;
+ int mColor = SMALL_COLOR;
+ SurfaceHolder mHolder = null;
+
+ private SimpleSurfaceView(Context context) {
+ super(context);
+ SurfaceHolder holder = getHolder();
+ holder.addCallback(this);
+ }
+
+
+ @Override
+ public void surfaceCreated(SurfaceHolder holder) {
+ System.out.println("surfaceCreated");
+ }
+
+ @Override
+ public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
+ System.out.println("surfaceChanged: w h = " + width + ", " + height);
+ Canvas canvas = holder.lockCanvas();
+ canvas.drawColor(mColor);
+ holder.unlockCanvasAndPost(canvas);
+ }
+
+ @Override
+ public void surfaceDestroyed(SurfaceHolder holder) {
+ System.out.println("surfaceDestroyed");
+ }
+ }
+
+ static private class SimpleTextureView extends TextureView implements TextureView.SurfaceTextureListener {
+
+ static final int SMALL_COLOR = Color.RED;
+ static final int LARGE_COLOR = Color.CYAN;
+ int mColor = SMALL_COLOR;
+
+ private SimpleTextureView(Context context) {
+ super(context);
+ setSurfaceTextureListener(this);
+ }
+
+ private SimpleTextureView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ setSurfaceTextureListener(this);
+ }
+
+ private SimpleTextureView(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ setSurfaceTextureListener(this);
+ }
+
+ @Override
+ public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
+ System.out.println("SurfaceTexture available");
+ }
+
+ @Override
+ public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
+ System.out.println("SurfaceTexture size changed to " + width + ", " + height);
+ Canvas canvas = lockCanvas();
+ canvas.drawColor(mColor);
+ unlockCanvasAndPost(canvas);
+ }
+
+ @Override
+ public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
+ return false;
+ }
+
+ @Override
+ public void onSurfaceTextureUpdated(SurfaceTexture surface) {
+ System.out.println("SurfaceTexture updated");
+ }
+ }
+}
diff --git a/tests/TransitionTests/src/com/android/transitiontests/UniqueIds.java b/tests/TransitionTests/src/com/android/transitiontests/UniqueIds.java
new file mode 100644
index 0000000..18537c7
--- /dev/null
+++ b/tests/TransitionTests/src/com/android/transitiontests/UniqueIds.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2013 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 com.android.transitiontests;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.transition.Scene;
+import android.view.transition.Transition;
+import android.widget.Button;
+import android.widget.LinearLayout;
+import android.view.transition.TransitionManager;
+import com.android.transitiontest.R;
+
+
+import java.util.HashMap;
+
+public class UniqueIds extends Activity {
+ ViewGroup mSceneRoot;
+ static Scene mCurrentScene;
+ TransitionManager mTransitionManager = null;
+ HashMap<Button, ToggleScene> mSceneMap = new HashMap<Button, ToggleScene>();
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.unique_id_test);
+
+ LinearLayout container = (LinearLayout) findViewById(R.id.container);
+ LayoutInflater inflater = getLayoutInflater();
+ Button button = (Button) inflater.inflate(R.layout.button_template, null);
+ container.addView(button);
+ ToggleScene scene = new ToggleScene(container, button);
+ mSceneMap.put(button, scene);
+ button = (Button) inflater.inflate(R.layout.button_template, null);
+ container.addView(button);
+ scene = new ToggleScene(container, button);
+ mSceneMap.put(button, scene);
+ }
+
+ public void sendMessage(View view) {
+ mSceneMap.get(view).changeToScene();
+ }
+
+ class ToggleScene {
+ Scene mScene;
+ Transition mTransition;
+ Button mButton;
+
+ ToggleScene(ViewGroup rootView, Button button) {
+ mScene = new Scene(rootView);
+ mButton = button;
+ mScene.setEnterAction(new Runnable() {
+ @Override
+ public void run() {
+ if (mButton.getLeft() == 0) {
+ mButton.offsetLeftAndRight(500);
+ } else {
+ int width = mButton.getWidth();
+ mButton.setLeft(0);
+ mButton.setRight(width);
+ }
+ }
+ });
+ }
+
+ void changeToScene() {
+ TransitionManager.go(mScene);
+ }
+ }
+}
diff --git a/tools/aapt/Resource.cpp b/tools/aapt/Resource.cpp
index 77168f9..fe5c810 100644
--- a/tools/aapt/Resource.cpp
+++ b/tools/aapt/Resource.cpp
@@ -172,6 +172,7 @@ private:
bool isValidResourceType(const String8& type)
{
return type == "anim" || type == "animator" || type == "interpolator"
+ || type == "transition" || type == "scene"
|| type == "drawable" || type == "layout"
|| type == "values" || type == "xml" || type == "raw"
|| type == "color" || type == "menu" || type == "mipmap";
@@ -932,6 +933,8 @@ status_t buildResources(Bundle* bundle, const sp<AaptAssets>& assets)
sp<ResourceTypeSet> anims;
sp<ResourceTypeSet> animators;
sp<ResourceTypeSet> interpolators;
+ sp<ResourceTypeSet> transitions;
+ sp<ResourceTypeSet> scenes;
sp<ResourceTypeSet> xmls;
sp<ResourceTypeSet> raws;
sp<ResourceTypeSet> colors;
@@ -943,6 +946,8 @@ status_t buildResources(Bundle* bundle, const sp<AaptAssets>& assets)
ASSIGN_IT(anim);
ASSIGN_IT(animator);
ASSIGN_IT(interpolator);
+ ASSIGN_IT(transition);
+ ASSIGN_IT(scene);
ASSIGN_IT(xml);
ASSIGN_IT(raw);
ASSIGN_IT(color);
@@ -965,6 +970,8 @@ status_t buildResources(Bundle* bundle, const sp<AaptAssets>& assets)
!applyFileOverlay(bundle, assets, &anims, "anim") ||
!applyFileOverlay(bundle, assets, &animators, "animator") ||
!applyFileOverlay(bundle, assets, &interpolators, "interpolator") ||
+ !applyFileOverlay(bundle, assets, &transitions, "transition") ||
+ !applyFileOverlay(bundle, assets, &scenes, "scene") ||
!applyFileOverlay(bundle, assets, &xmls, "xml") ||
!applyFileOverlay(bundle, assets, &raws, "raw") ||
!applyFileOverlay(bundle, assets, &colors, "color") ||
@@ -1024,6 +1031,20 @@ status_t buildResources(Bundle* bundle, const sp<AaptAssets>& assets)
}
}
+ if (transitions != NULL) {
+ err = makeFileResources(bundle, assets, &table, transitions, "transition");
+ if (err != NO_ERROR) {
+ hasErrors = true;
+ }
+ }
+
+ if (scenes != NULL) {
+ err = makeFileResources(bundle, assets, &table, scenes, "scene");
+ if (err != NO_ERROR) {
+ hasErrors = true;
+ }
+ }
+
if (interpolators != NULL) {
err = makeFileResources(bundle, assets, &table, interpolators, "interpolator");
if (err != NO_ERROR) {
@@ -1168,6 +1189,36 @@ status_t buildResources(Bundle* bundle, const sp<AaptAssets>& assets)
err = NO_ERROR;
}
+ if (transitions != NULL) {
+ ResourceDirIterator it(transitions, String8("transition"));
+ while ((err=it.next()) == NO_ERROR) {
+ err = compileXmlFile(assets, it.getFile(), &table, xmlFlags);
+ if (err != NO_ERROR) {
+ hasErrors = true;
+ }
+ }
+
+ if (err < NO_ERROR) {
+ hasErrors = true;
+ }
+ err = NO_ERROR;
+ }
+
+ if (scenes != NULL) {
+ ResourceDirIterator it(scenes, String8("scene"));
+ while ((err=it.next()) == NO_ERROR) {
+ err = compileXmlFile(assets, it.getFile(), &table, xmlFlags);
+ if (err != NO_ERROR) {
+ hasErrors = true;
+ }
+ }
+
+ if (err < NO_ERROR) {
+ hasErrors = true;
+ }
+ err = NO_ERROR;
+ }
+
if (xmls != NULL) {
ResourceDirIterator it(xmls, String8("xml"));
while ((err=it.next()) == NO_ERROR) {