Add tests for animator cloning and inflater

Bug: 17456416
Change-Id: I03b97df20d5920fff7305c5778f6633752449197
diff --git a/tests/tests/animation/src/android/animation/cts/AnimatorSetTest.java b/tests/tests/animation/src/android/animation/cts/AnimatorSetTest.java
index 35a0b4c..3ececed 100644
--- a/tests/tests/animation/src/android/animation/cts/AnimatorSetTest.java
+++ b/tests/tests/animation/src/android/animation/cts/AnimatorSetTest.java
@@ -16,8 +16,11 @@
 package android.animation.cts;
 
 import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Set;
 
 import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
 import android.animation.AnimatorSet;
 import android.animation.ObjectAnimator;
 import android.animation.TimeInterpolator;
@@ -25,6 +28,7 @@
 import android.test.ActivityInstrumentationTestCase2;
 import android.view.animation.AccelerateDecelerateInterpolator;
 import android.view.animation.AccelerateInterpolator;
+import android.view.animation.LinearInterpolator;
 
 public class AnimatorSetTest extends
         ActivityInstrumentationTestCase2<AnimationActivity> {
@@ -34,6 +38,7 @@
     private Object object;
     private ObjectAnimator yAnimator;
     private ObjectAnimator xAnimator;
+    Set<Integer> identityHashes = new HashSet<Integer>();
 
     public AnimatorSetTest() {
         super(AnimationActivity.class);
@@ -158,4 +163,81 @@
             }
         });
     }
+
+    private void assertUnique(Object object) {
+        assertUnique(object, "");
+    }
+
+    private void assertUnique(Object object, String msg) {
+        final int code = System.identityHashCode(object);
+        assertTrue("object should be unique " + msg + ", obj:" + object, identityHashes.add(code));
+
+    }
+
+    public void testClone() {
+        AnimatorSet set1 = new AnimatorSet();
+        final AnimatorListenerAdapter setListener = new AnimatorListenerAdapter() {};
+        set1.addListener(setListener);
+        ObjectAnimator animator1 = new ObjectAnimator();
+        animator1.setDuration(100);
+        animator1.setPropertyName("x");
+        animator1.setIntValues(5);
+        animator1.setInterpolator(new LinearInterpolator());
+        AnimatorListenerAdapter listener1 = new AnimatorListenerAdapter(){};
+        AnimatorListenerAdapter listener2 = new AnimatorListenerAdapter(){};
+        animator1.addListener(listener1);
+
+        ObjectAnimator animator2 = new ObjectAnimator();
+        animator2.setDuration(100);
+        animator2.setInterpolator(new LinearInterpolator());
+        animator2.addListener(listener2);
+        animator2.setPropertyName("y");
+        animator2.setIntValues(10);
+
+        set1.playTogether(animator1, animator2);
+
+        AnimateObject target = new AnimateObject();
+        set1.setTarget(target);
+        set1.start();
+        assertTrue(set1.isStarted());
+
+        animator1.getListeners();
+        AnimatorSet set2 = set1.clone();
+        assertFalse(set2.isStarted());
+
+        assertUnique(set1);
+        assertUnique(animator1);
+        assertUnique(animator2);
+
+        assertUnique(set2);
+        assertEquals(2, set2.getChildAnimations().size());
+
+        Animator clone1 = set2.getChildAnimations().get(0);
+        Animator clone2 = set2.getChildAnimations().get(1);
+
+        for (Animator animator : set2.getChildAnimations()) {
+            assertUnique(animator);
+        }
+
+        assertTrue(clone1.getListeners().contains(listener1));
+        assertTrue(clone2.getListeners().contains(listener2));
+
+        assertTrue(set2.getListeners().contains(setListener));
+        assertEquals(set1.getChangingConfigurations(), set2.getChangingConfigurations());
+
+
+        for (Animator.AnimatorListener listener : set1.getListeners()) {
+            assertTrue(set2.getListeners().contains(listener));
+        }
+
+        assertEquals(animator1.getDuration(), clone1.getDuration());
+        assertEquals(animator2.getDuration(), clone2.getDuration());
+        assertSame(animator1.getInterpolator(), clone1.getInterpolator());
+        assertSame(animator2.getInterpolator(), clone2.getInterpolator());
+    }
+
+    class AnimateObject {
+        int x = 1;
+        int y = 2;
+    }
 }
diff --git a/tests/tests/view/res/anim-land/changing_reset_state_anim.xml b/tests/tests/view/res/anim-land/changing_reset_state_anim.xml
new file mode 100644
index 0000000..0b3279a
--- /dev/null
+++ b/tests/tests/view/res/anim-land/changing_reset_state_anim.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+<set xmlns:android="http://schemas.android.com/apk/res/android">
+    <objectAnimator android:propertyName="x" android:duration="100" android:valueTo="100dp" android:valueType="floatType"/>
+    <objectAnimator android:propertyName="y" android:duration="100" android:valueTo="100dp" android:valueType="floatType"/>
+    <objectAnimator android:propertyName="z" android:duration="100" android:valueTo="100dp" android:valueType="floatType"/>
+</set>
\ No newline at end of file
diff --git a/tests/tests/view/res/anim-land/changing_state_list_animator.xml b/tests/tests/view/res/anim-land/changing_state_list_animator.xml
new file mode 100644
index 0000000..4c1c41e
--- /dev/null
+++ b/tests/tests/view/res/anim-land/changing_state_list_animator.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_pressed="true">
+        <objectAnimator android:propertyName="x" android:duration="100" android:valueTo="10" android:valueType="floatType"/>
+    </item>
+    <!-- base state-->
+    <item>
+        <objectAnimator android:propertyName="x" android:duration="100" android:valueTo="200dp" android:valueType="floatType"/>
+    </item>
+</selector>
\ No newline at end of file
diff --git a/tests/tests/view/res/anim-land/changing_test_animator.xml b/tests/tests/view/res/anim-land/changing_test_animator.xml
new file mode 100644
index 0000000..d5c83cd
--- /dev/null
+++ b/tests/tests/view/res/anim-land/changing_test_animator.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+<!-- if you change this, you should also change AnimatorInflaterTest#testLoadAnimator-->
+<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
+                android:propertyName="x" android:duration="100"
+                android:interpolator="@android:anim/bounce_interpolator"
+                android:valueTo="1" android:valueType="floatType"/>
\ No newline at end of file
diff --git a/tests/tests/view/res/anim/changing_reset_state_anim.xml b/tests/tests/view/res/anim/changing_reset_state_anim.xml
new file mode 100644
index 0000000..dd2b233
--- /dev/null
+++ b/tests/tests/view/res/anim/changing_reset_state_anim.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+<set xmlns:android="http://schemas.android.com/apk/res/android">
+    <objectAnimator android:propertyName="x" android:duration="100" android:valueTo="50dp" android:valueType="floatType"/>
+    <objectAnimator android:propertyName="y" android:duration="100" android:valueTo="50dp" android:valueType="floatType"/>
+    <objectAnimator android:propertyName="z" android:duration="100" android:valueTo="50dp" android:valueType="floatType"/>
+</set>
\ No newline at end of file
diff --git a/tests/tests/view/res/anim/changing_state_list_animator.xml b/tests/tests/view/res/anim/changing_state_list_animator.xml
new file mode 100644
index 0000000..6bcc0d9
--- /dev/null
+++ b/tests/tests/view/res/anim/changing_state_list_animator.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_pressed="true">
+        <objectAnimator android:propertyName="x" android:duration="100" android:valueTo="10" android:valueType="floatType"/>
+    </item>
+    <!-- base state-->
+    <item>
+        <objectAnimator android:propertyName="x" android:duration="100" android:valueTo="100dp" android:valueType="floatType"/>
+    </item>
+</selector>
\ No newline at end of file
diff --git a/tests/tests/view/res/anim/changing_test_animator.xml b/tests/tests/view/res/anim/changing_test_animator.xml
new file mode 100644
index 0000000..739a71b
--- /dev/null
+++ b/tests/tests/view/res/anim/changing_test_animator.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+<!-- if you change this, you should also change AnimatorInflaterTest#testLoadAnimator-->
+<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
+                android:propertyName="x" android:duration="100"
+                android:interpolator="@android:anim/accelerate_decelerate_interpolator"
+                android:valueTo="1" android:valueType="floatType"/>
\ No newline at end of file
diff --git a/tests/tests/view/res/anim/reset_state_anim.xml b/tests/tests/view/res/anim/reset_state_anim.xml
new file mode 100644
index 0000000..4bbbe62
--- /dev/null
+++ b/tests/tests/view/res/anim/reset_state_anim.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+<set xmlns:android="http://schemas.android.com/apk/res/android">
+    <objectAnimator android:propertyName="x" android:duration="100" android:valueTo="0" android:valueType="floatType"/>
+    <objectAnimator android:propertyName="y" android:duration="100" android:valueTo="0" android:valueType="floatType"/>
+    <objectAnimator android:propertyName="z" android:duration="100" android:valueTo="0" android:valueType="floatType"/>
+</set>
\ No newline at end of file
diff --git a/tests/tests/view/res/anim/test_animator.xml b/tests/tests/view/res/anim/test_animator.xml
new file mode 100644
index 0000000..94e9ec8
--- /dev/null
+++ b/tests/tests/view/res/anim/test_animator.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+<set xmlns:android="http://schemas.android.com/apk/res/android">
+    <!-- if you change this, you should also change AnimatorInflaterTest#testLoadAnimator-->
+    <objectAnimator android:propertyName="x" android:duration="100" android:valueTo="@dimen/test_animator_target_x" android:valueType="floatType"/>
+    <objectAnimator android:propertyName="y" android:duration="100" android:valueTo="@dimen/test_animator_target_y" android:valueType="floatType"/>
+    <objectAnimator android:propertyName="left" android:duration="100" android:valueTo="2" android:valueType="intType"/>
+</set>
\ No newline at end of file
diff --git a/tests/tests/view/res/anim/test_state_list_animator.xml b/tests/tests/view/res/anim/test_state_list_animator.xml
new file mode 100644
index 0000000..b6a4822
--- /dev/null
+++ b/tests/tests/view/res/anim/test_state_list_animator.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_pressed="true">
+        <set>
+            <objectAnimator android:propertyName="x" android:duration="100" android:valueTo="10" android:valueType="floatType"/>
+            <objectAnimator android:propertyName="y" android:duration="100" android:valueTo="20" android:valueType="floatType"/>
+            <objectAnimator android:propertyName="z" android:duration="100" android:valueTo="20" android:valueType="floatType"/>
+        </set>
+    </item>
+    <item android:state_enabled="true" android:state_pressed="false">
+        <set>
+            <objectAnimator android:propertyName="x" android:duration="100" android:valueTo="0" android:valueType="floatType"/>
+            <objectAnimator android:propertyName="y" android:duration="100" android:valueTo="0" android:valueType="floatType"/>
+            <objectAnimator android:propertyName="z" android:duration="100" android:valueTo="0" android:valueType="floatType"/>
+        </set>
+    </item>
+    <!-- base state-->
+    <item android:animation="@anim/reset_state_anim"/>
+</selector>
\ No newline at end of file
diff --git a/tests/tests/view/res/anim/test_state_list_animator_2.xml b/tests/tests/view/res/anim/test_state_list_animator_2.xml
new file mode 100644
index 0000000..6aeb41f
--- /dev/null
+++ b/tests/tests/view/res/anim/test_state_list_animator_2.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_pressed="true">
+        <objectAnimator android:propertyName="x" android:duration="100" android:valueTo="10" android:valueType="floatType"/>
+    </item>
+    <!-- base state-->
+    <item android:animation="@anim/changing_reset_state_anim"/>
+</selector>
\ No newline at end of file
diff --git a/tests/tests/view/res/values-land/dimens.xml b/tests/tests/view/res/values-land/dimens.xml
new file mode 100644
index 0000000..17b5395
--- /dev/null
+++ b/tests/tests/view/res/values-land/dimens.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+<resources>
+    <dimen name="test_animator_target_y">30dp</dimen>
+    <!-- this value is equal to the value in changing_reset_state_anim. It is NOT referenced
+    in the XML on purpose-->
+    <dimen name="reset_state_value">100dp</dimen>
+    <!-- this value is equal to the value in changing_state_list_animator. It is NOT referenced in the XML on purpose-->
+    <dimen name="changing_state_list_anim_target_x_value">200dp</dimen>
+</resources>
\ No newline at end of file
diff --git a/tests/tests/view/res/values/dimens.xml b/tests/tests/view/res/values/dimens.xml
new file mode 100644
index 0000000..16e5084
--- /dev/null
+++ b/tests/tests/view/res/values/dimens.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+<resources>
+    <dimen name="test_animator_target_x">10dp</dimen>
+    <dimen name="test_animator_target_y">20dp</dimen>
+    <!-- this value is equal to the value in changing_reset_state_anim. It is NOT referenced in the XML on purpose-->
+    <dimen name="reset_state_value">50dp</dimen>
+    <!-- this value is equal to the value in changing_state_list_animator. It is NOT referenced in the XML on purpose-->
+    <dimen name="changing_state_list_anim_target_x_value">100dp</dimen>
+</resources>
\ No newline at end of file
diff --git a/tests/tests/view/src/android/view/animation/cts/AnimatorInflaterTest.java b/tests/tests/view/src/android/view/animation/cts/AnimatorInflaterTest.java
new file mode 100644
index 0000000..eeda5a3
--- /dev/null
+++ b/tests/tests/view/src/android/view/animation/cts/AnimatorInflaterTest.java
@@ -0,0 +1,271 @@
+/*
+* Copyright (C) 2014 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+package android.view.animation.cts;
+
+import android.animation.Animator;
+import android.animation.AnimatorInflater;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.animation.StateListAnimator;
+import android.app.Activity;
+import android.app.Instrumentation;
+import android.content.pm.ActivityInfo;
+import android.content.res.Configuration;
+import android.os.Debug;
+import android.test.ActivityInstrumentationTestCase2;
+import android.view.View;
+
+import java.util.HashSet;
+import java.util.Set;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import com.android.cts.view.R;
+
+public class AnimatorInflaterTest
+        extends ActivityInstrumentationTestCase2<AnimationTestCtsActivity> {
+
+    Set<Integer> identityHashes = new HashSet<Integer>();
+
+    public AnimatorInflaterTest() {
+        super("com.android.cts.view", AnimationTestCtsActivity.class);
+    }
+
+    private void assertUnique(Object object) {
+        assertUnique(object, "");
+    }
+
+    private void assertUnique(Object object, String msg) {
+        final int code = System.identityHashCode(object);
+        assertTrue("object should be unique " + msg + ", obj:" + object, identityHashes.add(code));
+
+    }
+
+    public void testLoadAnimatorWithDifferentInterpolators() throws Throwable {
+        Animator anim1 = AnimatorInflater
+                .loadAnimator(getActivity(), R.anim.changing_test_animator);
+        rotate();
+        Animator anim2 = AnimatorInflater
+                .loadAnimator(getActivity(), R.anim.changing_test_animator);
+        assertNotSame(anim1, anim2);
+        assertNotSame("interpolater is orientation dependent, should change",
+                anim1.getInterpolator(), anim2.getInterpolator());
+    }
+
+    /**
+     * Tests animators with dimension references.
+     */
+    public void testLoadAnimator() throws Throwable {
+        // to identify objects
+        Animator anim1 = AnimatorInflater.loadAnimator(getActivity(), R.anim.test_animator);
+        Animator anim2 = AnimatorInflater.loadAnimator(getActivity(), R.anim.test_animator);
+        assertNotSame("a different animation should be returned", anim1, anim2);
+        assertSame("interpolator should be shallow cloned", anim1.getInterpolator(),
+                anim2.getInterpolator());
+        for (int i = 0; i < 2; i++) {
+            float targetX = getActivity().getResources()
+                    .getDimension(R.dimen.test_animator_target_x);
+            // y value changes in landscape orientation
+            float targetY = getActivity().getResources()
+                    .getDimension(R.dimen.test_animator_target_y);
+            for (Animator anim : new Animator[]{anim1, anim2}) {
+                assertTrue(anim instanceof AnimatorSet);
+                assertUnique(anim);
+                AnimatorSet set = (AnimatorSet) anim;
+                assertEquals("should have 3 sub animations", 3, set.getChildAnimations().size());
+                for (Animator subAnim : set.getChildAnimations()) {
+                    assertUnique(subAnim);
+                    assertTrue(subAnim instanceof ObjectAnimator);
+                }
+                final ObjectAnimator child1 = (ObjectAnimator) set.getChildAnimations().get(0);
+                final ObjectAnimator child2 = (ObjectAnimator) set.getChildAnimations().get(1);
+                final DummyObject dummyObject = new DummyObject();
+                runTestOnUiThread(new Runnable() {
+                    @Override
+                    public void run() {
+                        for (ObjectAnimator animator : new ObjectAnimator[]{child1, child2}) {
+                            animator.setTarget(dummyObject);
+                            animator.setupStartValues();
+                            animator.start();
+                            animator.end();
+                        }
+                    }
+                });
+                assertEquals(targetX, dummyObject.x);
+                assertEquals(targetY, dummyObject.y);
+            }
+            if (i == 0) {
+                rotate();
+            }
+            anim1 = AnimatorInflater.loadAnimator(getActivity(), R.anim.test_animator);
+            anim2 = AnimatorInflater.loadAnimator(getActivity(), R.anim.test_animator);
+
+        }
+    }
+
+    private void rotate() throws Throwable {
+        final Activity activity = getActivity();
+        int orientation = activity.getResources().getConfiguration().orientation;
+        final int nextOrientation = orientation == Configuration.ORIENTATION_LANDSCAPE
+                ? ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
+                : ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
+        Instrumentation.ActivityMonitor monitor = new Instrumentation.ActivityMonitor(
+                activity.getClass().getName(), null, false);
+        getInstrumentation().addMonitor(monitor);
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                activity.setRequestedOrientation(nextOrientation);
+            }
+        });
+        getInstrumentation().waitForIdleSync();
+        Activity newAct = getInstrumentation()
+                .waitForMonitorWithTimeout(monitor, TimeUnit.SECONDS.toMillis(2));
+        if (newAct != null) {
+            setActivity(newAct);
+        }
+    }
+
+    /**
+     * Simple state list animator test that checks for cloning
+     */
+    public void testLoadStateListAnimator() {
+        StateListAnimator sla1 = AnimatorInflater.loadStateListAnimator(getActivity(),
+                R.anim.test_state_list_animator);
+        StateListAnimator sla2 = AnimatorInflater.loadStateListAnimator(getActivity(),
+                R.anim.test_state_list_animator);
+        assertUnique(sla1);
+        assertUnique(sla2);
+    }
+
+    /**
+     * Tests a state list animator which has an @anim reference that has different xmls per
+     * orientation
+     */
+    public void testLoadStateListAnimatorWithChangingResetState() throws Throwable {
+        loadStateListAnimatorWithChangingResetStateTest();
+        rotate();
+        loadStateListAnimatorWithChangingResetStateTest();
+    }
+
+    private void loadStateListAnimatorWithChangingResetStateTest() throws Throwable {
+        final StateListAnimator sla = AnimatorInflater.loadStateListAnimator(getActivity(),
+                R.anim.test_state_list_animator_2);
+        final View testView = getTestView();
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                testView.setStateListAnimator(sla);
+                testView.jumpDrawablesToCurrentState();
+            }
+        });
+        float resetValue = getActivity().getResources().getDimension(R.dimen.reset_state_value);
+        getInstrumentation().waitForIdleSync();
+        assertEquals(resetValue, testView.getX());
+        assertEquals(resetValue, testView.getY());
+        assertEquals(resetValue, testView.getZ());
+    }
+
+    /**
+     * Tests a state list animator which has different xml descriptions per orientation.
+     */
+    public void testLoadChangingStateListAnimator() throws Throwable {
+        loadChangingStateListAnimatorTest();
+        rotate();
+        loadChangingStateListAnimatorTest();
+    }
+
+    private void loadChangingStateListAnimatorTest() throws Throwable {
+        final StateListAnimator sla = AnimatorInflater.loadStateListAnimator(getActivity(),
+                R.anim.changing_state_list_animator);
+        final View testView = getTestView();
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                testView.setStateListAnimator(sla);
+                testView.jumpDrawablesToCurrentState();
+            }
+        });
+        float targetValue = getActivity().getResources()
+                .getDimension(R.dimen.changing_state_list_anim_target_x_value);
+        getInstrumentation().waitForIdleSync();
+        assertEquals(targetValue, testView.getX());
+    }
+
+    /**
+     * Tests that makes sure that reloaded animator is not affected by previous changes
+     */
+    public void testReloadedAnimatorIsNotModified() throws Throwable {
+        final Animator anim1 = AnimatorInflater.loadAnimator(getActivity(), R.anim.test_animator);
+        final CountDownLatch mStarted = new CountDownLatch(1);
+        final AnimatorListenerAdapter listener = new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                super.onAnimationEnd(animation);
+            }
+
+            @Override
+            public void onAnimationStart(Animator animation) {
+                super.onAnimationStart(animation);
+                mStarted.countDown();
+            }
+        };
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                anim1.setTarget(getTestView());
+                anim1.addListener(listener);
+                anim1.start();
+            }
+        });
+        Animator anim2 = AnimatorInflater.loadAnimator(getActivity(), R.anim.test_animator);
+        assertTrue(anim1.isStarted());
+        assertFalse(anim2.isStarted());
+        assertFalse("anim2 should not include the listener",
+                anim2.getListeners() != null && anim2.getListeners().contains(listener));
+        assertTrue("animator should start", mStarted.await(10, TimeUnit.SECONDS));
+        assertFalse(anim2.isRunning());
+
+    }
+
+    public View getTestView() {
+        return getActivity().findViewById(R.id.anim_window);
+    }
+
+    class DummyObject {
+
+        float x;
+        float y;
+
+        public float getX() {
+            return x;
+        }
+
+        public void setX(float x) {
+            this.x = x;
+        }
+
+        public float getY() {
+            return y;
+        }
+
+        public void setY(float y) {
+            this.y = y;
+        }
+    }
+}
+