am 58cbe71c: am 8654b6c6: am 3ff1591c: am 28b127ec: New DevBytes animation demos

* commit '58cbe71cc434d787e54d3b3a1d7d86af9727857c':
  New DevBytes animation demos
diff --git a/samples/devbytes/animation/ActivityAnimations/AndroidManifest.xml b/samples/devbytes/animation/ActivityAnimations/AndroidManifest.xml
new file mode 100644
index 0000000..eeb5378
--- /dev/null
+++ b/samples/devbytes/animation/ActivityAnimations/AndroidManifest.xml
@@ -0,0 +1,45 @@
+<!-- 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.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="com.example.android.activityanim"
+          android:versionCode="1"
+          android:versionName="1.0" >
+
+    <uses-sdk
+            android:minSdkVersion="16"
+            android:targetSdkVersion="17" />
+
+    <application
+            android:allowBackup="true"
+            android:icon="@drawable/ic_launcher"
+            android:label="@string/app_name"
+            android:theme="@style/AppTheme" >
+        <activity
+                android:name="com.example.android.activityanim.ActivityAnimations"
+                android:label="@string/app_name" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+        <activity
+                android:name="com.example.android.activityanim.PictureDetailsActivity"
+                android:label="@string/subactivity_name"
+                android:theme="@style/Transparent" >
+        </activity>
+    </application>
+
+</manifest>
\ No newline at end of file
diff --git a/samples/devbytes/animation/ActivityAnimations/res/drawable-hdpi/ic_launcher.png b/samples/devbytes/animation/ActivityAnimations/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..96a442e
--- /dev/null
+++ b/samples/devbytes/animation/ActivityAnimations/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/samples/devbytes/animation/ActivityAnimations/res/drawable-mdpi/ic_launcher.png b/samples/devbytes/animation/ActivityAnimations/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..359047d
--- /dev/null
+++ b/samples/devbytes/animation/ActivityAnimations/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/samples/devbytes/animation/ActivityAnimations/res/drawable-nodpi/p1.jpg b/samples/devbytes/animation/ActivityAnimations/res/drawable-nodpi/p1.jpg
new file mode 100644
index 0000000..9745818
--- /dev/null
+++ b/samples/devbytes/animation/ActivityAnimations/res/drawable-nodpi/p1.jpg
Binary files differ
diff --git a/samples/devbytes/animation/ActivityAnimations/res/drawable-nodpi/p2.jpg b/samples/devbytes/animation/ActivityAnimations/res/drawable-nodpi/p2.jpg
new file mode 100644
index 0000000..db8731f
--- /dev/null
+++ b/samples/devbytes/animation/ActivityAnimations/res/drawable-nodpi/p2.jpg
Binary files differ
diff --git a/samples/devbytes/animation/ActivityAnimations/res/drawable-nodpi/p3.jpg b/samples/devbytes/animation/ActivityAnimations/res/drawable-nodpi/p3.jpg
new file mode 100644
index 0000000..b240b3a
--- /dev/null
+++ b/samples/devbytes/animation/ActivityAnimations/res/drawable-nodpi/p3.jpg
Binary files differ
diff --git a/samples/devbytes/animation/ActivityAnimations/res/drawable-nodpi/p4.jpg b/samples/devbytes/animation/ActivityAnimations/res/drawable-nodpi/p4.jpg
new file mode 100644
index 0000000..4de9292
--- /dev/null
+++ b/samples/devbytes/animation/ActivityAnimations/res/drawable-nodpi/p4.jpg
Binary files differ
diff --git a/samples/devbytes/animation/ActivityAnimations/res/drawable-xhdpi/ic_launcher.png b/samples/devbytes/animation/ActivityAnimations/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..71c6d76
--- /dev/null
+++ b/samples/devbytes/animation/ActivityAnimations/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/devbytes/animation/ActivityAnimations/res/layout/activity_animations.xml b/samples/devbytes/animation/ActivityAnimations/res/layout/activity_animations.xml
new file mode 100644
index 0000000..c11a568
--- /dev/null
+++ b/samples/devbytes/animation/ActivityAnimations/res/layout/activity_animations.xml
@@ -0,0 +1,21 @@
+<!-- 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.
+-->
+<GridLayout xmlns:android="http://schemas.android.com/apk/res/android"
+        android:layout_width="wrap_content"
+        android:layout_height="match_parent"
+        android:layout_gravity="center_horizontal"
+        android:id="@+id/gridLayout" >
+
+</GridLayout>
\ No newline at end of file
diff --git a/samples/devbytes/animation/ActivityAnimations/res/layout/picture_info.xml b/samples/devbytes/animation/ActivityAnimations/res/layout/picture_info.xml
new file mode 100644
index 0000000..cb2ced2
--- /dev/null
+++ b/samples/devbytes/animation/ActivityAnimations/res/layout/picture_info.xml
@@ -0,0 +1,41 @@
+<!-- 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.
+-->
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:id="@+id/topLevelLayout">
+    
+    <view
+        class="com.example.android.activityanim.ShadowLayout"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:id="@+id/shadowLayout"
+        android:visibility="visible" >
+
+        <TextView
+            android:id="@+id/description"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_below="@+id/imageView" />
+        <ImageView
+            android:id="@+id/imageView"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_centerInParent="true"
+            android:scaleType="centerInside" />
+    
+    
+    </view>
+</FrameLayout>
\ No newline at end of file
diff --git a/samples/devbytes/animation/ActivityAnimations/res/menu/activity_better_window_animations.xml b/samples/devbytes/animation/ActivityAnimations/res/menu/activity_better_window_animations.xml
new file mode 100644
index 0000000..aab540e
--- /dev/null
+++ b/samples/devbytes/animation/ActivityAnimations/res/menu/activity_better_window_animations.xml
@@ -0,0 +1,24 @@
+<!-- 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.
+-->
+<menu xmlns:android="http://schemas.android.com/apk/res/android" >
+
+    <item
+        android:id="@+id/menu_slow"
+        android:orderInCategory="100"
+        android:showAsAction="never"
+        android:title="@string/menu_slow_animations"
+        android:checkable="true"/>
+
+</menu>
\ No newline at end of file
diff --git a/samples/devbytes/animation/ActivityAnimations/res/values/strings.xml b/samples/devbytes/animation/ActivityAnimations/res/values/strings.xml
new file mode 100644
index 0000000..f9409b5
--- /dev/null
+++ b/samples/devbytes/animation/ActivityAnimations/res/values/strings.xml
@@ -0,0 +1,21 @@
+<!-- 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.
+-->
+<resources>
+
+    <string name="app_name">Activity Animations</string>
+    <string name="subactivity_name">PictureInfo!</string>
+    <string name="menu_slow_animations">Slow</string>
+
+</resources>
\ No newline at end of file
diff --git a/samples/devbytes/animation/ActivityAnimations/res/values/styles.xml b/samples/devbytes/animation/ActivityAnimations/res/values/styles.xml
new file mode 100644
index 0000000..9d83342
--- /dev/null
+++ b/samples/devbytes/animation/ActivityAnimations/res/values/styles.xml
@@ -0,0 +1,39 @@
+<!-- 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.
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <!--
+        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.Holo.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>
+
+    <style name="Transparent">
+        <item name="android:windowNoTitle">true</item>
+        <item name="android:windowIsTranslucent">true</item>
+        <item name="android:windowBackground">@android:color/transparent</item>
+    </style>
+</resources>
\ No newline at end of file
diff --git a/samples/devbytes/animation/ActivityAnimations/src/com/example/android/activityanim/ActivityAnimations.java b/samples/devbytes/animation/ActivityAnimations/src/com/example/android/activityanim/ActivityAnimations.java
new file mode 100644
index 0000000..4a3e0d9
--- /dev/null
+++ b/samples/devbytes/animation/ActivityAnimations/src/com/example/android/activityanim/ActivityAnimations.java
@@ -0,0 +1,133 @@
+/*
+ * 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.example.android.activityanim;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.content.res.Resources;
+import android.graphics.ColorMatrix;
+import android.graphics.ColorMatrixColorFilter;
+import android.graphics.drawable.BitmapDrawable;
+import android.os.Bundle;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.widget.GridLayout;
+import android.widget.ImageView;
+
+/**
+ * This example shows how to create a custom activity animation when you want something more
+ * than window animations can provide. The idea is to disable window animations for the
+ * activities and to instead launch or return from the sub-activity immediately, but use
+ * property animations inside the activities to customize the transition.
+ *
+ * Watch the associated video for this demo on the DevBytes channel of developer.android.com
+ * or on the DevBytes playlist in the androiddevelopers channel on YouTube at
+ * https://www.youtube.com/playlist?list=PLWz5rJ2EKKc_XOgcRukSoKKjewFJZrKV0.
+ */
+public class ActivityAnimations extends Activity {
+
+    private static final String PACKAGE = "com.example.android.activityanim";
+    static float sAnimatorScale = 1;
+
+    GridLayout mGridLayout;
+    HashMap<ImageView, PictureData> mPicturesData = new HashMap<ImageView, PictureData>();
+    BitmapUtils mBitmapUtils = new BitmapUtils();
+    
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_animations);
+
+        // Grayscale filter used on all thumbnails
+        ColorMatrix grayMatrix = new ColorMatrix();
+        grayMatrix.setSaturation(0);
+        ColorMatrixColorFilter grayscaleFilter = new ColorMatrixColorFilter(grayMatrix);
+        
+        mGridLayout = (GridLayout) findViewById(R.id.gridLayout);
+        mGridLayout.setColumnCount(3);
+        mGridLayout.setUseDefaultMargins(true);
+        
+        // add all photo thumbnails to layout
+        Resources resources = getResources();
+        ArrayList<PictureData> pictures = mBitmapUtils.loadPhotos(resources);
+        for (int i = 0; i < pictures.size(); ++i) {
+            PictureData pictureData = pictures.get(i);
+            BitmapDrawable thumbnailDrawable =
+                    new BitmapDrawable(resources, pictureData.thumbnail);
+            thumbnailDrawable.setColorFilter(grayscaleFilter);
+            ImageView imageView = new ImageView(this);
+            imageView.setOnClickListener(thumbnailClickListener);
+            imageView.setImageDrawable(thumbnailDrawable);
+            mPicturesData.put(imageView, pictureData);
+            mGridLayout.addView(imageView);
+        }
+    }
+
+    @Override
+    public boolean onCreateOptionsMenu(Menu menu) {
+        getMenuInflater().inflate(R.menu.activity_better_window_animations, menu);
+        return true;
+    }
+    
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        if (item.getItemId() == R.id.menu_slow) {
+            sAnimatorScale = item.isChecked() ? 1 : 5;
+            item.setChecked(!item.isChecked());
+        }
+        return super.onOptionsItemSelected(item);
+    }
+
+    /**
+     * When the user clicks a thumbnail, bundle up information about it and launch the
+     * details activity.
+     */
+    private View.OnClickListener thumbnailClickListener = new View.OnClickListener() {
+        
+        @Override
+        public void onClick(View v) {
+            // Interesting data to pass across are the thumbnail size/location, the
+            // resourceId of the source bitmap, the picture description, and the
+            // orientation (to avoid returning back to an obsolete configuration if
+            // the device rotates again in the meantime)
+            int[] screenLocation = new int[2];
+            v.getLocationOnScreen(screenLocation);
+            PictureData info = mPicturesData.get(v);
+            Intent subActivity = new Intent(ActivityAnimations.this,
+                    PictureDetailsActivity.class);
+            int orientation = getResources().getConfiguration().orientation;
+            subActivity.
+                    putExtra(PACKAGE + ".orientation", orientation).
+                    putExtra(PACKAGE + ".resourceId", info.resourceId).
+                    putExtra(PACKAGE + ".left", screenLocation[0]).
+                    putExtra(PACKAGE + ".top", screenLocation[1]).
+                    putExtra(PACKAGE + ".width", v.getWidth()).
+                    putExtra(PACKAGE + ".height", v.getHeight()).
+                    putExtra(PACKAGE + ".description", info.description);
+            startActivity(subActivity);
+            
+            // Override transitions: we don't want the normal window animation in addition
+            // to our custom one
+            overridePendingTransition(0, 0);
+        }
+    };
+
+}
diff --git a/samples/devbytes/animation/ActivityAnimations/src/com/example/android/activityanim/BitmapUtils.java b/samples/devbytes/animation/ActivityAnimations/src/com/example/android/activityanim/BitmapUtils.java
new file mode 100644
index 0000000..a8034dc
--- /dev/null
+++ b/samples/devbytes/animation/ActivityAnimations/src/com/example/android/activityanim/BitmapUtils.java
@@ -0,0 +1,107 @@
+/*
+ * 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.example.android.activityanim;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.drawable.BitmapDrawable;
+import android.widget.ImageView;
+
+public class BitmapUtils {
+    
+    int[] mPhotos = {
+            R.drawable.p1,
+            R.drawable.p2,
+            R.drawable.p3,
+            R.drawable.p4
+    };
+    
+    String[] mDescriptions = {
+            "This picture was taken while sunbathing in a natural hot spring, which was " +
+            "unfortunately filled with acid, which is a lasting memory from that trip, whenever I " +
+            "I look at my own skin.",
+            "I took this shot with a pinhole camera mounted on a tripod constructed out of " +
+            "soda straws. I felt that that combination best captured the beauty of the landscape " +
+            "in juxtaposition with the detritus of mankind.",
+            "I don't remember where or when I took this picture. All I know is that I was really " +
+            "drunk at the time, and I woke up without my left sock.",
+            "Right before I took this picture, there was a busload of school children right " +
+            "in my way. I knew the perfect shot was coming, so I quickly yelled 'Free candy!!!' " +
+            "and they scattered.",
+    };
+
+    static HashMap<Integer, Bitmap> sBitmapResourceMap = new HashMap<Integer, Bitmap>();
+
+    /**
+     * Load pictures and descriptions. A real app wouldn't do it this way, but that's
+     * not the point of this animation demo. Loading asynchronously is a better way to go
+     * for what can be time-consuming operations.
+     */
+    public ArrayList<PictureData> loadPhotos(Resources resources) {
+        ArrayList<PictureData> pictures = new ArrayList<PictureData>();
+        for (int i = 0; i < 30; ++i) {
+            int resourceId = mPhotos[(int) (Math.random() * mPhotos.length)];
+            Bitmap bitmap = getBitmap(resources, resourceId);
+            Bitmap thumbnail = getThumbnail(bitmap, 200);
+            String description = mDescriptions[(int) (Math.random() * mDescriptions.length)];
+            pictures.add(new PictureData(resourceId, description, thumbnail));
+        }
+        return pictures;
+    }
+
+    /**
+     * Utility method to get bitmap from cache or, if not there, load it
+     * from its resource.
+     */
+    static Bitmap getBitmap(Resources resources, int resourceId) {
+        Bitmap bitmap = sBitmapResourceMap.get(resourceId);
+        if (bitmap == null) {
+            bitmap = BitmapFactory.decodeResource(resources, resourceId);
+            sBitmapResourceMap.put(resourceId, bitmap);
+        }        
+        return bitmap;
+    }
+    
+    /**
+     * Create and return a thumbnail image given the original source bitmap and a max
+     * dimension (width or height).
+     */
+    private Bitmap getThumbnail(Bitmap original, int maxDimension) {
+        int width = original.getWidth();
+        int height = original.getHeight();
+        int scaledWidth, scaledHeight;
+        if (width >= height) {
+            float scaleFactor = (float) maxDimension / width;
+            scaledWidth = 200;
+            scaledHeight = (int) (scaleFactor * height);
+        } else {
+            float scaleFactor = (float) maxDimension / height;
+            scaledWidth = (int) (scaleFactor * width);
+            scaledHeight = 200;
+        }
+        Bitmap thumbnail = Bitmap.createScaledBitmap(original, scaledWidth, scaledHeight, true);
+        
+        return thumbnail;
+    }
+    
+
+}
diff --git a/samples/devbytes/animation/ActivityAnimations/src/com/example/android/activityanim/PictureData.java b/samples/devbytes/animation/ActivityAnimations/src/com/example/android/activityanim/PictureData.java
new file mode 100644
index 0000000..eb2d126
--- /dev/null
+++ b/samples/devbytes/animation/ActivityAnimations/src/com/example/android/activityanim/PictureData.java
@@ -0,0 +1,31 @@
+/*
+ * 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.example.android.activityanim;
+
+import android.graphics.Bitmap;
+
+public class PictureData {
+    int resourceId;
+    String description;
+    Bitmap thumbnail;
+    
+    public PictureData(int resourceId, String description, Bitmap thumbnail) {
+        this.resourceId = resourceId;
+        this.description = description;
+        this.thumbnail = thumbnail;
+    }
+}
diff --git a/samples/devbytes/animation/ActivityAnimations/src/com/example/android/activityanim/PictureDetailsActivity.java b/samples/devbytes/animation/ActivityAnimations/src/com/example/android/activityanim/PictureDetailsActivity.java
new file mode 100644
index 0000000..e1674c9
--- /dev/null
+++ b/samples/devbytes/animation/ActivityAnimations/src/com/example/android/activityanim/PictureDetailsActivity.java
@@ -0,0 +1,280 @@
+/*
+ * 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.example.android.activityanim;
+
+import android.animation.ObjectAnimator;
+import android.animation.TimeInterpolator;
+import android.app.Activity;
+import android.graphics.Bitmap;
+import android.graphics.Color;
+import android.graphics.ColorMatrix;
+import android.graphics.ColorMatrixColorFilter;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.ColorDrawable;
+import android.os.Bundle;
+import android.view.View;
+import android.view.ViewTreeObserver;
+import android.view.animation.AccelerateInterpolator;
+import android.view.animation.DecelerateInterpolator;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+/**
+ * This sub-activity shows a zoomed-in view of a specific photo, along with the
+ * picture's text description. Most of the logic is for the animations that will
+ * be run when the activity is being launched and exited. When launching,
+ * the large version of the picture will resize from the thumbnail version in the
+ * main activity, colorizing it from the thumbnail's grayscale version at the
+ * same time. Meanwhile, the black background of the activity will fade in and
+ * the description will eventually slide into place. The exit animation runs all
+ * of this in reverse.
+ * 
+ */
+public class PictureDetailsActivity extends Activity {
+
+    private static final TimeInterpolator sDecelerator = new DecelerateInterpolator();
+    private static final TimeInterpolator sAccelerator = new AccelerateInterpolator();
+    private static final String PACKAGE_NAME = "com.example.android.activityanim";
+    private static final int ANIM_DURATION = 500;
+
+    private BitmapDrawable mBitmapDrawable;
+    private ColorMatrix colorizerMatrix = new ColorMatrix();
+    ColorDrawable mBackground;
+    int mLeftDelta;
+    int mTopDelta;
+    float mWidthScale;
+    float mHeightScale;
+    private ImageView mImageView;
+    private TextView mTextView;
+    private FrameLayout mTopLevelLayout;
+    private ShadowLayout mShadowLayout;
+    private int mOriginalOrientation;
+    
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.picture_info);
+        mImageView = (ImageView) findViewById(R.id.imageView);
+        mTopLevelLayout = (FrameLayout) findViewById(R.id.topLevelLayout);
+        mShadowLayout = (ShadowLayout) findViewById(R.id.shadowLayout);
+        mTextView = (TextView) findViewById(R.id.description);
+        
+        // Retrieve the data we need for the picture/description to display and
+        // the thumbnail to animate it from
+        Bundle bundle = getIntent().getExtras();
+        Bitmap bitmap = BitmapUtils.getBitmap(getResources(),
+                bundle.getInt(PACKAGE_NAME + ".resourceId"));
+        String description = bundle.getString(PACKAGE_NAME + ".description");
+        final int thumbnailTop = bundle.getInt(PACKAGE_NAME + ".top");
+        final int thumbnailLeft = bundle.getInt(PACKAGE_NAME + ".left");
+        final int thumbnailWidth = bundle.getInt(PACKAGE_NAME + ".width");
+        final int thumbnailHeight = bundle.getInt(PACKAGE_NAME + ".height");
+        mOriginalOrientation = bundle.getInt(PACKAGE_NAME + ".orientation");
+        
+        mBitmapDrawable = new BitmapDrawable(getResources(), bitmap);
+        mImageView.setImageDrawable(mBitmapDrawable);
+        mTextView.setText(description);
+        
+        mBackground = new ColorDrawable(Color.BLACK);
+        mTopLevelLayout.setBackground(mBackground);
+
+        // Only run the animation if we're coming from the parent activity, not if
+        // we're recreated automatically by the window manager (e.g., device rotation)
+        if (savedInstanceState == null) {
+            ViewTreeObserver observer = mImageView.getViewTreeObserver();
+            observer.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
+                
+                @Override
+                public boolean onPreDraw() {
+                    mImageView.getViewTreeObserver().removeOnPreDrawListener(this);
+
+                    // Figure out where the thumbnail and full size versions are, relative
+                    // to the screen and each other
+                    int[] screenLocation = new int[2];
+                    mImageView.getLocationOnScreen(screenLocation);
+                    mLeftDelta = thumbnailLeft - screenLocation[0];
+                    mTopDelta = thumbnailTop - screenLocation[1];
+                    
+                    // Scale factors to make the large version the same size as the thumbnail
+                    mWidthScale = (float) thumbnailWidth / mImageView.getWidth();
+                    mHeightScale = (float) thumbnailHeight / mImageView.getHeight();
+    
+                    runEnterAnimation();
+                    
+                    return true;
+                }
+            });
+        }
+    }
+
+    /**
+     * The enter animation scales the picture in from its previous thumbnail
+     * size/location, colorizing it in parallel. In parallel, the background of the
+     * activity is fading in. When the pictue is in place, the text description
+     * drops down.
+     */
+    public void runEnterAnimation() {
+        final long duration = (long) (ANIM_DURATION * ActivityAnimations.sAnimatorScale);
+        
+        // Set starting values for properties we're going to animate. These
+        // values scale and position the full size version down to the thumbnail
+        // size/location, from which we'll animate it back up
+        mImageView.setPivotX(0);
+        mImageView.setPivotY(0);
+        mImageView.setScaleX(mWidthScale);
+        mImageView.setScaleY(mHeightScale);
+        mImageView.setTranslationX(mLeftDelta);
+        mImageView.setTranslationY(mTopDelta);
+        
+        // We'll fade the text in later
+        mTextView.setAlpha(0);
+        
+        // Animate scale and translation to go from thumbnail to full size
+        mImageView.animate().setDuration(duration).
+                scaleX(1).scaleY(1).
+                translationX(0).translationY(0).
+                setInterpolator(sDecelerator).
+                withEndAction(new Runnable() {
+                    public void run() {
+                        // Animate the description in after the image animation
+                        // is done. Slide and fade the text in from underneath
+                        // the picture.
+                        mTextView.setTranslationY(-mTextView.getHeight());
+                        mTextView.animate().setDuration(duration/2).
+                                translationY(0).alpha(1).
+                                setInterpolator(sDecelerator);
+                    }
+                });
+        
+        // Fade in the black background
+        ObjectAnimator bgAnim = ObjectAnimator.ofInt(mBackground, "alpha", 0, 255);
+        bgAnim.setDuration(duration);
+        bgAnim.start();
+        
+        // Animate a color filter to take the image from grayscale to full color.
+        // This happens in parallel with the image scaling and moving into place.
+        ObjectAnimator colorizer = ObjectAnimator.ofFloat(PictureDetailsActivity.this,
+                "saturation", 0, 1);
+        colorizer.setDuration(duration);
+        colorizer.start();
+
+        // Animate a drop-shadow of the image
+        ObjectAnimator shadowAnim = ObjectAnimator.ofFloat(mShadowLayout, "shadowDepth", 0, 1);
+        shadowAnim.setDuration(duration);
+        shadowAnim.start();
+    }
+    
+    /**
+     * The exit animation is basically a reverse of the enter animation, except that if
+     * the orientation has changed we simply scale the picture back into the center of
+     * the screen.
+     * 
+     * @param endAction This action gets run after the animation completes (this is
+     * when we actually switch activities)
+     */
+    public void runExitAnimation(final Runnable endAction) {
+        final long duration = (long) (ANIM_DURATION * ActivityAnimations.sAnimatorScale);
+
+        // No need to set initial values for the reverse animation; the image is at the
+        // starting size/location that we want to start from. Just animate to the
+        // thumbnail size/location that we retrieved earlier 
+        
+        // Caveat: configuration change invalidates thumbnail positions; just animate
+        // the scale around the center. Also, fade it out since it won't match up with
+        // whatever's actually in the center
+        final boolean fadeOut;
+        if (getResources().getConfiguration().orientation != mOriginalOrientation) {
+            mImageView.setPivotX(mImageView.getWidth() / 2);
+            mImageView.setPivotY(mImageView.getHeight() / 2);
+            mLeftDelta = 0;
+            mTopDelta = 0;
+            fadeOut = true;
+        } else {
+            fadeOut = false;
+        }
+
+        // First, slide/fade text out of the way
+        mTextView.animate().translationY(-mTextView.getHeight()).alpha(0).
+                setDuration(duration/2).setInterpolator(sAccelerator).
+                withEndAction(new Runnable() {
+                    public void run() {
+                        // Animate image back to thumbnail size/location
+                        mImageView.animate().setDuration(duration).
+                                scaleX(mWidthScale).scaleY(mHeightScale).
+                                translationX(mLeftDelta).translationY(mTopDelta).
+                                withEndAction(endAction);
+                        if (fadeOut) {
+                            mImageView.animate().alpha(0);
+                        }
+                        // Fade out background
+                        ObjectAnimator bgAnim = ObjectAnimator.ofInt(mBackground, "alpha", 0);
+                        bgAnim.setDuration(duration);
+                        bgAnim.start();
+
+                        // Animate the shadow of the image
+                        ObjectAnimator shadowAnim = ObjectAnimator.ofFloat(mShadowLayout,
+                                "shadowDepth", 1, 0);
+                        shadowAnim.setDuration(duration);
+                        shadowAnim.start();
+
+                        // Animate a color filter to take the image back to grayscale,
+                        // in parallel with the image scaling and moving into place.
+                        ObjectAnimator colorizer =
+                                ObjectAnimator.ofFloat(PictureDetailsActivity.this,
+                                "saturation", 1, 0);
+                        colorizer.setDuration(duration);
+                        colorizer.start();
+                    }
+                });
+
+        
+    }
+
+    /**
+     * Overriding this method allows us to run our exit animation first, then exiting
+     * the activity when it is complete.
+     */
+    @Override
+    public void onBackPressed() {
+        runExitAnimation(new Runnable() {
+            public void run() {
+                // *Now* go ahead and exit the activity
+                finish();
+            }
+        });
+    }
+
+    /**
+     * This is called by the colorizing animator. It sets a saturation factor that is then
+     * passed onto a filter on the picture's drawable.
+     * @param value
+     */
+    public void setSaturation(float value) {
+        colorizerMatrix.setSaturation(value);
+        ColorMatrixColorFilter colorizerFilter = new ColorMatrixColorFilter(colorizerMatrix);
+        mBitmapDrawable.setColorFilter(colorizerFilter);
+    }
+    
+    @Override
+    public void finish() {
+        super.finish();
+        
+        // override transitions to skip the standard window animations
+        overridePendingTransition(0, 0);
+    }
+}
diff --git a/samples/devbytes/animation/ActivityAnimations/src/com/example/android/activityanim/ShadowLayout.java b/samples/devbytes/animation/ActivityAnimations/src/com/example/android/activityanim/ShadowLayout.java
new file mode 100644
index 0000000..b3bc961
--- /dev/null
+++ b/samples/devbytes/animation/ActivityAnimations/src/com/example/android/activityanim/ShadowLayout.java
@@ -0,0 +1,116 @@
+/*
+ * 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.example.android.activityanim;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.BlurMaskFilter;
+import android.graphics.BlurMaskFilter.Blur;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Paint.Style;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.RelativeLayout;
+
+/**
+ * This custom layout paints a drop shadow behind all children. The size and opacity
+ * of the drop shadow is determined by a "depth" factor that can be set and animated.
+ */
+public class ShadowLayout extends RelativeLayout {
+
+    Paint mShadowPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+    float mShadowDepth;
+    Bitmap mShadowBitmap;
+    static final int BLUR_RADIUS = 6;
+    static final RectF sShadowRectF = new RectF(0, 0, 200, 200);
+    static final Rect sShadowRect = new Rect(0, 0, 200 + 2 * BLUR_RADIUS, 200 + 2 * BLUR_RADIUS);
+    static RectF tempShadowRectF = new RectF(0, 0, 0, 0);
+    
+    public ShadowLayout(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+        init();
+    }
+
+    public ShadowLayout(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        init();
+    }
+
+    public ShadowLayout(Context context) {
+        super(context);
+        init();
+    }
+    
+    /**
+     * Called by the constructors - sets up the drawing parameters for the drop shadow.
+     */
+    private void init() {
+        mShadowPaint.setColor(Color.BLACK);
+        mShadowPaint.setStyle(Style.FILL);
+        setWillNotDraw(false);
+        mShadowBitmap = Bitmap.createBitmap(sShadowRect.width(),
+                sShadowRect.height(), Bitmap.Config.ARGB_8888);
+        Canvas c = new Canvas(mShadowBitmap);
+        mShadowPaint.setMaskFilter(new BlurMaskFilter(BLUR_RADIUS, Blur.NORMAL));
+        c.translate(BLUR_RADIUS, BLUR_RADIUS);
+        c.drawRoundRect(sShadowRectF, sShadowRectF.width() / 40,
+                sShadowRectF.height() / 40, mShadowPaint);
+    }
+    
+    /**
+     * The "depth" factor determines the offset distance and opacity of the shadow (shadows that
+     * are further away from the source are offset greater and are more translucent).
+     * @param depth
+     */
+    public void setShadowDepth(float depth) {
+        if (depth != mShadowDepth) {
+            mShadowDepth = depth;
+            mShadowPaint.setAlpha((int) (100 + 150 * (1 - mShadowDepth)));
+            invalidate(); // We need to redraw when the shadow attributes change
+        }
+    }
+
+    /**
+     * Overriding onDraw allows us to draw shadows behind every child of this container.
+     * onDraw() is called to draw a layout's content before the children are drawn, so the
+     * shadows will be drawn first, behind the children (which is what we want).
+     */
+    @Override
+    protected void onDraw(Canvas canvas) {
+        for (int i = 0; i < getChildCount(); ++i) {
+            View child = getChildAt(i);
+            if (child.getVisibility() != View.VISIBLE || child.getAlpha() == 0) {
+                continue;
+            }
+            int depthFactor = (int) (80 * mShadowDepth);
+            canvas.save();
+            canvas.translate(child.getLeft() + depthFactor,
+                    child.getTop() + depthFactor);
+            canvas.concat(child.getMatrix());
+            tempShadowRectF.right = child.getWidth();
+            tempShadowRectF.bottom = child.getHeight();
+            canvas.drawBitmap(mShadowBitmap, sShadowRect, tempShadowRectF, mShadowPaint);
+            canvas.restore();
+        }
+    }
+    
+    
+}
diff --git a/samples/devbytes/animation/Anticipation/AndroidManifest.xml b/samples/devbytes/animation/Anticipation/AndroidManifest.xml
new file mode 100644
index 0000000..c941524
--- /dev/null
+++ b/samples/devbytes/animation/Anticipation/AndroidManifest.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.example.android.anticipation"
+    android:versionCode="1"
+    android:versionName="1.0" >
+
+    <uses-sdk
+        android:minSdkVersion="14"
+        android:targetSdkVersion="17" />
+
+    <application
+        android:allowBackup="true"
+        android:icon="@drawable/ic_launcher"
+        android:label="@string/app_name"
+        android:theme="@style/AppTheme" >
+        <activity
+            android:name="com.example.android.anticipation.Anticipation"
+            android:label="@string/app_name" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+
+</manifest>
\ No newline at end of file
diff --git a/samples/devbytes/animation/Anticipation/res/drawable-hdpi/ic_launcher.png b/samples/devbytes/animation/Anticipation/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..96a442e
--- /dev/null
+++ b/samples/devbytes/animation/Anticipation/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/samples/devbytes/animation/Anticipation/res/drawable-mdpi/ic_launcher.png b/samples/devbytes/animation/Anticipation/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..359047d
--- /dev/null
+++ b/samples/devbytes/animation/Anticipation/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/samples/devbytes/animation/Anticipation/res/drawable-xhdpi/ic_launcher.png b/samples/devbytes/animation/Anticipation/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..71c6d76
--- /dev/null
+++ b/samples/devbytes/animation/Anticipation/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/devbytes/animation/Anticipation/res/layout/main.xml b/samples/devbytes/animation/Anticipation/res/layout/main.xml
new file mode 100644
index 0000000..7da093f
--- /dev/null
+++ b/samples/devbytes/animation/Anticipation/res/layout/main.xml
@@ -0,0 +1,28 @@
+<!-- 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.
+-->
+<LinearLayout 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"
+    android:clipChildren="false"
+    tools:context=".Anticipation" >
+    
+    <view
+        class="com.example.android.anticipation.AnticiButton"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="AnticiButton"/>
+</LinearLayout>
\ No newline at end of file
diff --git a/samples/devbytes/animation/Anticipation/res/values-v14/styles.xml b/samples/devbytes/animation/Anticipation/res/values-v14/styles.xml
new file mode 100644
index 0000000..6e9521a
--- /dev/null
+++ b/samples/devbytes/animation/Anticipation/res/values-v14/styles.xml
@@ -0,0 +1,26 @@
+<!-- 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.
+-->
+<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/samples/devbytes/animation/Anticipation/res/values/strings.xml b/samples/devbytes/animation/Anticipation/res/values/strings.xml
new file mode 100644
index 0000000..9097629
--- /dev/null
+++ b/samples/devbytes/animation/Anticipation/res/values/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<resources>
+
+    <string name="app_name">Anticipation</string>
+    <string name="hello_world">Hello world!</string>
+    <string name="menu_settings">Settings</string>
+
+</resources>
\ No newline at end of file
diff --git a/samples/devbytes/animation/Anticipation/res/values/styles.xml b/samples/devbytes/animation/Anticipation/res/values/styles.xml
new file mode 100644
index 0000000..27658b7
--- /dev/null
+++ b/samples/devbytes/animation/Anticipation/res/values/styles.xml
@@ -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.
+-->
+<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/samples/devbytes/animation/Anticipation/src/com/example/android/anticipation/AnticiButton.java b/samples/devbytes/animation/Anticipation/src/com/example/android/anticipation/AnticiButton.java
new file mode 100644
index 0000000..707765b
--- /dev/null
+++ b/samples/devbytes/animation/Anticipation/src/com/example/android/anticipation/AnticiButton.java
@@ -0,0 +1,230 @@
+/*
+ * 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.example.android.anticipation;
+
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Matrix;
+import android.graphics.RectF;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.animation.AccelerateInterpolator;
+import android.view.animation.DecelerateInterpolator;
+import android.view.animation.LinearInterpolator;
+import android.view.animation.OvershootInterpolator;
+import android.widget.Button;
+
+/**
+ * Custom button which can be deformed by skewing the top left and right, to simulate
+ * anticipation and follow-through animation effects. Clicking on the button runs
+ * an animation which moves the button left or right, applying the skew effect to the
+ * button. The logic of drawing the button with a skew transform is handled in the
+ * draw() override.
+ */
+public class AnticiButton extends Button {
+
+    private static final LinearInterpolator sLinearInterpolator = new LinearInterpolator();
+    private static final DecelerateInterpolator sDecelerator = new DecelerateInterpolator(8);
+    private static final AccelerateInterpolator sAccelerator = new AccelerateInterpolator();
+    private static final OvershootInterpolator sOvershooter = new OvershootInterpolator();
+    private static final DecelerateInterpolator sQuickDecelerator = new DecelerateInterpolator();
+    
+    private float mSkewX = 0;
+    ObjectAnimator downAnim = null;
+    boolean mOnLeft = true;
+    RectF mTempRect = new RectF();
+    
+    public AnticiButton(Context context) {
+        super(context);
+        init();
+    }
+
+    public AnticiButton(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+        init();
+    }
+
+    public AnticiButton(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        init();
+    }
+
+    private void init() {
+        setOnTouchListener(mTouchListener);
+        setOnClickListener(new OnClickListener() {
+            public void onClick(View v) {
+                runClickAnim();
+            }
+        });
+    }
+
+    /**
+     * The skew effect is handled by changing the transform of the Canvas
+     * and then calling the usual superclass draw() method.
+     */
+    @Override
+    public void draw(Canvas canvas) {
+        if (mSkewX != 0) {
+            canvas.translate(0, getHeight());
+            canvas.skew(mSkewX, 0);
+            canvas.translate(0,  -getHeight());
+        }
+        super.draw(canvas);
+    }
+
+    /**
+     * Anticipate the future animation by rearing back, away from the direction of travel
+     */
+    private void runPressAnim() {
+        downAnim = ObjectAnimator.ofFloat(this, "skewX", mOnLeft ? .5f : -.5f);
+        downAnim.setDuration(2500);
+        downAnim.setInterpolator(sDecelerator);
+        downAnim.start();
+    }
+
+    /**
+     * Finish the "anticipation" animation (skew the button back from the direction of
+     * travel), animate it to the other side of the screen, then un-skew the button
+     * with an Overshoot effect.
+     */
+    private void runClickAnim() {
+        // Anticipation
+        ObjectAnimator finishDownAnim = null;
+        if (downAnim != null && downAnim.isRunning()) {
+            // finish the skew animation quickly
+            downAnim.cancel();
+            finishDownAnim = ObjectAnimator.ofFloat(this, "skewX",
+                    mOnLeft ? .5f : -.5f);
+            finishDownAnim.setDuration(150);
+            finishDownAnim.setInterpolator(sQuickDecelerator);
+        }
+        
+        // Slide. Use LinearInterpolator in this rare situation where we want to start
+        // and end fast (no acceleration or deceleration, since we're doing that part
+        // during the anticipation and overshoot phases).
+        ObjectAnimator moveAnim = ObjectAnimator.ofFloat(this,
+                View.TRANSLATION_X, mOnLeft ? 400 : 0);
+        moveAnim.setInterpolator(sLinearInterpolator);
+        moveAnim.setDuration(150);
+        
+        // Then overshoot by stopping the movement but skewing the button as if it couldn't
+        // all stop at once
+        ObjectAnimator skewAnim = ObjectAnimator.ofFloat(this, "skewX",
+                mOnLeft ? -.5f : .5f);
+        skewAnim.setInterpolator(sQuickDecelerator);
+        skewAnim.setDuration(100);
+        // and wobble it
+        ObjectAnimator wobbleAnim = ObjectAnimator.ofFloat(this, "skewX", 0);
+        wobbleAnim.setInterpolator(sOvershooter);
+        wobbleAnim.setDuration(150);
+        AnimatorSet set = new AnimatorSet();
+        set.playSequentially(moveAnim, skewAnim, wobbleAnim);
+        if (finishDownAnim != null) {
+            set.play(finishDownAnim).before(moveAnim);
+        }
+        set.start();
+        mOnLeft = !mOnLeft;
+    }
+
+    /**
+     * Restore the button to its un-pressed state
+     */
+    private void runCancelAnim() {
+        if (downAnim != null && downAnim.isRunning()) {
+            downAnim.cancel();
+            ObjectAnimator reverser = ObjectAnimator.ofFloat(this, "skewX", 0);
+            reverser.setDuration(200);
+            reverser.setInterpolator(sAccelerator);
+            reverser.start();
+            downAnim = null;
+        }
+    }
+
+    /**
+     * Handle touch events directly since we want to react on down/up events, not just
+     * button clicks
+     */
+    private View.OnTouchListener mTouchListener = new View.OnTouchListener() {
+        
+        @Override
+        public boolean onTouch(View v, MotionEvent event) {
+            switch (event.getAction()) {
+            case MotionEvent.ACTION_UP:
+                if (isPressed()) {
+                    performClick();
+                    setPressed(false);
+                    break;
+                }
+                // No click: Fall through; equivalent to cancel event
+            case MotionEvent.ACTION_CANCEL:
+                // Run the cancel animation in either case
+                runCancelAnim();
+                break;
+            case MotionEvent.ACTION_MOVE:
+                float x = event.getX();
+                float y = event.getY();
+                boolean isInside = (x > 0 && x < getWidth() &&
+                        y > 0 && y < getHeight());
+                if (isPressed() != isInside) {
+                    setPressed(isInside);
+                }
+                break;
+            case MotionEvent.ACTION_DOWN:
+                setPressed(true);
+                runPressAnim();
+                break;
+            default:
+                break;
+            }
+            return true;
+        }
+    };
+    
+    public float getSkewX() {
+        return mSkewX;
+    }
+    
+    /**
+     * Sets the amount of left/right skew on the button, which determines how far the button
+     * leans.
+     */
+    public void setSkewX(float value) {
+        if (value != mSkewX) {
+            mSkewX = value;
+            invalidate();             // force button to redraw with new skew value
+            invalidateSkewedBounds(); // also invalidate appropriate area of parent
+        }
+    }
+    
+    /**
+     * Need to invalidate proper area of parent for skewed bounds
+     */
+    private void invalidateSkewedBounds() {
+        if (mSkewX != 0) {
+            Matrix matrix = new Matrix();
+            matrix.setSkew(-mSkewX, 0);
+            mTempRect.set(0, 0, getRight(), getBottom());
+            matrix.mapRect(mTempRect);
+            mTempRect.offset(getLeft() + getTranslationX(), getTop() + getTranslationY());
+            ((View) getParent()).invalidate((int) mTempRect.left, (int) mTempRect.top,
+                    (int) (mTempRect.right +.5f), (int) (mTempRect.bottom + .5f));
+        }
+    }
+}
diff --git a/samples/devbytes/animation/Anticipation/src/com/example/android/anticipation/Anticipation.java b/samples/devbytes/animation/Anticipation/src/com/example/android/anticipation/Anticipation.java
new file mode 100644
index 0000000..4ef8f62
--- /dev/null
+++ b/samples/devbytes/animation/Anticipation/src/com/example/android/anticipation/Anticipation.java
@@ -0,0 +1,40 @@
+/*
+ * 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.example.android.anticipation;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.ViewGroup;
+import android.view.ViewGroup.LayoutParams;
+
+/**
+ * This example shows how to animate some simple deformations on a standard UI widget
+ * to achieve some interactive and cartoon-ish effects.
+ *
+ * Watch the associated video for this demo on the DevBytes channel of developer.android.com
+ * or on the DevBytes playlist in the androiddevelopers channel on YouTube at
+ * https://www.youtube.com/playlist?list=PLWz5rJ2EKKc_XOgcRukSoKKjewFJZrKV0.
+ */
+public class Anticipation extends Activity {
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.main);
+    }
+
+}
diff --git a/samples/devbytes/animation/CurvedMotion/AndroidManifest.xml b/samples/devbytes/animation/CurvedMotion/AndroidManifest.xml
new file mode 100644
index 0000000..195faae
--- /dev/null
+++ b/samples/devbytes/animation/CurvedMotion/AndroidManifest.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.example.android.curvedmotion"
+    android:versionCode="1"
+    android:versionName="1.0" >
+
+    <uses-sdk
+        android:minSdkVersion="11"
+        android:targetSdkVersion="11" />
+
+    <application
+        android:allowBackup="true"
+        android:icon="@drawable/ic_launcher"
+        android:label="@string/app_name"
+        android:theme="@style/AppTheme" >
+        <activity
+            android:name="com.example.android.curvedmotion.CurvedMotion"
+            android:label="@string/app_name" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+
+</manifest>
\ No newline at end of file
diff --git a/samples/devbytes/animation/CurvedMotion/res/drawable-hdpi/ic_launcher.png b/samples/devbytes/animation/CurvedMotion/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..96a442e
--- /dev/null
+++ b/samples/devbytes/animation/CurvedMotion/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/samples/devbytes/animation/CurvedMotion/res/drawable-mdpi/ic_launcher.png b/samples/devbytes/animation/CurvedMotion/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..359047d
--- /dev/null
+++ b/samples/devbytes/animation/CurvedMotion/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/samples/devbytes/animation/CurvedMotion/res/drawable-xhdpi/ic_launcher.png b/samples/devbytes/animation/CurvedMotion/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..71c6d76
--- /dev/null
+++ b/samples/devbytes/animation/CurvedMotion/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/devbytes/animation/CurvedMotion/res/layout/activity_curved_motion.xml b/samples/devbytes/animation/CurvedMotion/res/layout/activity_curved_motion.xml
new file mode 100644
index 0000000..10adea3
--- /dev/null
+++ b/samples/devbytes/animation/CurvedMotion/res/layout/activity_curved_motion.xml
@@ -0,0 +1,33 @@
+<!-- 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.
+-->
+<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:paddingBottom="@dimen/activity_vertical_margin"
+    android:paddingLeft="@dimen/activity_horizontal_margin"
+    android:paddingRight="@dimen/activity_horizontal_margin"
+    android:paddingTop="@dimen/activity_vertical_margin"
+    tools:context=".CurvedMotion" >
+
+    <Button
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignParentLeft="true"
+        android:layout_alignParentTop="true"
+        android:id="@+id/button"
+        android:text="Click Me!" />
+
+</RelativeLayout>
\ No newline at end of file
diff --git a/samples/devbytes/animation/CurvedMotion/res/values-v11/styles.xml b/samples/devbytes/animation/CurvedMotion/res/values-v11/styles.xml
new file mode 100644
index 0000000..556d2da
--- /dev/null
+++ b/samples/devbytes/animation/CurvedMotion/res/values-v11/styles.xml
@@ -0,0 +1,25 @@
+<!-- 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.
+-->
+<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/samples/devbytes/animation/CurvedMotion/res/values-v14/styles.xml b/samples/devbytes/animation/CurvedMotion/res/values-v14/styles.xml
new file mode 100644
index 0000000..6e9521a
--- /dev/null
+++ b/samples/devbytes/animation/CurvedMotion/res/values-v14/styles.xml
@@ -0,0 +1,26 @@
+<!-- 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.
+-->
+<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/samples/devbytes/animation/CurvedMotion/res/values/dimens.xml b/samples/devbytes/animation/CurvedMotion/res/values/dimens.xml
new file mode 100644
index 0000000..90db76b
--- /dev/null
+++ b/samples/devbytes/animation/CurvedMotion/res/values/dimens.xml
@@ -0,0 +1,21 @@
+<!-- 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.
+-->
+<resources>
+
+    <!-- Default screen margins, per the Android Design guidelines. -->
+    <dimen name="activity_horizontal_margin">16dp</dimen>
+    <dimen name="activity_vertical_margin">16dp</dimen>
+
+</resources>
\ No newline at end of file
diff --git a/samples/devbytes/animation/CurvedMotion/res/values/strings.xml b/samples/devbytes/animation/CurvedMotion/res/values/strings.xml
new file mode 100644
index 0000000..a070e15
--- /dev/null
+++ b/samples/devbytes/animation/CurvedMotion/res/values/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<resources>
+
+    <string name="app_name">CurvedMotion</string>
+    <string name="action_settings">Settings</string>
+    <string name="hello_world">Hello world!</string>
+
+</resources>
\ No newline at end of file
diff --git a/samples/devbytes/animation/CurvedMotion/res/values/styles.xml b/samples/devbytes/animation/CurvedMotion/res/values/styles.xml
new file mode 100644
index 0000000..27658b7
--- /dev/null
+++ b/samples/devbytes/animation/CurvedMotion/res/values/styles.xml
@@ -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.
+-->
+<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/samples/devbytes/animation/CurvedMotion/src/com/example/android/curvedmotion/AnimatorPath.java b/samples/devbytes/animation/CurvedMotion/src/com/example/android/curvedmotion/AnimatorPath.java
new file mode 100644
index 0000000..d030c6a
--- /dev/null
+++ b/samples/devbytes/animation/CurvedMotion/src/com/example/android/curvedmotion/AnimatorPath.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.example.android.curvedmotion;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+/**
+ * A simple Path object that holds information about the points along
+ * a path. The API allows you to specify a move location (which essentially
+ * jumps from the previous point in the path to the new one), a line location
+ * (which creates a line segment from the previous location) and a curve
+ * location (which creates a B�zier curve from the previous location).
+ */
+public class AnimatorPath {
+    
+    // The points in the path
+    ArrayList<PathPoint> mPoints = new ArrayList<PathPoint>();
+
+
+    /**
+     * Move from the current path point to the new one
+     * specified by x and y. This will create a discontinuity if this point is
+     * neither the first point in the path nor the same as the previous point
+     * in the path.
+     */
+    public void moveTo(float x, float y) {
+        mPoints.add(PathPoint.moveTo(x, y));
+    }
+
+    /**
+     * Create a straight line from the current path point to the new one
+     * specified by x and y.
+     */
+    public void lineTo(float x, float y) {
+        mPoints.add(PathPoint.lineTo(x, y));
+    }
+
+    /**
+     * Create a quadratic B�zier curve from the current path point to the new one
+     * specified by x and y. The curve uses the current path location as the first anchor
+     * point, the control points (c0X, c0Y) and (c1X, c1Y), and (x, y) as the end anchor.
+     */
+    public void curveTo(float c0X, float c0Y, float c1X, float c1Y, float x, float y) {
+        mPoints.add(PathPoint.curveTo(c0X, c0Y, c1X, c1Y, x, y));
+    }
+
+    /**
+     * Returns a Collection of PathPoint objects that describe all points in the path.
+     */
+    public Collection<PathPoint> getPoints() {
+        return mPoints;
+    }
+}
diff --git a/samples/devbytes/animation/CurvedMotion/src/com/example/android/curvedmotion/CurvedMotion.java b/samples/devbytes/animation/CurvedMotion/src/com/example/android/curvedmotion/CurvedMotion.java
new file mode 100644
index 0000000..357d72d
--- /dev/null
+++ b/samples/devbytes/animation/CurvedMotion/src/com/example/android/curvedmotion/CurvedMotion.java
@@ -0,0 +1,124 @@
+/*
+ * 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.example.android.curvedmotion;
+
+import android.animation.ObjectAnimator;
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.View;
+import android.view.ViewTreeObserver;
+import android.view.animation.DecelerateInterpolator;
+import android.widget.Button;
+import android.widget.RelativeLayout;
+import android.widget.RelativeLayout.LayoutParams;
+
+/**
+ * This app shows how to move a view in a curved path between two endpoints.
+ * The real work is done by PathEvaluator, which interpolates along a path
+ * using Bezier control and anchor points in the path.
+ *
+ * Watch the associated video for this demo on the DevBytes channel of developer.android.com
+ * or on the DevBytes playlist in the androiddevelopers channel on YouTube at
+ * https://www.youtube.com/playlist?list=PLWz5rJ2EKKc_XOgcRukSoKKjewFJZrKV0.
+ */
+public class CurvedMotion extends Activity {
+
+    private static final DecelerateInterpolator sDecelerateInterpolator =
+            new DecelerateInterpolator();
+    boolean mTopLeft = true;
+    Button mButton;
+    
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_curved_motion);
+        
+        mButton = (Button) findViewById(R.id.button);
+        mButton.setOnClickListener(new View.OnClickListener() {
+            
+            @Override
+            public void onClick(View v) {
+                // Capture current location of button
+                final int oldLeft = mButton.getLeft();
+                final int oldTop = mButton.getTop();
+                
+                // Change layout parameters of button to move it
+                moveButton();
+                
+                // Add OnPreDrawListener to catch button after layout but before drawing
+                mButton.getViewTreeObserver().addOnPreDrawListener(
+                        new ViewTreeObserver.OnPreDrawListener() {
+                            public boolean onPreDraw() {
+                                mButton.getViewTreeObserver().removeOnPreDrawListener(this);
+                                
+                                // Capture new location
+                                int left = mButton.getLeft();
+                                int top = mButton.getTop();
+                                int deltaX = left - oldLeft;
+                                int deltaY = top - oldTop;
+
+                                // Set up path to new location using a B�zier spline curve
+                                AnimatorPath path = new AnimatorPath();
+                                path.moveTo(-deltaX, -deltaY);
+                                path.curveTo(-(deltaX/2), -deltaY, 0, -deltaY/2, 0, 0);
+                                
+                                // Set up the animation
+                                final ObjectAnimator anim = ObjectAnimator.ofObject(
+                                        CurvedMotion.this, "buttonLoc", 
+                                        new PathEvaluator(), path.getPoints().toArray());
+                                anim.setInterpolator(sDecelerateInterpolator);
+                                anim.start();
+                                return true;
+                            }
+                        });
+            }
+        });
+    }
+    
+    /**
+     * Toggles button location on click between top-left and bottom-right
+     */
+    private void moveButton() {
+        LayoutParams params = (LayoutParams) mButton.getLayoutParams();
+        if (mTopLeft) {
+            params.removeRule(RelativeLayout.ALIGN_PARENT_LEFT);
+            params.removeRule(RelativeLayout.ALIGN_PARENT_TOP);
+            params.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
+            params.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
+        } else {
+            params.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
+            params.addRule(RelativeLayout.ALIGN_PARENT_TOP);
+            params.removeRule(RelativeLayout.ALIGN_PARENT_RIGHT);
+            params.removeRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
+        }
+        mButton.setLayoutParams(params);
+        mTopLeft = !mTopLeft;
+    }
+
+    /**
+     * We need this setter to translate between the information the animator
+     * produces (a new "PathPoint" describing the current animated location)
+     * and the information that the button requires (an xy location). The
+     * setter will be called by the ObjectAnimator given the 'buttonLoc'
+     * property string.
+     */
+    public void setButtonLoc(PathPoint newLoc) {
+        mButton.setTranslationX(newLoc.mX);
+        mButton.setTranslationY(newLoc.mY);
+    }
+
+}
diff --git a/samples/devbytes/animation/CurvedMotion/src/com/example/android/curvedmotion/PathEvaluator.java b/samples/devbytes/animation/CurvedMotion/src/com/example/android/curvedmotion/PathEvaluator.java
new file mode 100644
index 0000000..e68d4cd
--- /dev/null
+++ b/samples/devbytes/animation/CurvedMotion/src/com/example/android/curvedmotion/PathEvaluator.java
@@ -0,0 +1,49 @@
+/*
+ * 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.example.android.curvedmotion;
+
+import android.animation.TypeEvaluator;
+
+/**
+ * This evaluator interpolates between two PathPoint values given the value t, the
+ * proportion traveled between those points. The value of the interpolation depends
+ * on the operation specified by the endValue (the operation for the interval between
+ * PathPoints is always specified by the end point of that interval).
+ */
+public class PathEvaluator implements TypeEvaluator<PathPoint> {
+    @Override
+    public PathPoint evaluate(float t, PathPoint startValue, PathPoint endValue) {
+        float x, y;
+        if (endValue.mOperation == PathPoint.CURVE) {
+            float oneMinusT = 1 - t;
+            x = oneMinusT * oneMinusT * oneMinusT * startValue.mX +
+                    3 * oneMinusT * oneMinusT * t * endValue.mControl0X +
+                    3 * oneMinusT * t * t * endValue.mControl1X +
+                    t * t * t * endValue.mX;
+            y = oneMinusT * oneMinusT * oneMinusT * startValue.mY +
+                    3 * oneMinusT * oneMinusT * t * endValue.mControl0Y +
+                    3 * oneMinusT * t * t * endValue.mControl1Y +
+                    t * t * t * endValue.mY;
+        } else if (endValue.mOperation == PathPoint.LINE) {
+            x = startValue.mX + t * (endValue.mX - startValue.mX);
+            y = startValue.mY + t * (endValue.mY - startValue.mY);
+        } else {
+            x = endValue.mX;
+            y = endValue.mY;
+        }
+        return PathPoint.moveTo(x, y);
+    }
+}
diff --git a/samples/devbytes/animation/CurvedMotion/src/com/example/android/curvedmotion/PathPoint.java b/samples/devbytes/animation/CurvedMotion/src/com/example/android/curvedmotion/PathPoint.java
new file mode 100644
index 0000000..ba1a05e
--- /dev/null
+++ b/samples/devbytes/animation/CurvedMotion/src/com/example/android/curvedmotion/PathPoint.java
@@ -0,0 +1,101 @@
+/*
+ * 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.example.android.curvedmotion;
+
+/**
+ * A class that holds information about a location and how the path should get to that
+ * location from the previous path location (if any). Any PathPoint holds the information for
+ * its location as well as the instructions on how to traverse the preceding interval from the
+ * previous location.
+ */
+public class PathPoint {
+
+    /**
+     * The possible path operations that describe how to move from a preceding PathPoint to the
+     * location described by this PathPoint.
+     */
+    public static final int MOVE = 0;
+    public static final int LINE = 1;
+    public static final int CURVE = 2;
+
+    /**
+     * The location of this PathPoint
+     */
+    float mX, mY;
+    
+    /**
+     * The first control point, if any, for a PathPoint of type CURVE
+     */
+    float mControl0X, mControl0Y;
+
+    /**
+     * The second control point, if any, for a PathPoint of type CURVE
+     */
+    float mControl1X, mControl1Y;
+
+    /**
+     * The motion described by the path to get from the previous PathPoint in an AnimatorPath
+     * to the location of this PathPoint. This can be one of MOVE, LINE, or CURVE.
+     */
+    int mOperation;
+
+
+
+    /**
+     * Line/Move constructor
+     */
+    private PathPoint(int operation, float x, float y) {
+        mOperation = operation;
+        mX = x;
+        mY = y;
+    }
+
+    /**
+     * Curve constructor
+     */
+    private PathPoint(float c0X, float c0Y, float c1X, float c1Y, float x, float y) {
+        mControl0X = c0X;
+        mControl0Y = c0Y;
+        mControl1X = c1X;
+        mControl1Y = c1Y;
+        mX = x;
+        mY = y;
+        mOperation = CURVE;
+    }
+
+    /**
+     * Constructs and returns a PathPoint object that describes a line to the given xy location.
+     */
+    public static PathPoint lineTo(float x, float y) {
+        return new PathPoint(LINE, x, y);
+    }
+
+    /**
+     * Constructs and returns a PathPoint object that describes a curve to the given xy location
+     * with the control points at c0 and c1.
+     */
+    public static PathPoint curveTo(float c0X, float c0Y, float c1X, float c1Y, float x, float y) {
+        return new PathPoint(c0X,  c0Y, c1X, c1Y, x, y);
+    }
+    
+    /**
+     * Constructs and returns a PathPoint object that describes a discontinuous move to the given
+     * xy location.
+     */
+    public static PathPoint moveTo(float x, float y) {
+        return new PathPoint(MOVE, x, y);
+    }
+}
diff --git a/samples/devbytes/animation/ListViewItemAnimations/AndroidManifest.xml b/samples/devbytes/animation/ListViewItemAnimations/AndroidManifest.xml
new file mode 100644
index 0000000..173b188
--- /dev/null
+++ b/samples/devbytes/animation/ListViewItemAnimations/AndroidManifest.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.example.android.listviewitemanimations"
+    android:versionCode="1"
+    android:versionName="1.0" >
+
+    <uses-sdk
+        android:minSdkVersion="9"
+        android:targetSdkVersion="16" />
+
+    <application
+        android:allowBackup="true"
+        android:icon="@drawable/ic_launcher"
+        android:label="@string/app_name"
+        android:theme="@style/AppTheme" >
+        <activity
+            android:theme="@style/WithoutBackground"
+            android:name="com.example.android.listviewitemanimations.ListViewItemAnimations"
+            android:label="@string/app_name" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+
+</manifest>
\ No newline at end of file
diff --git a/samples/devbytes/animation/ListViewItemAnimations/res/drawable-hdpi/ic_launcher.png b/samples/devbytes/animation/ListViewItemAnimations/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..96a442e
--- /dev/null
+++ b/samples/devbytes/animation/ListViewItemAnimations/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/samples/devbytes/animation/ListViewItemAnimations/res/drawable-mdpi/ic_launcher.png b/samples/devbytes/animation/ListViewItemAnimations/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..359047d
--- /dev/null
+++ b/samples/devbytes/animation/ListViewItemAnimations/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/samples/devbytes/animation/ListViewItemAnimations/res/drawable-xhdpi/ic_launcher.png b/samples/devbytes/animation/ListViewItemAnimations/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..71c6d76
--- /dev/null
+++ b/samples/devbytes/animation/ListViewItemAnimations/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/devbytes/animation/ListViewItemAnimations/res/drawable-xhdpi/shadowed_background.9.png b/samples/devbytes/animation/ListViewItemAnimations/res/drawable-xhdpi/shadowed_background.9.png
new file mode 100644
index 0000000..6226b9e
--- /dev/null
+++ b/samples/devbytes/animation/ListViewItemAnimations/res/drawable-xhdpi/shadowed_background.9.png
Binary files differ
diff --git a/samples/devbytes/animation/ListViewItemAnimations/res/drawable-xhdpi/tv_background_with_divider.9.png b/samples/devbytes/animation/ListViewItemAnimations/res/drawable-xhdpi/tv_background_with_divider.9.png
new file mode 100644
index 0000000..e6e3cd5
--- /dev/null
+++ b/samples/devbytes/animation/ListViewItemAnimations/res/drawable-xhdpi/tv_background_with_divider.9.png
Binary files differ
diff --git a/samples/devbytes/animation/ListViewItemAnimations/res/layout-v9/activity_list_view_item_animations.xml b/samples/devbytes/animation/ListViewItemAnimations/res/layout-v9/activity_list_view_item_animations.xml
new file mode 100644
index 0000000..8290927
--- /dev/null
+++ b/samples/devbytes/animation/ListViewItemAnimations/res/layout-v9/activity_list_view_item_animations.xml
@@ -0,0 +1,37 @@
+<!-- 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.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:orientation="vertical"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    tools:context=".ListViewAnimations" >
+
+    <view
+        class="com.example.android.listviewitemanimations.BackgroundContainer"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:id="@+id/listViewBackground">
+
+        <ListView
+            android:id="@+id/listview"
+            android:divider="@null"
+            android:dividerHeight="0dp"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content" />
+
+    </view>
+
+</LinearLayout>
diff --git a/samples/devbytes/animation/ListViewItemAnimations/res/layout-v9/opaque_text_view.xml b/samples/devbytes/animation/ListViewItemAnimations/res/layout-v9/opaque_text_view.xml
new file mode 100644
index 0000000..aa03362
--- /dev/null
+++ b/samples/devbytes/animation/ListViewItemAnimations/res/layout-v9/opaque_text_view.xml
@@ -0,0 +1,25 @@
+<!-- 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.
+-->
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+          android:layout_width="match_parent"
+          android:layout_height="wrap_content"
+          android:background="@drawable/tv_background_with_divider"
+          android:textAppearance="?android:attr/textAppearanceListItemSmall"
+          android:paddingLeft="10dp"
+          android:paddingRight="10dp"
+          android:textSize="20dp"
+          android:gravity="center_vertical"
+          android:minHeight="48dp"
+        />
diff --git a/samples/devbytes/animation/ListViewItemAnimations/res/layout/activity_list_view_item_animations.xml b/samples/devbytes/animation/ListViewItemAnimations/res/layout/activity_list_view_item_animations.xml
new file mode 100644
index 0000000..8290927
--- /dev/null
+++ b/samples/devbytes/animation/ListViewItemAnimations/res/layout/activity_list_view_item_animations.xml
@@ -0,0 +1,37 @@
+<!-- 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.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:orientation="vertical"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    tools:context=".ListViewAnimations" >
+
+    <view
+        class="com.example.android.listviewitemanimations.BackgroundContainer"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:id="@+id/listViewBackground">
+
+        <ListView
+            android:id="@+id/listview"
+            android:divider="@null"
+            android:dividerHeight="0dp"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content" />
+
+    </view>
+
+</LinearLayout>
diff --git a/samples/devbytes/animation/ListViewItemAnimations/res/layout/opaque_text_view.xml b/samples/devbytes/animation/ListViewItemAnimations/res/layout/opaque_text_view.xml
new file mode 100644
index 0000000..c37f62d
--- /dev/null
+++ b/samples/devbytes/animation/ListViewItemAnimations/res/layout/opaque_text_view.xml
@@ -0,0 +1,24 @@
+<!-- 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.
+-->
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:background="@drawable/tv_background_with_divider"
+    android:textAppearance="?android:attr/textAppearanceListItemSmall"
+    android:gravity="center_vertical"
+    android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+    android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
+    android:minHeight="?android:attr/listPreferredItemHeightSmall"
+/>
diff --git a/samples/devbytes/animation/ListViewItemAnimations/res/values-v11/styles.xml b/samples/devbytes/animation/ListViewItemAnimations/res/values-v11/styles.xml
new file mode 100644
index 0000000..556d2da
--- /dev/null
+++ b/samples/devbytes/animation/ListViewItemAnimations/res/values-v11/styles.xml
@@ -0,0 +1,25 @@
+<!-- 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.
+-->
+<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/samples/devbytes/animation/ListViewItemAnimations/res/values-v14/styles.xml b/samples/devbytes/animation/ListViewItemAnimations/res/values-v14/styles.xml
new file mode 100644
index 0000000..6e9521a
--- /dev/null
+++ b/samples/devbytes/animation/ListViewItemAnimations/res/values-v14/styles.xml
@@ -0,0 +1,26 @@
+<!-- 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.
+-->
+<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/samples/devbytes/animation/ListViewItemAnimations/res/values/dimens.xml b/samples/devbytes/animation/ListViewItemAnimations/res/values/dimens.xml
new file mode 100644
index 0000000..90db76b
--- /dev/null
+++ b/samples/devbytes/animation/ListViewItemAnimations/res/values/dimens.xml
@@ -0,0 +1,21 @@
+<!-- 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.
+-->
+<resources>
+
+    <!-- Default screen margins, per the Android Design guidelines. -->
+    <dimen name="activity_horizontal_margin">16dp</dimen>
+    <dimen name="activity_vertical_margin">16dp</dimen>
+
+</resources>
\ No newline at end of file
diff --git a/samples/devbytes/animation/ListViewItemAnimations/res/values/strings.xml b/samples/devbytes/animation/ListViewItemAnimations/res/values/strings.xml
new file mode 100644
index 0000000..2cc5f71
--- /dev/null
+++ b/samples/devbytes/animation/ListViewItemAnimations/res/values/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<resources>
+
+    <string name="app_name">ListViewItemAnimations</string>
+    <string name="action_settings">Settings</string>
+    <string name="hello_world">Hello world!</string>
+
+</resources>
\ No newline at end of file
diff --git a/samples/devbytes/animation/ListViewItemAnimations/res/values/styles.xml b/samples/devbytes/animation/ListViewItemAnimations/res/values/styles.xml
new file mode 100644
index 0000000..ee3c56c
--- /dev/null
+++ b/samples/devbytes/animation/ListViewItemAnimations/res/values/styles.xml
@@ -0,0 +1,38 @@
+<!-- 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.
+-->
+<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>
+
+    <style name="WithoutBackground" parent="AppTheme">
+        <item name="android:windowBackground">@null</item>
+    </style>
+    
+</resources>
\ No newline at end of file
diff --git a/samples/devbytes/animation/ListViewItemAnimations/src/com/example/android/listviewitemanimations/BackgroundContainer.java b/samples/devbytes/animation/ListViewItemAnimations/src/com/example/android/listviewitemanimations/BackgroundContainer.java
new file mode 100644
index 0000000..40ac39a
--- /dev/null
+++ b/samples/devbytes/animation/ListViewItemAnimations/src/com/example/android/listviewitemanimations/BackgroundContainer.java
@@ -0,0 +1,77 @@
+/*
+ * 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.example.android.listviewitemanimations;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.widget.FrameLayout;
+
+public class BackgroundContainer extends FrameLayout {
+
+    boolean mShowing = false;
+    Drawable mShadowedBackground;
+    int mOpenAreaTop, mOpenAreaBottom, mOpenAreaHeight;
+    boolean mUpdateBounds = false;
+    
+    public BackgroundContainer(Context context) {
+        super(context);
+        init();
+    }
+
+    public BackgroundContainer(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        init();
+    }
+
+    public BackgroundContainer(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+        init();
+    }
+
+    private void init() {
+        mShadowedBackground = getContext().getResources().getDrawable(R.drawable.shadowed_background);
+    }
+
+    public void showBackground(int top, int bottom) {
+        setWillNotDraw(false);
+        mOpenAreaTop = top;
+        mOpenAreaHeight = bottom;
+        mShowing = true;
+        mUpdateBounds = true;
+    }
+    
+    public void hideBackground() {
+        setWillNotDraw(true);
+        mShowing = false;
+    }
+    
+    @Override
+    protected void onDraw(Canvas canvas) {
+        if (mShowing) {
+            if (mUpdateBounds) {
+                mShadowedBackground.setBounds(0, 0, getWidth(), mOpenAreaHeight);
+            }
+            canvas.save();
+            canvas.translate(0, mOpenAreaTop);
+            mShadowedBackground.draw(canvas);
+            canvas.restore();
+        }
+    }
+
+}
diff --git a/samples/devbytes/animation/ListViewItemAnimations/src/com/example/android/listviewitemanimations/Cheeses.java b/samples/devbytes/animation/ListViewItemAnimations/src/com/example/android/listviewitemanimations/Cheeses.java
new file mode 100644
index 0000000..5241022
--- /dev/null
+++ b/samples/devbytes/animation/ListViewItemAnimations/src/com/example/android/listviewitemanimations/Cheeses.java
@@ -0,0 +1,154 @@
+/*
+ * 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.example.android.listviewitemanimations;
+
+public class Cheeses {
+
+    public static final String[] sCheeseStrings = {
+            "Abbaye de Belloc", "Abbaye du Mont des Cats", "Abertam", "Abondance", "Ackawi",
+            "Acorn", "Adelost", "Affidelice au Chablis", "Afuega'l Pitu", "Airag", "Airedale",
+            "Aisy Cendre", "Allgauer Emmentaler", "Alverca", "Ambert", "American Cheese",
+            "Ami du Chambertin", "Anejo Enchilado", "Anneau du Vic-Bilh", "Anthoriro", "Appenzell",
+            "Aragon", "Ardi Gasna", "Ardrahan", "Armenian String", "Aromes au Gene de Marc",
+            "Asadero", "Asiago", "Aubisque Pyrenees", "Autun", "Avaxtskyr", "Baby Swiss",
+            "Babybel", "Baguette Laonnaise", "Bakers", "Baladi", "Balaton", "Bandal", "Banon",
+            "Barry's Bay Cheddar", "Basing", "Basket Cheese", "Bath Cheese", "Bavarian Bergkase",
+            "Baylough", "Beaufort", "Beauvoorde", "Beenleigh Blue", "Beer Cheese", "Bel Paese",
+            "Bergader", "Bergere Bleue", "Berkswell", "Beyaz Peynir", "Bierkase", "Bishop Kennedy",
+            "Blarney", "Bleu d'Auvergne", "Bleu de Gex", "Bleu de Laqueuille",
+            "Bleu de Septmoncel", "Bleu Des Causses", "Blue", "Blue Castello", "Blue Rathgore",
+            "Blue Vein (Australian)", "Blue Vein Cheeses", "Bocconcini", "Bocconcini (Australian)",
+            "Boeren Leidenkaas", "Bonchester", "Bosworth", "Bougon", "Boule Du Roves",
+            "Boulette d'Avesnes", "Boursault", "Boursin", "Bouyssou", "Bra", "Braudostur",
+            "Breakfast Cheese", "Brebis du Lavort", "Brebis du Lochois", "Brebis du Puyfaucon",
+            "Bresse Bleu", "Brick", "Brie", "Brie de Meaux", "Brie de Melun", "Brillat-Savarin",
+            "Brin", "Brin d' Amour", "Brin d'Amour", "Brinza (Burduf Brinza)",
+            "Briquette de Brebis", "Briquette du Forez", "Broccio", "Broccio Demi-Affine",
+            "Brousse du Rove", "Bruder Basil", "Brusselae Kaas (Fromage de Bruxelles)", "Bryndza",
+            "Buchette d'Anjou", "Buffalo", "Burgos", "Butte", "Butterkase", "Button (Innes)",
+            "Buxton Blue", "Cabecou", "Caboc", "Cabrales", "Cachaille", "Caciocavallo", "Caciotta",
+            "Caerphilly", "Cairnsmore", "Calenzana", "Cambazola", "Camembert de Normandie",
+            "Canadian Cheddar", "Canestrato", "Cantal", "Caprice des Dieux", "Capricorn Goat",
+            "Capriole Banon", "Carre de l'Est", "Casciotta di Urbino", "Cashel Blue", "Castellano",
+            "Castelleno", "Castelmagno", "Castelo Branco", "Castigliano", "Cathelain",
+            "Celtic Promise", "Cendre d'Olivet", "Cerney", "Chabichou", "Chabichou du Poitou",
+            "Chabis de Gatine", "Chaource", "Charolais", "Chaumes", "Cheddar",
+            "Cheddar Clothbound", "Cheshire", "Chevres", "Chevrotin des Aravis", "Chontaleno",
+            "Civray", "Coeur de Camembert au Calvados", "Coeur de Chevre", "Colby", "Cold Pack",
+            "Comte", "Coolea", "Cooleney", "Coquetdale", "Corleggy", "Cornish Pepper",
+            "Cotherstone", "Cotija", "Cottage Cheese", "Cottage Cheese (Australian)",
+            "Cougar Gold", "Coulommiers", "Coverdale", "Crayeux de Roncq", "Cream Cheese",
+            "Cream Havarti", "Crema Agria", "Crema Mexicana", "Creme Fraiche", "Crescenza",
+            "Croghan", "Crottin de Chavignol", "Crottin du Chavignol", "Crowdie", "Crowley",
+            "Cuajada", "Curd", "Cure Nantais", "Curworthy", "Cwmtawe Pecorino",
+            "Cypress Grove Chevre", "Danablu (Danish Blue)", "Danbo", "Danish Fontina",
+            "Daralagjazsky", "Dauphin", "Delice des Fiouves", "Denhany Dorset Drum", "Derby",
+            "Dessertnyj Belyj", "Devon Blue", "Devon Garland", "Dolcelatte", "Doolin",
+            "Doppelrhamstufel", "Dorset Blue Vinney", "Double Gloucester", "Double Worcester",
+            "Dreux a la Feuille", "Dry Jack", "Duddleswell", "Dunbarra", "Dunlop", "Dunsyre Blue",
+            "Duroblando", "Durrus", "Dutch Mimolette (Commissiekaas)", "Edam", "Edelpilz",
+            "Emental Grand Cru", "Emlett", "Emmental", "Epoisses de Bourgogne", "Esbareich",
+            "Esrom", "Etorki", "Evansdale Farmhouse Brie", "Evora De L'Alentejo", "Exmoor Blue",
+            "Explorateur", "Feta", "Feta (Australian)", "Figue", "Filetta", "Fin-de-Siecle",
+            "Finlandia Swiss", "Finn", "Fiore Sardo", "Fleur du Maquis", "Flor de Guia",
+            "Flower Marie", "Folded", "Folded cheese with mint", "Fondant de Brebis",
+            "Fontainebleau", "Fontal", "Fontina Val d'Aosta", "Formaggio di capra", "Fougerus",
+            "Four Herb Gouda", "Fourme d' Ambert", "Fourme de Haute Loire", "Fourme de Montbrison",
+            "Fresh Jack", "Fresh Mozzarella", "Fresh Ricotta", "Fresh Truffles", "Fribourgeois",
+            "Friesekaas", "Friesian", "Friesla", "Frinault", "Fromage a Raclette", "Fromage Corse",
+            "Fromage de Montagne de Savoie", "Fromage Frais", "Fruit Cream Cheese",
+            "Frying Cheese", "Fynbo", "Gabriel", "Galette du Paludier", "Galette Lyonnaise",
+            "Galloway Goat's Milk Gems", "Gammelost", "Gaperon a l'Ail", "Garrotxa", "Gastanberra",
+            "Geitost", "Gippsland Blue", "Gjetost", "Gloucester", "Golden Cross", "Gorgonzola",
+            "Gornyaltajski", "Gospel Green", "Gouda", "Goutu", "Gowrie", "Grabetto", "Graddost",
+            "Grafton Village Cheddar", "Grana", "Grana Padano", "Grand Vatel",
+            "Grataron d' Areches", "Gratte-Paille", "Graviera", "Greuilh", "Greve",
+            "Gris de Lille", "Gruyere", "Gubbeen", "Guerbigny", "Halloumi",
+            "Halloumy (Australian)", "Haloumi-Style Cheese", "Harbourne Blue", "Havarti",
+            "Heidi Gruyere", "Hereford Hop", "Herrgardsost", "Herriot Farmhouse", "Herve",
+            "Hipi Iti", "Hubbardston Blue Cow", "Hushallsost", "Iberico", "Idaho Goatster",
+            "Idiazabal", "Il Boschetto al Tartufo", "Ile d'Yeu", "Isle of Mull", "Jarlsberg",
+            "Jermi Tortes", "Jibneh Arabieh", "Jindi Brie", "Jubilee Blue", "Juustoleipa",
+            "Kadchgall", "Kaseri", "Kashta", "Kefalotyri", "Kenafa", "Kernhem", "Kervella Affine",
+            "Kikorangi", "King Island Cape Wickham Brie", "King River Gold", "Klosterkaese",
+            "Knockalara", "Kugelkase", "L'Aveyronnais", "L'Ecir de l'Aubrac", "La Taupiniere",
+            "La Vache Qui Rit", "Laguiole", "Lairobell", "Lajta", "Lanark Blue", "Lancashire",
+            "Langres", "Lappi", "Laruns", "Lavistown", "Le Brin", "Le Fium Orbo", "Le Lacandou",
+            "Le Roule", "Leafield", "Lebbene", "Leerdammer", "Leicester", "Leyden", "Limburger",
+            "Lincolnshire Poacher", "Lingot Saint Bousquet d'Orb", "Liptauer", "Little Rydings",
+            "Livarot", "Llanboidy", "Llanglofan Farmhouse", "Loch Arthur Farmhouse",
+            "Loddiswell Avondale", "Longhorn", "Lou Palou", "Lou Pevre", "Lyonnais", "Maasdam",
+            "Macconais", "Mahoe Aged Gouda", "Mahon", "Malvern", "Mamirolle", "Manchego",
+            "Manouri", "Manur", "Marble Cheddar", "Marbled Cheeses", "Maredsous", "Margotin",
+            "Maribo", "Maroilles", "Mascares", "Mascarpone", "Mascarpone (Australian)",
+            "Mascarpone Torta", "Matocq", "Maytag Blue", "Meira", "Menallack Farmhouse",
+            "Menonita", "Meredith Blue", "Mesost", "Metton (Cancoillotte)", "Meyer Vintage Gouda",
+            "Mihalic Peynir", "Milleens", "Mimolette", "Mine-Gabhar", "Mini Baby Bells", "Mixte",
+            "Molbo", "Monastery Cheeses", "Mondseer", "Mont D'or Lyonnais", "Montasio",
+            "Monterey Jack", "Monterey Jack Dry", "Morbier", "Morbier Cru de Montagne",
+            "Mothais a la Feuille", "Mozzarella", "Mozzarella (Australian)",
+            "Mozzarella di Bufala", "Mozzarella Fresh, in water", "Mozzarella Rolls", "Munster",
+            "Murol", "Mycella", "Myzithra", "Naboulsi", "Nantais", "Neufchatel",
+            "Neufchatel (Australian)", "Niolo", "Nokkelost", "Northumberland", "Oaxaca",
+            "Olde York", "Olivet au Foin", "Olivet Bleu", "Olivet Cendre",
+            "Orkney Extra Mature Cheddar", "Orla", "Oschtjepka", "Ossau Fermier", "Ossau-Iraty",
+            "Oszczypek", "Oxford Blue", "P'tit Berrichon", "Palet de Babligny", "Paneer", "Panela",
+            "Pannerone", "Pant ys Gawn", "Parmesan (Parmigiano)", "Parmigiano Reggiano",
+            "Pas de l'Escalette", "Passendale", "Pasteurized Processed", "Pate de Fromage",
+            "Patefine Fort", "Pave d'Affinois", "Pave d'Auge", "Pave de Chirac", "Pave du Berry",
+            "Pecorino", "Pecorino in Walnut Leaves", "Pecorino Romano", "Peekskill Pyramid",
+            "Pelardon des Cevennes", "Pelardon des Corbieres", "Penamellera", "Penbryn",
+            "Pencarreg", "Perail de Brebis", "Petit Morin", "Petit Pardou", "Petit-Suisse",
+            "Picodon de Chevre", "Picos de Europa", "Piora", "Pithtviers au Foin",
+            "Plateau de Herve", "Plymouth Cheese", "Podhalanski", "Poivre d'Ane", "Polkolbin",
+            "Pont l'Eveque", "Port Nicholson", "Port-Salut", "Postel", "Pouligny-Saint-Pierre",
+            "Pourly", "Prastost", "Pressato", "Prince-Jean", "Processed Cheddar", "Provolone",
+            "Provolone (Australian)", "Pyengana Cheddar", "Pyramide", "Quark",
+            "Quark (Australian)", "Quartirolo Lombardo", "Quatre-Vents", "Quercy Petit",
+            "Queso Blanco", "Queso Blanco con Frutas --Pina y Mango", "Queso de Murcia",
+            "Queso del Montsec", "Queso del Tietar", "Queso Fresco", "Queso Fresco (Adobera)",
+            "Queso Iberico", "Queso Jalapeno", "Queso Majorero", "Queso Media Luna",
+            "Queso Para Frier", "Queso Quesadilla", "Rabacal", "Raclette", "Ragusano", "Raschera",
+            "Reblochon", "Red Leicester", "Regal de la Dombes", "Reggianito", "Remedou",
+            "Requeson", "Richelieu", "Ricotta", "Ricotta (Australian)", "Ricotta Salata", "Ridder",
+            "Rigotte", "Rocamadour", "Rollot", "Romano", "Romans Part Dieu", "Roncal", "Roquefort",
+            "Roule", "Rouleau De Beaulieu", "Royalp Tilsit", "Rubens", "Rustinu", "Saaland Pfarr",
+            "Saanenkaese", "Saga", "Sage Derby", "Sainte Maure", "Saint-Marcellin",
+            "Saint-Nectaire", "Saint-Paulin", "Salers", "Samso", "San Simon", "Sancerre",
+            "Sap Sago", "Sardo", "Sardo Egyptian", "Sbrinz", "Scamorza", "Schabzieger", "Schloss",
+            "Selles sur Cher", "Selva", "Serat", "Seriously Strong Cheddar", "Serra da Estrela",
+            "Sharpam", "Shelburne Cheddar", "Shropshire Blue", "Siraz", "Sirene", "Smoked Gouda",
+            "Somerset Brie", "Sonoma Jack", "Sottocenare al Tartufo", "Soumaintrain",
+            "Sourire Lozerien", "Spenwood", "Sraffordshire Organic", "St. Agur Blue Cheese",
+            "Stilton", "Stinking Bishop", "String", "Sussex Slipcote", "Sveciaost", "Swaledale",
+            "Sweet Style Swiss", "Swiss", "Syrian (Armenian String)", "Tala", "Taleggio", "Tamie",
+            "Tasmania Highland Chevre Log", "Taupiniere", "Teifi", "Telemea", "Testouri",
+            "Tete de Moine", "Tetilla", "Texas Goat Cheese", "Tibet", "Tillamook Cheddar",
+            "Tilsit", "Timboon Brie", "Toma", "Tomme Brulee", "Tomme d'Abondance",
+            "Tomme de Chevre", "Tomme de Romans", "Tomme de Savoie", "Tomme des Chouans", "Tommes",
+            "Torta del Casar", "Toscanello", "Touree de L'Aubier", "Tourmalet",
+            "Trappe (Veritable)", "Trois Cornes De Vendee", "Tronchon", "Trou du Cru", "Truffe",
+            "Tupi", "Turunmaa", "Tymsboro", "Tyn Grug", "Tyning", "Ubriaco", "Ulloa",
+            "Vacherin-Fribourgeois", "Valencay", "Vasterbottenost", "Venaco", "Vendomois",
+            "Vieux Corse", "Vignotte", "Vulscombe", "Waimata Farmhouse Blue",
+            "Washed Rind Cheese (Australian)", "Waterloo", "Weichkaese", "Wellington",
+            "Wensleydale", "White Stilton", "Whitestone Farmhouse", "Wigmore", "Woodside Cabecou",
+            "Xanadu", "Xynotyro", "Yarg Cornish", "Yarra Valley Pyramid", "Yorkshire Blue",
+            "Zamorano", "Zanetti Grana Padano", "Zanetti Parmigiano Reggiano"
+    };
+
+}
diff --git a/samples/devbytes/animation/ListViewItemAnimations/src/com/example/android/listviewitemanimations/ListViewItemAnimations.java b/samples/devbytes/animation/ListViewItemAnimations/src/com/example/android/listviewitemanimations/ListViewItemAnimations.java
new file mode 100644
index 0000000..68a7651
--- /dev/null
+++ b/samples/devbytes/animation/ListViewItemAnimations/src/com/example/android/listviewitemanimations/ListViewItemAnimations.java
@@ -0,0 +1,402 @@
+/*
+ * 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.example.android.listviewitemanimations;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
+import android.annotation.SuppressLint;
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewConfiguration;
+import android.view.ViewTreeObserver;
+import android.view.animation.AlphaAnimation;
+import android.view.animation.Animation;
+import android.view.animation.Animation.AnimationListener;
+import android.view.animation.AnimationSet;
+import android.view.animation.TranslateAnimation;
+import android.widget.ListView;
+
+/**
+ * This example shows how to use a swipe effect to remove items from a ListView,
+ * and how to use animations to complete the swipe as well as to animate the other
+ * items in the list into their final places. This code works on runtimes back to Gingerbread
+ * (Android 2.3), by using the android.view.animation classes on earlier releases.
+ *
+ * Watch the associated video for this demo on the DevBytes channel of developer.android.com
+ * or on the DevBytes playlist in the androiddevelopers channel on YouTube at
+ * https://www.youtube.com/playlist?list=PLWz5rJ2EKKc_XOgcRukSoKKjewFJZrKV0.
+ */
+public class ListViewItemAnimations extends Activity {
+
+    final ArrayList<View> mCheckedViews = new ArrayList<View>();
+    StableArrayAdapter mAdapter;
+    ListView mListView;
+    BackgroundContainer mBackgroundContainer;
+    boolean mSwiping = false;
+    boolean mItemPressed = false;
+    HashMap<Long, Integer> mItemIdTopMap = new HashMap<Long, Integer>();
+    boolean mAnimating = false;
+    float mCurrentX = 0;
+    float mCurrentAlpha = 1;
+
+    private static final int SWIPE_DURATION = 250;
+    private static final int MOVE_DURATION = 150;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_list_view_item_animations);
+        
+        mBackgroundContainer = (BackgroundContainer) findViewById(R.id.listViewBackground);
+        mListView = (ListView) findViewById(R.id.listview);
+        final ArrayList<String> cheeseList = new ArrayList<String>();
+        for (int i = 0; i < Cheeses.sCheeseStrings.length; ++i) {
+            cheeseList.add(Cheeses.sCheeseStrings[i]);
+        }
+        mAdapter = new StableArrayAdapter(this,R.layout.opaque_text_view, cheeseList,
+                mTouchListener);
+        mListView.setAdapter(mAdapter);
+    }
+    
+    /**
+     * Returns true if the current runtime is Honeycomb or later
+     */
+    private boolean isRuntimePostGingerbread() {
+        return android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB;
+    }
+
+    private View.OnTouchListener mTouchListener = new View.OnTouchListener() {
+        
+        float mDownX;
+        private int mSwipeSlop = -1;
+        
+        @SuppressLint("NewApi")
+        @Override
+        public boolean onTouch(final View v, MotionEvent event) {
+            if (mSwipeSlop < 0) {
+                mSwipeSlop = ViewConfiguration.get(ListViewItemAnimations.this).
+                        getScaledTouchSlop();
+            }
+            switch (event.getAction()) {
+            case MotionEvent.ACTION_DOWN:
+                if (mAnimating) {
+                    // Multi-item swipes not handled
+                    return true;
+                }
+                mItemPressed = true;
+                mDownX = event.getX();
+                break;
+            case MotionEvent.ACTION_CANCEL:
+                setSwipePosition(v, 0);
+                mItemPressed = false;
+                break;
+            case MotionEvent.ACTION_MOVE:
+                {
+                    if (mAnimating) {
+                        return true;
+                    }
+                    float x = event.getX();
+                    if (isRuntimePostGingerbread()) {
+                        x += v.getTranslationX();
+                    }
+                    float deltaX = x - mDownX;
+                    float deltaXAbs = Math.abs(deltaX);
+                    if (!mSwiping) {
+                        if (deltaXAbs > mSwipeSlop) {
+                            mSwiping = true;
+                            mListView.requestDisallowInterceptTouchEvent(true);
+                            mBackgroundContainer.showBackground(v.getTop(), v.getHeight());
+                        }
+                    }
+                    if (mSwiping) {
+                        setSwipePosition(v, deltaX);
+                    }
+                }
+                break;
+            case MotionEvent.ACTION_UP:
+                {
+                    if (mAnimating) {
+                        return true;
+                    }
+                    // User let go - figure out whether to animate the view out, or back into place
+                    if (mSwiping) {
+                        float x = event.getX();
+                        if (isRuntimePostGingerbread()) {
+                            x += v.getTranslationX();
+                        }
+                        float deltaX = x - mDownX;
+                        float deltaXAbs = Math.abs(deltaX);
+                        float fractionCovered;
+                        float endX;
+                        final boolean remove;
+                        if (deltaXAbs > v.getWidth() / 4) {
+                            // Greater than a quarter of the width - animate it out
+                            fractionCovered = deltaXAbs / v.getWidth();
+                            endX = deltaX < 0 ? -v.getWidth() : v.getWidth();
+                            remove = true;
+                        } else {
+                            // Not far enough - animate it back
+                            fractionCovered = 1 - (deltaXAbs / v.getWidth());
+                            endX = 0;
+                            remove = false;
+                        }
+                        // Animate position and alpha
+                        long duration = (int) ((1 - fractionCovered) * SWIPE_DURATION);
+                        animateSwipe(v, endX, duration, remove);
+                    } else {
+                        mItemPressed = false;
+                    }
+                }
+                break;
+            default: 
+                return false;
+            }
+            return true;
+        }
+    };
+
+    /**
+     * Animates a swipe of the item either back into place or out of the listview container.
+     * NOTE: This is a simplified version of swipe behavior, for the purposes of this demo
+     * about animation. A real version should use velocity (via the VelocityTracker class)
+     * to send the item off or back at an appropriate speed.
+     */
+    @SuppressLint("NewApi")
+    private void animateSwipe(final View view, float endX, long duration, final boolean remove) {
+        mAnimating = true;
+        mListView.setEnabled(false);
+        if (isRuntimePostGingerbread()) {
+            view.animate().setDuration(duration).
+                    alpha(remove ? 0 : 1).translationX(endX).
+                    setListener(new AnimatorListenerAdapter() {
+                        @Override
+                        public void onAnimationEnd(Animator animation) {
+                            // Restore animated values
+                            view.setAlpha(1);
+                            view.setTranslationX(0);
+                            if (remove) {
+                                animateOtherViews(mListView, view);
+                            } else {
+                                mBackgroundContainer.hideBackground();
+                                mSwiping = false;
+                                mAnimating = false;
+                                mListView.setEnabled(true);
+                            }
+                            mItemPressed = false;
+                        }
+                    });
+        } else {
+            TranslateAnimation swipeAnim = new TranslateAnimation(mCurrentX, endX, 0, 0);
+            AlphaAnimation alphaAnim = new AlphaAnimation(mCurrentAlpha, remove ? 0 : 1);
+            AnimationSet set = new AnimationSet(true);
+            set.addAnimation(swipeAnim);
+            set.addAnimation(alphaAnim);
+            set.setDuration(duration);
+            view.startAnimation(set);
+            setAnimationEndAction(set, new Runnable() {
+                @Override
+                public void run() {
+                    if (remove) {
+                        animateOtherViews(mListView, view);
+                    } else {
+                        mBackgroundContainer.hideBackground();
+                        mSwiping = false;
+                        mAnimating = false;
+                        mListView.setEnabled(true);
+                    }
+                    mItemPressed = false;
+                }
+            });
+        }
+            
+    }
+        
+    /**
+     * Sets the horizontal position and translucency of the view being swiped.
+     */
+    @SuppressLint("NewApi")
+    private void setSwipePosition(View view, float deltaX) {
+        float fraction = Math.abs(deltaX) / view.getWidth();
+        if (isRuntimePostGingerbread()) {
+            view.setTranslationX(deltaX);
+            view.setAlpha(1 - fraction);
+        } else {
+            // Hello, Gingerbread!
+            TranslateAnimation swipeAnim = new TranslateAnimation(deltaX, deltaX, 0, 0);
+            mCurrentX = deltaX;
+            mCurrentAlpha = (1 - fraction);
+            AlphaAnimation alphaAnim = new AlphaAnimation(mCurrentAlpha, mCurrentAlpha);
+            AnimationSet set = new AnimationSet(true);
+            set.addAnimation(swipeAnim);
+            set.addAnimation(alphaAnim);
+            set.setFillAfter(true);
+            set.setFillEnabled(true);
+            view.startAnimation(set);
+        }
+    }
+
+    /**
+     * This method animates all other views in the ListView container (not including ignoreView)
+     * into their final positions. It is called after ignoreView has been removed from the
+     * adapter, but before layout has been run. The approach here is to figure out where
+     * everything is now, then allow layout to run, then figure out where everything is after
+     * layout, and then to run animations between all of those start/end positions.
+     */
+    private void animateOtherViews(final ListView listview, View viewToRemove) {
+        int firstVisiblePosition = listview.getFirstVisiblePosition();
+        for (int i = 0; i < listview.getChildCount(); ++i) {
+            View child = listview.getChildAt(i);
+            int position = firstVisiblePosition + i;
+            long itemId = mAdapter.getItemId(position);
+            if (child != viewToRemove) {
+                mItemIdTopMap.put(itemId, child.getTop());
+            }
+        }
+        // Delete the item from the adapter
+        int position = mListView.getPositionForView(viewToRemove);
+        mAdapter.remove(mAdapter.getItem(position));
+        
+        // After layout runs, capture position of all itemIDs, compare to pre-layout
+        // positions, and animate changes
+        final ViewTreeObserver observer = listview.getViewTreeObserver();
+        observer.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
+            public boolean onPreDraw() {
+                observer.removeOnPreDrawListener(this);
+                boolean firstAnimation = true;
+                int firstVisiblePosition = listview.getFirstVisiblePosition();
+                for (int i = 0; i < listview.getChildCount(); ++i) {
+                    final View child = listview.getChildAt(i);
+                    int position = firstVisiblePosition + i;
+                    long itemId = mAdapter.getItemId(position);
+                    Integer startTop = mItemIdTopMap.get(itemId);
+                    int top = child.getTop();
+                    if (startTop == null) {
+                        // Animate new views along with the others. The catch is that they did not
+                        // exist in the start state, so we must calculate their starting position
+                        // based on whether they're coming in from the bottom (i > 0) or top.
+                        int childHeight = child.getHeight() + listview.getDividerHeight();
+                        startTop = top + (i > 0 ? childHeight : -childHeight);
+                    }
+                    int delta = startTop - top;
+                    if (delta != 0) {
+                        Runnable endAction = firstAnimation ?
+                            new Runnable() {
+                                public void run() {
+                                    mBackgroundContainer.hideBackground();
+                                    mSwiping = false;
+                                    mAnimating = false;
+                                    mListView.setEnabled(true);
+                                }
+                            } :
+                            null;
+                        firstAnimation = false;
+                        moveView(child, 0, 0, delta, 0, endAction);
+                    }
+                }
+                mItemIdTopMap.clear();
+                return true;
+            }
+        });
+    }
+    
+    /**
+     * Animate a view between start and end X/Y locations, using either old (pre-3.0) or
+     * new animation APIs.
+     */
+    @SuppressLint("NewApi")
+    private void moveView(View view, float startX, float endX, float startY, float endY,
+            Runnable endAction) {
+        final Runnable finalEndAction = endAction;
+        if (isRuntimePostGingerbread()) {
+            view.animate().setDuration(MOVE_DURATION);
+            if (startX != endX) {
+                ObjectAnimator anim = ObjectAnimator.ofFloat(view, View.TRANSLATION_X, startX, endX);
+                anim.setDuration(MOVE_DURATION);
+                anim.start();
+                setAnimatorEndAction(anim, endAction);
+                endAction = null;
+            }
+            if (startY != endY) {
+                ObjectAnimator anim = ObjectAnimator.ofFloat(view, View.TRANSLATION_Y, startY, endY);
+                anim.setDuration(MOVE_DURATION);
+                anim.start();
+                setAnimatorEndAction(anim, endAction);
+            }
+        } else {
+            TranslateAnimation translator = new TranslateAnimation(startX, endX, startY, endY);
+            translator.setDuration(MOVE_DURATION);
+            view.startAnimation(translator);
+            if (endAction != null) {
+                view.getAnimation().setAnimationListener(new AnimationListenerAdapter() {
+                    @Override
+                    public void onAnimationEnd(Animation animation) {
+                        finalEndAction.run();
+                    }
+                });
+            }
+        }
+    }
+    
+    @SuppressLint("NewApi")
+    private void setAnimatorEndAction(Animator animator, final Runnable endAction) {
+        if (endAction != null) {
+            animator.addListener(new AnimatorListenerAdapter() {
+                @Override
+                public void onAnimationEnd(Animator animation) {
+                    endAction.run();
+                }
+            });
+        }
+    }
+
+    private void setAnimationEndAction(Animation animation, final Runnable endAction) {
+        if (endAction != null) {
+            animation.setAnimationListener(new AnimationListenerAdapter() {
+                @Override
+                public void onAnimationEnd(Animation animation) {
+                    endAction.run();
+                }
+            });
+        }
+    }
+
+    /**
+     * Utility, to avoid having to implement every method in AnimationListener in
+     * every implementation class
+     */
+    static class AnimationListenerAdapter implements AnimationListener {
+
+        @Override
+        public void onAnimationEnd(Animation animation) {
+        }
+
+        @Override
+        public void onAnimationRepeat(Animation animation) {
+        }
+
+        @Override
+        public void onAnimationStart(Animation animation) {
+        }
+    }
+
+}
diff --git a/samples/devbytes/animation/ListViewItemAnimations/src/com/example/android/listviewitemanimations/StableArrayAdapter.java b/samples/devbytes/animation/ListViewItemAnimations/src/com/example/android/listviewitemanimations/StableArrayAdapter.java
new file mode 100644
index 0000000..4bddc5e
--- /dev/null
+++ b/samples/devbytes/animation/ListViewItemAnimations/src/com/example/android/listviewitemanimations/StableArrayAdapter.java
@@ -0,0 +1,62 @@
+/*
+ * 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.example.android.listviewitemanimations;
+
+import java.util.HashMap;
+import java.util.List;
+
+import android.content.Context;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+
+public class StableArrayAdapter extends ArrayAdapter<String> {
+
+    HashMap<String, Integer> mIdMap = new HashMap<String, Integer>();
+    View.OnTouchListener mTouchListener;
+
+    public StableArrayAdapter(Context context, int textViewResourceId,
+            List<String> objects, View.OnTouchListener listener) {
+        super(context, textViewResourceId, objects);
+        mTouchListener = listener;
+        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;
+    }
+
+    @Override
+    public View getView(int position, View convertView, ViewGroup parent) {
+        View view = super.getView(position, convertView, parent);
+        if (view != convertView) {
+            // Add touch listener to every new view to track swipe motion
+            view.setOnTouchListener(mTouchListener);
+        }
+        return view;
+    }
+
+}
diff --git a/samples/devbytes/animation/ListViewRemovalAnimation/AndroidManifest.xml b/samples/devbytes/animation/ListViewRemovalAnimation/AndroidManifest.xml
new file mode 100644
index 0000000..f030747
--- /dev/null
+++ b/samples/devbytes/animation/ListViewRemovalAnimation/AndroidManifest.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.example.android.listviewremovalanimation"
+    android:versionCode="1"
+    android:versionName="1.0" >
+
+    <uses-sdk
+        android:minSdkVersion="16"
+        android:targetSdkVersion="16" />
+
+    <application
+        android:allowBackup="true"
+        android:icon="@drawable/ic_launcher"
+        android:label="@string/app_name"
+        android:theme="@style/AppTheme" >
+        <activity
+            android:theme="@style/WithoutBackground"
+            android:name="com.example.android.listviewremovalanimation.ListViewRemovalAnimation"
+            android:label="@string/app_name" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+
+</manifest>
diff --git a/samples/devbytes/animation/ListViewRemovalAnimation/res/drawable-hdpi/ic_launcher.png b/samples/devbytes/animation/ListViewRemovalAnimation/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..96a442e
--- /dev/null
+++ b/samples/devbytes/animation/ListViewRemovalAnimation/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/samples/devbytes/animation/ListViewRemovalAnimation/res/drawable-mdpi/ic_launcher.png b/samples/devbytes/animation/ListViewRemovalAnimation/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..359047d
--- /dev/null
+++ b/samples/devbytes/animation/ListViewRemovalAnimation/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/samples/devbytes/animation/ListViewRemovalAnimation/res/drawable-xhdpi/ic_launcher.png b/samples/devbytes/animation/ListViewRemovalAnimation/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..71c6d76
--- /dev/null
+++ b/samples/devbytes/animation/ListViewRemovalAnimation/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/devbytes/animation/ListViewRemovalAnimation/res/drawable-xhdpi/shadowed_background.9.png b/samples/devbytes/animation/ListViewRemovalAnimation/res/drawable-xhdpi/shadowed_background.9.png
new file mode 100644
index 0000000..f905bbc
--- /dev/null
+++ b/samples/devbytes/animation/ListViewRemovalAnimation/res/drawable-xhdpi/shadowed_background.9.png
Binary files differ
diff --git a/samples/devbytes/animation/ListViewRemovalAnimation/res/drawable-xhdpi/tv_background_with_divider.9.png b/samples/devbytes/animation/ListViewRemovalAnimation/res/drawable-xhdpi/tv_background_with_divider.9.png
new file mode 100644
index 0000000..e6e3cd5
--- /dev/null
+++ b/samples/devbytes/animation/ListViewRemovalAnimation/res/drawable-xhdpi/tv_background_with_divider.9.png
Binary files differ
diff --git a/samples/devbytes/animation/ListViewRemovalAnimation/res/layout/activity_list_view_deletion.xml b/samples/devbytes/animation/ListViewRemovalAnimation/res/layout/activity_list_view_deletion.xml
new file mode 100644
index 0000000..26aa123
--- /dev/null
+++ b/samples/devbytes/animation/ListViewRemovalAnimation/res/layout/activity_list_view_deletion.xml
@@ -0,0 +1,37 @@
+<!-- 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.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:orientation="vertical"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    tools:context=".ListViewAnimations" >
+
+    <view
+        class="com.example.android.listviewremovalanimation.BackgroundContainer"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:id="@+id/listViewBackground">
+
+        <ListView
+            android:id="@+id/listview"
+            android:divider="@null"
+            android:dividerHeight="0dp"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content" />
+
+    </view>
+
+</LinearLayout>
diff --git a/samples/devbytes/animation/ListViewRemovalAnimation/res/layout/opaque_text_view.xml b/samples/devbytes/animation/ListViewRemovalAnimation/res/layout/opaque_text_view.xml
new file mode 100644
index 0000000..c37f62d
--- /dev/null
+++ b/samples/devbytes/animation/ListViewRemovalAnimation/res/layout/opaque_text_view.xml
@@ -0,0 +1,24 @@
+<!-- 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.
+-->
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:background="@drawable/tv_background_with_divider"
+    android:textAppearance="?android:attr/textAppearanceListItemSmall"
+    android:gravity="center_vertical"
+    android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+    android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
+    android:minHeight="?android:attr/listPreferredItemHeightSmall"
+/>
diff --git a/samples/devbytes/animation/ListViewRemovalAnimation/res/values-v11/styles.xml b/samples/devbytes/animation/ListViewRemovalAnimation/res/values-v11/styles.xml
new file mode 100644
index 0000000..139d283
--- /dev/null
+++ b/samples/devbytes/animation/ListViewRemovalAnimation/res/values-v11/styles.xml
@@ -0,0 +1,25 @@
+<!-- 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.
+-->
+<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>
diff --git a/samples/devbytes/animation/ListViewRemovalAnimation/res/values-v14/styles.xml b/samples/devbytes/animation/ListViewRemovalAnimation/res/values-v14/styles.xml
new file mode 100644
index 0000000..8ac4522
--- /dev/null
+++ b/samples/devbytes/animation/ListViewRemovalAnimation/res/values-v14/styles.xml
@@ -0,0 +1,26 @@
+<!-- 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.
+-->
+<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>
diff --git a/samples/devbytes/animation/ListViewRemovalAnimation/res/values/strings.xml b/samples/devbytes/animation/ListViewRemovalAnimation/res/values/strings.xml
new file mode 100644
index 0000000..7125618
--- /dev/null
+++ b/samples/devbytes/animation/ListViewRemovalAnimation/res/values/strings.xml
@@ -0,0 +1,21 @@
+<!-- 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.
+-->
+<resources>
+
+    <string name="app_name">ListViewRemovalAnimation</string>
+    <string name="use_positions">Use Positions</string>
+    <string name="delete_selected">Delete Selected</string>
+
+</resources>
diff --git a/samples/devbytes/animation/ListViewRemovalAnimation/res/values/styles.xml b/samples/devbytes/animation/ListViewRemovalAnimation/res/values/styles.xml
new file mode 100644
index 0000000..c7f2e79
--- /dev/null
+++ b/samples/devbytes/animation/ListViewRemovalAnimation/res/values/styles.xml
@@ -0,0 +1,37 @@
+<!-- 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.
+-->
+<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>
+
+    <style name="WithoutBackground" parent="AppTheme">
+        <item name="android:windowBackground">@null</item>
+    </style>
+</resources>
diff --git a/samples/devbytes/animation/ListViewRemovalAnimation/src/com/example/android/listviewremovalanimation/BackgroundContainer.java b/samples/devbytes/animation/ListViewRemovalAnimation/src/com/example/android/listviewremovalanimation/BackgroundContainer.java
new file mode 100644
index 0000000..1d0e806
--- /dev/null
+++ b/samples/devbytes/animation/ListViewRemovalAnimation/src/com/example/android/listviewremovalanimation/BackgroundContainer.java
@@ -0,0 +1,78 @@
+/*
+ * 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.example.android.listviewremovalanimation;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.widget.FrameLayout;
+
+public class BackgroundContainer extends FrameLayout {
+
+    boolean mShowing = false;
+    Drawable mShadowedBackground;
+    int mOpenAreaTop, mOpenAreaBottom, mOpenAreaHeight;
+    boolean mUpdateBounds = false;
+    
+    public BackgroundContainer(Context context) {
+        super(context);
+        init();
+    }
+
+    public BackgroundContainer(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        init();
+    }
+
+    public BackgroundContainer(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+        init();
+    }
+
+    private void init() {
+        mShadowedBackground =
+                getContext().getResources().getDrawable(R.drawable.shadowed_background);
+    }
+
+    public void showBackground(int top, int bottom) {
+        setWillNotDraw(false);
+        mOpenAreaTop = top;
+        mOpenAreaHeight = bottom;
+        mShowing = true;
+        mUpdateBounds = true;
+    }
+    
+    public void hideBackground() {
+        setWillNotDraw(true);
+        mShowing = false;
+    }
+    
+    @Override
+    protected void onDraw(Canvas canvas) {
+        if (mShowing) {
+            	if (mUpdateBounds) {
+                mShadowedBackground.setBounds(0, 0, getWidth(), mOpenAreaHeight);
+            	}
+            canvas.save();
+            canvas.translate(0, mOpenAreaTop);
+            mShadowedBackground.draw(canvas);
+            canvas.restore();
+        }
+    }
+
+}
diff --git a/samples/devbytes/animation/ListViewRemovalAnimation/src/com/example/android/listviewremovalanimation/Cheeses.java b/samples/devbytes/animation/ListViewRemovalAnimation/src/com/example/android/listviewremovalanimation/Cheeses.java
new file mode 100644
index 0000000..4f4b88b
--- /dev/null
+++ b/samples/devbytes/animation/ListViewRemovalAnimation/src/com/example/android/listviewremovalanimation/Cheeses.java
@@ -0,0 +1,154 @@
+/*
+ * 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.example.android.listviewremovalanimation;
+
+public class Cheeses {
+
+    public static final String[] sCheeseStrings = {
+            "Abbaye de Belloc", "Abbaye du Mont des Cats", "Abertam", "Abondance", "Ackawi",
+            "Acorn", "Adelost", "Affidelice au Chablis", "Afuega'l Pitu", "Airag", "Airedale",
+            "Aisy Cendre", "Allgauer Emmentaler", "Alverca", "Ambert", "American Cheese",
+            "Ami du Chambertin", "Anejo Enchilado", "Anneau du Vic-Bilh", "Anthoriro", "Appenzell",
+            "Aragon", "Ardi Gasna", "Ardrahan", "Armenian String", "Aromes au Gene de Marc",
+            "Asadero", "Asiago", "Aubisque Pyrenees", "Autun", "Avaxtskyr", "Baby Swiss",
+            "Babybel", "Baguette Laonnaise", "Bakers", "Baladi", "Balaton", "Bandal", "Banon",
+            "Barry's Bay Cheddar", "Basing", "Basket Cheese", "Bath Cheese", "Bavarian Bergkase",
+            "Baylough", "Beaufort", "Beauvoorde", "Beenleigh Blue", "Beer Cheese", "Bel Paese",
+            "Bergader", "Bergere Bleue", "Berkswell", "Beyaz Peynir", "Bierkase", "Bishop Kennedy",
+            "Blarney", "Bleu d'Auvergne", "Bleu de Gex", "Bleu de Laqueuille",
+            "Bleu de Septmoncel", "Bleu Des Causses", "Blue", "Blue Castello", "Blue Rathgore",
+            "Blue Vein (Australian)", "Blue Vein Cheeses", "Bocconcini", "Bocconcini (Australian)",
+            "Boeren Leidenkaas", "Bonchester", "Bosworth", "Bougon", "Boule Du Roves",
+            "Boulette d'Avesnes", "Boursault", "Boursin", "Bouyssou", "Bra", "Braudostur",
+            "Breakfast Cheese", "Brebis du Lavort", "Brebis du Lochois", "Brebis du Puyfaucon",
+            "Bresse Bleu", "Brick", "Brie", "Brie de Meaux", "Brie de Melun", "Brillat-Savarin",
+            "Brin", "Brin d' Amour", "Brin d'Amour", "Brinza (Burduf Brinza)",
+            "Briquette de Brebis", "Briquette du Forez", "Broccio", "Broccio Demi-Affine",
+            "Brousse du Rove", "Bruder Basil", "Brusselae Kaas (Fromage de Bruxelles)", "Bryndza",
+            "Buchette d'Anjou", "Buffalo", "Burgos", "Butte", "Butterkase", "Button (Innes)",
+            "Buxton Blue", "Cabecou", "Caboc", "Cabrales", "Cachaille", "Caciocavallo", "Caciotta",
+            "Caerphilly", "Cairnsmore", "Calenzana", "Cambazola", "Camembert de Normandie",
+            "Canadian Cheddar", "Canestrato", "Cantal", "Caprice des Dieux", "Capricorn Goat",
+            "Capriole Banon", "Carre de l'Est", "Casciotta di Urbino", "Cashel Blue", "Castellano",
+            "Castelleno", "Castelmagno", "Castelo Branco", "Castigliano", "Cathelain",
+            "Celtic Promise", "Cendre d'Olivet", "Cerney", "Chabichou", "Chabichou du Poitou",
+            "Chabis de Gatine", "Chaource", "Charolais", "Chaumes", "Cheddar",
+            "Cheddar Clothbound", "Cheshire", "Chevres", "Chevrotin des Aravis", "Chontaleno",
+            "Civray", "Coeur de Camembert au Calvados", "Coeur de Chevre", "Colby", "Cold Pack",
+            "Comte", "Coolea", "Cooleney", "Coquetdale", "Corleggy", "Cornish Pepper",
+            "Cotherstone", "Cotija", "Cottage Cheese", "Cottage Cheese (Australian)",
+            "Cougar Gold", "Coulommiers", "Coverdale", "Crayeux de Roncq", "Cream Cheese",
+            "Cream Havarti", "Crema Agria", "Crema Mexicana", "Creme Fraiche", "Crescenza",
+            "Croghan", "Crottin de Chavignol", "Crottin du Chavignol", "Crowdie", "Crowley",
+            "Cuajada", "Curd", "Cure Nantais", "Curworthy", "Cwmtawe Pecorino",
+            "Cypress Grove Chevre", "Danablu (Danish Blue)", "Danbo", "Danish Fontina",
+            "Daralagjazsky", "Dauphin", "Delice des Fiouves", "Denhany Dorset Drum", "Derby",
+            "Dessertnyj Belyj", "Devon Blue", "Devon Garland", "Dolcelatte", "Doolin",
+            "Doppelrhamstufel", "Dorset Blue Vinney", "Double Gloucester", "Double Worcester",
+            "Dreux a la Feuille", "Dry Jack", "Duddleswell", "Dunbarra", "Dunlop", "Dunsyre Blue",
+            "Duroblando", "Durrus", "Dutch Mimolette (Commissiekaas)", "Edam", "Edelpilz",
+            "Emental Grand Cru", "Emlett", "Emmental", "Epoisses de Bourgogne", "Esbareich",
+            "Esrom", "Etorki", "Evansdale Farmhouse Brie", "Evora De L'Alentejo", "Exmoor Blue",
+            "Explorateur", "Feta", "Feta (Australian)", "Figue", "Filetta", "Fin-de-Siecle",
+            "Finlandia Swiss", "Finn", "Fiore Sardo", "Fleur du Maquis", "Flor de Guia",
+            "Flower Marie", "Folded", "Folded cheese with mint", "Fondant de Brebis",
+            "Fontainebleau", "Fontal", "Fontina Val d'Aosta", "Formaggio di capra", "Fougerus",
+            "Four Herb Gouda", "Fourme d' Ambert", "Fourme de Haute Loire", "Fourme de Montbrison",
+            "Fresh Jack", "Fresh Mozzarella", "Fresh Ricotta", "Fresh Truffles", "Fribourgeois",
+            "Friesekaas", "Friesian", "Friesla", "Frinault", "Fromage a Raclette", "Fromage Corse",
+            "Fromage de Montagne de Savoie", "Fromage Frais", "Fruit Cream Cheese",
+            "Frying Cheese", "Fynbo", "Gabriel", "Galette du Paludier", "Galette Lyonnaise",
+            "Galloway Goat's Milk Gems", "Gammelost", "Gaperon a l'Ail", "Garrotxa", "Gastanberra",
+            "Geitost", "Gippsland Blue", "Gjetost", "Gloucester", "Golden Cross", "Gorgonzola",
+            "Gornyaltajski", "Gospel Green", "Gouda", "Goutu", "Gowrie", "Grabetto", "Graddost",
+            "Grafton Village Cheddar", "Grana", "Grana Padano", "Grand Vatel",
+            "Grataron d' Areches", "Gratte-Paille", "Graviera", "Greuilh", "Greve",
+            "Gris de Lille", "Gruyere", "Gubbeen", "Guerbigny", "Halloumi",
+            "Halloumy (Australian)", "Haloumi-Style Cheese", "Harbourne Blue", "Havarti",
+            "Heidi Gruyere", "Hereford Hop", "Herrgardsost", "Herriot Farmhouse", "Herve",
+            "Hipi Iti", "Hubbardston Blue Cow", "Hushallsost", "Iberico", "Idaho Goatster",
+            "Idiazabal", "Il Boschetto al Tartufo", "Ile d'Yeu", "Isle of Mull", "Jarlsberg",
+            "Jermi Tortes", "Jibneh Arabieh", "Jindi Brie", "Jubilee Blue", "Juustoleipa",
+            "Kadchgall", "Kaseri", "Kashta", "Kefalotyri", "Kenafa", "Kernhem", "Kervella Affine",
+            "Kikorangi", "King Island Cape Wickham Brie", "King River Gold", "Klosterkaese",
+            "Knockalara", "Kugelkase", "L'Aveyronnais", "L'Ecir de l'Aubrac", "La Taupiniere",
+            "La Vache Qui Rit", "Laguiole", "Lairobell", "Lajta", "Lanark Blue", "Lancashire",
+            "Langres", "Lappi", "Laruns", "Lavistown", "Le Brin", "Le Fium Orbo", "Le Lacandou",
+            "Le Roule", "Leafield", "Lebbene", "Leerdammer", "Leicester", "Leyden", "Limburger",
+            "Lincolnshire Poacher", "Lingot Saint Bousquet d'Orb", "Liptauer", "Little Rydings",
+            "Livarot", "Llanboidy", "Llanglofan Farmhouse", "Loch Arthur Farmhouse",
+            "Loddiswell Avondale", "Longhorn", "Lou Palou", "Lou Pevre", "Lyonnais", "Maasdam",
+            "Macconais", "Mahoe Aged Gouda", "Mahon", "Malvern", "Mamirolle", "Manchego",
+            "Manouri", "Manur", "Marble Cheddar", "Marbled Cheeses", "Maredsous", "Margotin",
+            "Maribo", "Maroilles", "Mascares", "Mascarpone", "Mascarpone (Australian)",
+            "Mascarpone Torta", "Matocq", "Maytag Blue", "Meira", "Menallack Farmhouse",
+            "Menonita", "Meredith Blue", "Mesost", "Metton (Cancoillotte)", "Meyer Vintage Gouda",
+            "Mihalic Peynir", "Milleens", "Mimolette", "Mine-Gabhar", "Mini Baby Bells", "Mixte",
+            "Molbo", "Monastery Cheeses", "Mondseer", "Mont D'or Lyonnais", "Montasio",
+            "Monterey Jack", "Monterey Jack Dry", "Morbier", "Morbier Cru de Montagne",
+            "Mothais a la Feuille", "Mozzarella", "Mozzarella (Australian)",
+            "Mozzarella di Bufala", "Mozzarella Fresh, in water", "Mozzarella Rolls", "Munster",
+            "Murol", "Mycella", "Myzithra", "Naboulsi", "Nantais", "Neufchatel",
+            "Neufchatel (Australian)", "Niolo", "Nokkelost", "Northumberland", "Oaxaca",
+            "Olde York", "Olivet au Foin", "Olivet Bleu", "Olivet Cendre",
+            "Orkney Extra Mature Cheddar", "Orla", "Oschtjepka", "Ossau Fermier", "Ossau-Iraty",
+            "Oszczypek", "Oxford Blue", "P'tit Berrichon", "Palet de Babligny", "Paneer", "Panela",
+            "Pannerone", "Pant ys Gawn", "Parmesan (Parmigiano)", "Parmigiano Reggiano",
+            "Pas de l'Escalette", "Passendale", "Pasteurized Processed", "Pate de Fromage",
+            "Patefine Fort", "Pave d'Affinois", "Pave d'Auge", "Pave de Chirac", "Pave du Berry",
+            "Pecorino", "Pecorino in Walnut Leaves", "Pecorino Romano", "Peekskill Pyramid",
+            "Pelardon des Cevennes", "Pelardon des Corbieres", "Penamellera", "Penbryn",
+            "Pencarreg", "Perail de Brebis", "Petit Morin", "Petit Pardou", "Petit-Suisse",
+            "Picodon de Chevre", "Picos de Europa", "Piora", "Pithtviers au Foin",
+            "Plateau de Herve", "Plymouth Cheese", "Podhalanski", "Poivre d'Ane", "Polkolbin",
+            "Pont l'Eveque", "Port Nicholson", "Port-Salut", "Postel", "Pouligny-Saint-Pierre",
+            "Pourly", "Prastost", "Pressato", "Prince-Jean", "Processed Cheddar", "Provolone",
+            "Provolone (Australian)", "Pyengana Cheddar", "Pyramide", "Quark",
+            "Quark (Australian)", "Quartirolo Lombardo", "Quatre-Vents", "Quercy Petit",
+            "Queso Blanco", "Queso Blanco con Frutas --Pina y Mango", "Queso de Murcia",
+            "Queso del Montsec", "Queso del Tietar", "Queso Fresco", "Queso Fresco (Adobera)",
+            "Queso Iberico", "Queso Jalapeno", "Queso Majorero", "Queso Media Luna",
+            "Queso Para Frier", "Queso Quesadilla", "Rabacal", "Raclette", "Ragusano", "Raschera",
+            "Reblochon", "Red Leicester", "Regal de la Dombes", "Reggianito", "Remedou",
+            "Requeson", "Richelieu", "Ricotta", "Ricotta (Australian)", "Ricotta Salata", "Ridder",
+            "Rigotte", "Rocamadour", "Rollot", "Romano", "Romans Part Dieu", "Roncal", "Roquefort",
+            "Roule", "Rouleau De Beaulieu", "Royalp Tilsit", "Rubens", "Rustinu", "Saaland Pfarr",
+            "Saanenkaese", "Saga", "Sage Derby", "Sainte Maure", "Saint-Marcellin",
+            "Saint-Nectaire", "Saint-Paulin", "Salers", "Samso", "San Simon", "Sancerre",
+            "Sap Sago", "Sardo", "Sardo Egyptian", "Sbrinz", "Scamorza", "Schabzieger", "Schloss",
+            "Selles sur Cher", "Selva", "Serat", "Seriously Strong Cheddar", "Serra da Estrela",
+            "Sharpam", "Shelburne Cheddar", "Shropshire Blue", "Siraz", "Sirene", "Smoked Gouda",
+            "Somerset Brie", "Sonoma Jack", "Sottocenare al Tartufo", "Soumaintrain",
+            "Sourire Lozerien", "Spenwood", "Sraffordshire Organic", "St. Agur Blue Cheese",
+            "Stilton", "Stinking Bishop", "String", "Sussex Slipcote", "Sveciaost", "Swaledale",
+            "Sweet Style Swiss", "Swiss", "Syrian (Armenian String)", "Tala", "Taleggio", "Tamie",
+            "Tasmania Highland Chevre Log", "Taupiniere", "Teifi", "Telemea", "Testouri",
+            "Tete de Moine", "Tetilla", "Texas Goat Cheese", "Tibet", "Tillamook Cheddar",
+            "Tilsit", "Timboon Brie", "Toma", "Tomme Brulee", "Tomme d'Abondance",
+            "Tomme de Chevre", "Tomme de Romans", "Tomme de Savoie", "Tomme des Chouans", "Tommes",
+            "Torta del Casar", "Toscanello", "Touree de L'Aubier", "Tourmalet",
+            "Trappe (Veritable)", "Trois Cornes De Vendee", "Tronchon", "Trou du Cru", "Truffe",
+            "Tupi", "Turunmaa", "Tymsboro", "Tyn Grug", "Tyning", "Ubriaco", "Ulloa",
+            "Vacherin-Fribourgeois", "Valencay", "Vasterbottenost", "Venaco", "Vendomois",
+            "Vieux Corse", "Vignotte", "Vulscombe", "Waimata Farmhouse Blue",
+            "Washed Rind Cheese (Australian)", "Waterloo", "Weichkaese", "Wellington",
+            "Wensleydale", "White Stilton", "Whitestone Farmhouse", "Wigmore", "Woodside Cabecou",
+            "Xanadu", "Xynotyro", "Yarg Cornish", "Yarra Valley Pyramid", "Yorkshire Blue",
+            "Zamorano", "Zanetti Grana Padano", "Zanetti Parmigiano Reggiano"
+    };
+
+}
diff --git a/samples/devbytes/animation/ListViewRemovalAnimation/src/com/example/android/listviewremovalanimation/ListViewRemovalAnimation.java b/samples/devbytes/animation/ListViewRemovalAnimation/src/com/example/android/listviewremovalanimation/ListViewRemovalAnimation.java
new file mode 100644
index 0000000..1e3ee8c
--- /dev/null
+++ b/samples/devbytes/animation/ListViewRemovalAnimation/src/com/example/android/listviewremovalanimation/ListViewRemovalAnimation.java
@@ -0,0 +1,248 @@
+/*
+ * 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.example.android.listviewremovalanimation;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewConfiguration;
+import android.view.ViewTreeObserver;
+import android.widget.ListView;
+
+/**
+ * This example shows how to use a swipe effect to remove items from a ListView,
+ * and how to use animations to complete the swipe as well as to animate the other
+ * items in the list into their final places.
+ *
+ * Watch the associated video for this demo on the DevBytes channel of developer.android.com
+ * or on YouTube at https://www.youtube.com/watch?v=NewCSg2JKLk.
+ */
+public class ListViewRemovalAnimation extends Activity {
+
+    StableArrayAdapter mAdapter;
+    ListView mListView;
+    BackgroundContainer mBackgroundContainer;
+    boolean mSwiping = false;
+    boolean mItemPressed = false;
+    HashMap<Long, Integer> mItemIdTopMap = new HashMap<Long, Integer>();
+
+    private static final int SWIPE_DURATION = 250;
+    private static final int MOVE_DURATION = 150;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_list_view_deletion);
+        
+        mBackgroundContainer = (BackgroundContainer) findViewById(R.id.listViewBackground);
+        mListView = (ListView) findViewById(R.id.listview);
+        android.util.Log.d("Debug", "d=" + mListView.getDivider());
+        final ArrayList<String> cheeseList = new ArrayList<String>();
+        for (int i = 0; i < Cheeses.sCheeseStrings.length; ++i) {
+            cheeseList.add(Cheeses.sCheeseStrings[i]);
+        }
+        mAdapter = new StableArrayAdapter(this,R.layout.opaque_text_view, cheeseList,
+                mTouchListener);
+        mListView.setAdapter(mAdapter);
+    }
+
+    /**
+     * Handle touch events to fade/move dragged items as they are swiped out
+     */
+    private View.OnTouchListener mTouchListener = new View.OnTouchListener() {
+        
+        float mDownX;
+        private int mSwipeSlop = -1;
+        
+        @Override
+        public boolean onTouch(final View v, MotionEvent event) {
+            if (mSwipeSlop < 0) {
+                mSwipeSlop = ViewConfiguration.get(ListViewRemovalAnimation.this).
+                        getScaledTouchSlop();
+            }
+            switch (event.getAction()) {
+            case MotionEvent.ACTION_DOWN:
+                if (mItemPressed) {
+                    // Multi-item swipes not handled
+                    return false;
+                }
+                mItemPressed = true;
+                mDownX = event.getX();
+                break;
+            case MotionEvent.ACTION_CANCEL:
+                v.setAlpha(1);
+                v.setTranslationX(0);
+                mItemPressed = false;
+                break;
+            case MotionEvent.ACTION_MOVE:
+                {
+                    float x = event.getX() + v.getTranslationX();
+                    float deltaX = x - mDownX;
+                    float deltaXAbs = Math.abs(deltaX);
+                    if (!mSwiping) {
+                        if (deltaXAbs > mSwipeSlop) {
+                            mSwiping = true;
+                            mListView.requestDisallowInterceptTouchEvent(true);
+                            mBackgroundContainer.showBackground(v.getTop(), v.getHeight());
+                        }
+                    }
+                    if (mSwiping) {
+                        v.setTranslationX((x - mDownX));
+                        v.setAlpha(1 - deltaXAbs / v.getWidth());
+                    }
+                }
+                break;
+            case MotionEvent.ACTION_UP:
+                {
+                    // User let go - figure out whether to animate the view out, or back into place
+                    if (mSwiping) {
+                        float x = event.getX() + v.getTranslationX();
+                        float deltaX = x - mDownX;
+                        float deltaXAbs = Math.abs(deltaX);
+                        float fractionCovered;
+                        float endX;
+                        float endAlpha;
+                        final boolean remove;
+                        if (deltaXAbs > v.getWidth() / 4) {
+                            // Greater than a quarter of the width - animate it out
+                            fractionCovered = deltaXAbs / v.getWidth();
+                            endX = deltaX < 0 ? -v.getWidth() : v.getWidth();
+                            endAlpha = 0;
+                            remove = true;
+                        } else {
+                            // Not far enough - animate it back
+                            fractionCovered = 1 - (deltaXAbs / v.getWidth());
+                            endX = 0;
+                            endAlpha = 1;
+                            remove = false;
+                        }
+                        // Animate position and alpha of swiped item
+                        // NOTE: This is a simplified version of swipe behavior, for the
+                        // purposes of this demo about animation. A real version should use
+                        // velocity (via the VelocityTracker class) to send the item off or
+                        // back at an appropriate speed.
+                        long duration = (int) ((1 - fractionCovered) * SWIPE_DURATION);
+                        mListView.setEnabled(false);
+                        v.animate().setDuration(duration).
+                                alpha(endAlpha).translationX(endX).
+                                withEndAction(new Runnable() {
+                                    @Override
+                                    public void run() {
+                                        // Restore animated values
+                                        v.setAlpha(1);
+                                        v.setTranslationX(0);
+                                        if (remove) {
+                                            animateRemoval(mListView, v);
+                                        } else {
+                                            mBackgroundContainer.hideBackground();
+                                            mSwiping = false;
+                                            mListView.setEnabled(true);
+                                        }
+                                    }
+                                });
+                    }
+                }
+                mItemPressed = false;
+                break;
+            default: 
+                return false;
+            }
+            return true;
+        }
+    };
+
+    /**
+     * This method animates all other views in the ListView container (not including ignoreView)
+     * into their final positions. It is called after ignoreView has been removed from the
+     * adapter, but before layout has been run. The approach here is to figure out where
+     * everything is now, then allow layout to run, then figure out where everything is after
+     * layout, and then to run animations between all of those start/end positions.
+     */
+    private void animateRemoval(final ListView listview, View viewToRemove) {
+        int firstVisiblePosition = listview.getFirstVisiblePosition();
+        for (int i = 0; i < listview.getChildCount(); ++i) {
+            View child = listview.getChildAt(i);
+            if (child != viewToRemove) {
+                int position = firstVisiblePosition + i;
+                long itemId = mAdapter.getItemId(position);
+                mItemIdTopMap.put(itemId, child.getTop());
+            }
+        }
+        // Delete the item from the adapter
+        int position = mListView.getPositionForView(viewToRemove);
+        mAdapter.remove(mAdapter.getItem(position));
+
+        final ViewTreeObserver observer = listview.getViewTreeObserver();
+        observer.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
+            public boolean onPreDraw() {
+                observer.removeOnPreDrawListener(this);
+                boolean firstAnimation = true;
+                int firstVisiblePosition = listview.getFirstVisiblePosition();
+                for (int i = 0; i < listview.getChildCount(); ++i) {
+                    final View child = listview.getChildAt(i);
+                    int position = firstVisiblePosition + i;
+                    long itemId = mAdapter.getItemId(position);
+                    Integer startTop = mItemIdTopMap.get(itemId);
+                    int top = child.getTop();
+                    if (startTop != null) {
+                        if (startTop != top) {
+                            int delta = startTop - top;
+                            child.setTranslationY(delta);
+                            child.animate().setDuration(MOVE_DURATION).translationY(0);
+                            if (firstAnimation) {
+                                child.animate().withEndAction(new Runnable() {
+                                    public void run() {
+                                        mBackgroundContainer.hideBackground();
+                                        mSwiping = false;
+                                        mListView.setEnabled(true);
+                                    }
+                                });
+                                firstAnimation = false;
+                            }
+                        }
+                    } else {
+                        // Animate new views along with the others. The catch is that they did not
+                        // exist in the start state, so we must calculate their starting position
+                        // based on neighboring views.
+                        int childHeight = child.getHeight() + listview.getDividerHeight();
+                        startTop = top + (i > 0 ? childHeight : -childHeight);
+                        int delta = startTop - top;
+                        child.setTranslationY(delta);
+                        child.animate().setDuration(MOVE_DURATION).translationY(0);
+                        if (firstAnimation) {
+                            child.animate().withEndAction(new Runnable() {
+                                public void run() {
+                                    mBackgroundContainer.hideBackground();
+                                    mSwiping = false;
+                                    mListView.setEnabled(true);
+                                }
+                            });
+                            firstAnimation = false;
+                        }
+                    }
+                }
+                mItemIdTopMap.clear();
+                return true;
+            }
+        });
+    }
+
+}
diff --git a/samples/devbytes/animation/ListViewRemovalAnimation/src/com/example/android/listviewremovalanimation/StableArrayAdapter.java b/samples/devbytes/animation/ListViewRemovalAnimation/src/com/example/android/listviewremovalanimation/StableArrayAdapter.java
new file mode 100644
index 0000000..948676e
--- /dev/null
+++ b/samples/devbytes/animation/ListViewRemovalAnimation/src/com/example/android/listviewremovalanimation/StableArrayAdapter.java
@@ -0,0 +1,62 @@
+/*
+ * 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.example.android.listviewremovalanimation;
+
+import java.util.HashMap;
+import java.util.List;
+
+import android.content.Context;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+
+public class StableArrayAdapter extends ArrayAdapter<String> {
+
+    HashMap<String, Integer> mIdMap = new HashMap<String, Integer>();
+    View.OnTouchListener mTouchListener;
+
+    public StableArrayAdapter(Context context, int textViewResourceId,
+            List<String> objects, View.OnTouchListener listener) {
+        super(context, textViewResourceId, objects);
+        mTouchListener = listener;
+        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;
+    }
+
+    @Override
+    public View getView(int position, View convertView, ViewGroup parent) {
+        View view = super.getView(position, convertView, parent);
+        if (view != convertView) {
+            // Add touch listener to every new view to track swipe motion
+            view.setOnTouchListener(mTouchListener);
+        }
+        return view;
+    }
+
+}
diff --git a/samples/devbytes/animation/LiveButton/AndroidManifest.xml b/samples/devbytes/animation/LiveButton/AndroidManifest.xml
new file mode 100644
index 0000000..280c2f8
--- /dev/null
+++ b/samples/devbytes/animation/LiveButton/AndroidManifest.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.example.android.livebutton"
+    android:versionCode="1"
+    android:versionName="1.0" >
+
+    <uses-sdk
+        android:minSdkVersion="14"
+        android:targetSdkVersion="17" />
+
+    <application
+        android:allowBackup="true"
+        android:icon="@drawable/ic_launcher"
+        android:label="@string/app_name"
+        android:theme="@style/AppTheme" >
+        <activity
+            android:name="com.example.android.livebutton.LiveButton"
+            android:label="@string/app_name" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+
+</manifest>
\ No newline at end of file
diff --git a/samples/devbytes/animation/LiveButton/res/drawable-hdpi/ic_launcher.png b/samples/devbytes/animation/LiveButton/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..96a442e
--- /dev/null
+++ b/samples/devbytes/animation/LiveButton/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/samples/devbytes/animation/LiveButton/res/drawable-mdpi/ic_launcher.png b/samples/devbytes/animation/LiveButton/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..359047d
--- /dev/null
+++ b/samples/devbytes/animation/LiveButton/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/samples/devbytes/animation/LiveButton/res/drawable-xhdpi/ic_launcher.png b/samples/devbytes/animation/LiveButton/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..71c6d76
--- /dev/null
+++ b/samples/devbytes/animation/LiveButton/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/devbytes/animation/LiveButton/res/layout/activity_overshoot.xml b/samples/devbytes/animation/LiveButton/res/layout/activity_overshoot.xml
new file mode 100644
index 0000000..6900650
--- /dev/null
+++ b/samples/devbytes/animation/LiveButton/res/layout/activity_overshoot.xml
@@ -0,0 +1,29 @@
+<!-- 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.
+-->
+<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"
+    tools:context=".LiveButton" >
+
+    <Button
+        android:id="@+id/clickMe"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_centerHorizontal="true"
+        android:layout_centerVertical="true"
+        android:text="Click me!" />
+
+</RelativeLayout>
\ No newline at end of file
diff --git a/samples/devbytes/animation/LiveButton/res/values-v14/styles.xml b/samples/devbytes/animation/LiveButton/res/values-v14/styles.xml
new file mode 100644
index 0000000..6e9521a
--- /dev/null
+++ b/samples/devbytes/animation/LiveButton/res/values-v14/styles.xml
@@ -0,0 +1,26 @@
+<!-- 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.
+-->
+<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/samples/devbytes/animation/LiveButton/res/values/strings.xml b/samples/devbytes/animation/LiveButton/res/values/strings.xml
new file mode 100644
index 0000000..5c5ff17
--- /dev/null
+++ b/samples/devbytes/animation/LiveButton/res/values/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<resources>
+
+    <string name="app_name">LiveButton</string>
+    <string name="hello_world">Hello world!</string>
+    <string name="menu_settings">Settings</string>
+
+</resources>
\ No newline at end of file
diff --git a/samples/devbytes/animation/LiveButton/res/values/styles.xml b/samples/devbytes/animation/LiveButton/res/values/styles.xml
new file mode 100644
index 0000000..27658b7
--- /dev/null
+++ b/samples/devbytes/animation/LiveButton/res/values/styles.xml
@@ -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.
+-->
+<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/samples/devbytes/animation/LiveButton/src/com/example/android/livebutton/LiveButton.java b/samples/devbytes/animation/LiveButton/src/com/example/android/livebutton/LiveButton.java
new file mode 100644
index 0000000..d9f8d5e
--- /dev/null
+++ b/samples/devbytes/animation/LiveButton/src/com/example/android/livebutton/LiveButton.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.example.android.livebutton;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.animation.DecelerateInterpolator;
+import android.view.animation.OvershootInterpolator;
+import android.widget.Button;
+
+/**
+ * This app shows a simple application of anticipation and follow-through techniques as
+ * the button animates into its pressed state and animates back out of it, overshooting
+ * end state before resolving.
+ *
+ * Watch the associated video for this demo on the DevBytes channel of developer.android.com
+ * or on the DevBytes playlist in the androiddevelopers channel on YouTube at
+ * https://www.youtube.com/playlist?list=PLWz5rJ2EKKc_XOgcRukSoKKjewFJZrKV0.
+ */
+public class LiveButton extends Activity {
+    
+    DecelerateInterpolator sDecelerator = new DecelerateInterpolator();
+    OvershootInterpolator sOvershooter = new OvershootInterpolator(10f);
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_overshoot);
+        
+        final Button clickMeButton = (Button) findViewById(R.id.clickMe);
+        clickMeButton.animate().setDuration(200);
+        
+        clickMeButton.setOnTouchListener(new View.OnTouchListener() {
+            
+            @Override
+            public boolean onTouch(View arg0, MotionEvent arg1) {
+                if (arg1.getAction() == MotionEvent.ACTION_DOWN) {
+                    clickMeButton.animate().setInterpolator(sDecelerator).
+                            scaleX(.7f).scaleY(.7f);
+                } else if (arg1.getAction() == MotionEvent.ACTION_UP) {
+                    clickMeButton.animate().setInterpolator(sOvershooter).
+                            scaleX(1f).scaleY(1f);
+                }
+                return false;
+            }
+        });
+        
+    }
+}
diff --git a/samples/devbytes/animation/MultiPropertyAnimations/AndroidManifest.xml b/samples/devbytes/animation/MultiPropertyAnimations/AndroidManifest.xml
new file mode 100644
index 0000000..6a7a593
--- /dev/null
+++ b/samples/devbytes/animation/MultiPropertyAnimations/AndroidManifest.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.example.android.multipropertyanimations"
+    android:versionCode="1"
+    android:versionName="1.0" >
+
+    <uses-sdk
+        android:minSdkVersion="14"
+        android:targetSdkVersion="17" />
+
+    <application
+        android:allowBackup="true"
+        android:icon="@drawable/ic_launcher"
+        android:label="@string/app_name"
+        android:theme="@style/AppTheme" >
+        <activity
+            android:name="com.example.android.multipropertyanimations.MultiPropertyAnimations"
+            android:label="@string/app_name" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+
+</manifest>
\ No newline at end of file
diff --git a/samples/devbytes/animation/MultiPropertyAnimations/res/drawable-hdpi/ic_launcher.png b/samples/devbytes/animation/MultiPropertyAnimations/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..96a442e
--- /dev/null
+++ b/samples/devbytes/animation/MultiPropertyAnimations/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/samples/devbytes/animation/MultiPropertyAnimations/res/drawable-mdpi/ic_launcher.png b/samples/devbytes/animation/MultiPropertyAnimations/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..359047d
--- /dev/null
+++ b/samples/devbytes/animation/MultiPropertyAnimations/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/samples/devbytes/animation/MultiPropertyAnimations/res/drawable-xhdpi/ic_launcher.png b/samples/devbytes/animation/MultiPropertyAnimations/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..71c6d76
--- /dev/null
+++ b/samples/devbytes/animation/MultiPropertyAnimations/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/devbytes/animation/MultiPropertyAnimations/res/layout/activity_multi_property_animations.xml b/samples/devbytes/animation/MultiPropertyAnimations/res/layout/activity_multi_property_animations.xml
new file mode 100644
index 0000000..f4826b6
--- /dev/null
+++ b/samples/devbytes/animation/MultiPropertyAnimations/res/layout/activity_multi_property_animations.xml
@@ -0,0 +1,46 @@
+<!-- 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.
+-->
+<LinearLayout 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:orientation="vertical"
+    tools:context=".MultiPropertyAnimations" >
+
+    <Button
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:onClick="runValueAnimator"
+        android:text="Animate Me!" />
+
+    <Button
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:onClick="runViewPropertyAnimator"
+        android:text="Animate Me!" />
+
+    <Button
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:onClick="runObjectAnimators"
+        android:text="Animate Me!" />
+
+    <Button
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:onClick="runObjectAnimator"
+        android:text="Animate Me!" />
+
+</LinearLayout>
\ No newline at end of file
diff --git a/samples/devbytes/animation/MultiPropertyAnimations/res/values-v14/styles.xml b/samples/devbytes/animation/MultiPropertyAnimations/res/values-v14/styles.xml
new file mode 100644
index 0000000..6e9521a
--- /dev/null
+++ b/samples/devbytes/animation/MultiPropertyAnimations/res/values-v14/styles.xml
@@ -0,0 +1,26 @@
+<!-- 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.
+-->
+<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/samples/devbytes/animation/MultiPropertyAnimations/res/values/dimens.xml b/samples/devbytes/animation/MultiPropertyAnimations/res/values/dimens.xml
new file mode 100644
index 0000000..90db76b
--- /dev/null
+++ b/samples/devbytes/animation/MultiPropertyAnimations/res/values/dimens.xml
@@ -0,0 +1,21 @@
+<!-- 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.
+-->
+<resources>
+
+    <!-- Default screen margins, per the Android Design guidelines. -->
+    <dimen name="activity_horizontal_margin">16dp</dimen>
+    <dimen name="activity_vertical_margin">16dp</dimen>
+
+</resources>
\ No newline at end of file
diff --git a/samples/devbytes/animation/MultiPropertyAnimations/res/values/strings.xml b/samples/devbytes/animation/MultiPropertyAnimations/res/values/strings.xml
new file mode 100644
index 0000000..5487857
--- /dev/null
+++ b/samples/devbytes/animation/MultiPropertyAnimations/res/values/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<resources>
+
+    <string name="app_name">MultiPropertyAnimations</string>
+    <string name="action_settings">Settings</string>
+    <string name="hello_world">Hello world!</string>
+
+</resources>
\ No newline at end of file
diff --git a/samples/devbytes/animation/MultiPropertyAnimations/res/values/styles.xml b/samples/devbytes/animation/MultiPropertyAnimations/res/values/styles.xml
new file mode 100644
index 0000000..27658b7
--- /dev/null
+++ b/samples/devbytes/animation/MultiPropertyAnimations/res/values/styles.xml
@@ -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.
+-->
+<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/samples/devbytes/animation/MultiPropertyAnimations/src/com/example/android/multipropertyanimations/MultiPropertyAnimations.java b/samples/devbytes/animation/MultiPropertyAnimations/src/com/example/android/multipropertyanimations/MultiPropertyAnimations.java
new file mode 100644
index 0000000..e1c8054
--- /dev/null
+++ b/samples/devbytes/animation/MultiPropertyAnimations/src/com/example/android/multipropertyanimations/MultiPropertyAnimations.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.example.android.multipropertyanimations;
+
+import android.animation.ObjectAnimator;
+import android.animation.PropertyValuesHolder;
+import android.animation.ValueAnimator;
+import android.animation.ValueAnimator.AnimatorUpdateListener;
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.View;
+
+/**
+ * This example shows various ways of animating multiple properties in parallel.
+ *
+ * Watch the associated video for this demo on the DevBytes channel of developer.android.com
+ * or on the DevBytes playlist in the androiddevelopers channel on YouTube at
+ * https://www.youtube.com/playlist?list=PLWz5rJ2EKKc_XOgcRukSoKKjewFJZrKV0.
+ */
+public class MultiPropertyAnimations extends Activity {
+
+    private static final float TX_START = 0;
+    private static final float TY_START = 0;
+    private static final float TX_END = 400;
+    private static final float TY_END = 200;
+    
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_multi_property_animations);
+    }
+
+    /**
+     * A very manual approach to animation uses a ValueAnimator to animate a fractional
+     * value and then turns that value into the final property values which are then set
+     * directly on the target object.
+     */
+    public void runValueAnimator(final View view) {
+        ValueAnimator anim = ValueAnimator.ofFloat(0, 400);
+        anim.addUpdateListener(new AnimatorUpdateListener() {
+            @Override
+            public void onAnimationUpdate(ValueAnimator animator) {
+                float fraction = animator.getAnimatedFraction();
+                view.setTranslationX(TX_START + fraction * (TX_END - TX_START));
+                view.setTranslationY(TY_START + fraction * (TY_END - TY_START));
+            }
+        });
+        anim.start();
+    }
+
+    /**
+     * ViewPropertyAnimator is the cleanest and most efficient way of animating
+     * View properties, even when there are multiple properties to be animated
+     * in parallel.
+     */
+    public void runViewPropertyAnimator(View view) {
+        view.animate().translationX(TX_END).translationY(TY_END);
+    }
+
+    /**
+     * Multiple ObjectAnimator objects can be created and run in parallel.
+     */
+    public void runObjectAnimators(View view) {
+        ObjectAnimator.ofFloat(view, View.TRANSLATION_X, TX_END).start();
+        ObjectAnimator.ofFloat(view, View.TRANSLATION_Y, TY_END).start();
+        // Optional: use an AnimatorSet to run these in parallel
+    }
+    
+    /**
+     * Using PropertyValuesHolder objects enables the use of a single ObjectAnimator
+     * per target, even when there are multiple properties being animated on that target.
+     */
+    public void runObjectAnimator(View view) {
+        PropertyValuesHolder pvhTX = PropertyValuesHolder.ofFloat(View.TRANSLATION_X, TX_END);
+        PropertyValuesHolder pvhTY = PropertyValuesHolder.ofFloat(View.TRANSLATION_Y, TY_END);
+        ObjectAnimator.ofPropertyValuesHolder(view, pvhTX, pvhTY).start();
+    }
+}
diff --git a/samples/devbytes/animation/SquashAndStretch/AndroidManifest.xml b/samples/devbytes/animation/SquashAndStretch/AndroidManifest.xml
new file mode 100644
index 0000000..82e9b1b
--- /dev/null
+++ b/samples/devbytes/animation/SquashAndStretch/AndroidManifest.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.example.squashandstretch"
+    android:versionCode="1"
+    android:versionName="1.0" >
+
+    <uses-sdk
+        android:minSdkVersion="14"
+        android:targetSdkVersion="17" />
+
+    <application
+        android:allowBackup="true"
+        android:icon="@drawable/ic_launcher"
+        android:label="@string/app_name"
+        android:theme="@style/AppTheme" >
+        <activity
+            android:name="com.example.squashandstretch.SquashAndStretch"
+            android:label="@string/app_name" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+
+</manifest>
\ No newline at end of file
diff --git a/samples/devbytes/animation/SquashAndStretch/res/drawable-hdpi/ic_launcher.png b/samples/devbytes/animation/SquashAndStretch/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..96a442e
--- /dev/null
+++ b/samples/devbytes/animation/SquashAndStretch/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/samples/devbytes/animation/SquashAndStretch/res/drawable-mdpi/ic_launcher.png b/samples/devbytes/animation/SquashAndStretch/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..359047d
--- /dev/null
+++ b/samples/devbytes/animation/SquashAndStretch/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/samples/devbytes/animation/SquashAndStretch/res/drawable-xhdpi/ic_launcher.png b/samples/devbytes/animation/SquashAndStretch/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..71c6d76
--- /dev/null
+++ b/samples/devbytes/animation/SquashAndStretch/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/devbytes/animation/SquashAndStretch/res/layout/main.xml b/samples/devbytes/animation/SquashAndStretch/res/layout/main.xml
new file mode 100644
index 0000000..ea6793d
--- /dev/null
+++ b/samples/devbytes/animation/SquashAndStretch/res/layout/main.xml
@@ -0,0 +1,31 @@
+<!-- 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.
+-->
+<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=".SquashAndStretch" >
+
+    <Button
+        android:id="@+id/button"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignParentTop="true"
+        android:layout_centerHorizontal="true"
+        android:onClick="onButtonClick"
+        android:text="Click Me!" />
+
+</RelativeLayout>
\ No newline at end of file
diff --git a/samples/devbytes/animation/SquashAndStretch/res/menu/main.xml b/samples/devbytes/animation/SquashAndStretch/res/menu/main.xml
new file mode 100644
index 0000000..aab540e
--- /dev/null
+++ b/samples/devbytes/animation/SquashAndStretch/res/menu/main.xml
@@ -0,0 +1,24 @@
+<!-- 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.
+-->
+<menu xmlns:android="http://schemas.android.com/apk/res/android" >
+
+    <item
+        android:id="@+id/menu_slow"
+        android:orderInCategory="100"
+        android:showAsAction="never"
+        android:title="@string/menu_slow_animations"
+        android:checkable="true"/>
+
+</menu>
\ No newline at end of file
diff --git a/samples/devbytes/animation/SquashAndStretch/res/values-v14/styles.xml b/samples/devbytes/animation/SquashAndStretch/res/values-v14/styles.xml
new file mode 100644
index 0000000..6e9521a
--- /dev/null
+++ b/samples/devbytes/animation/SquashAndStretch/res/values-v14/styles.xml
@@ -0,0 +1,26 @@
+<!-- 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.
+-->
+<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/samples/devbytes/animation/SquashAndStretch/res/values/strings.xml b/samples/devbytes/animation/SquashAndStretch/res/values/strings.xml
new file mode 100644
index 0000000..3fb1b96
--- /dev/null
+++ b/samples/devbytes/animation/SquashAndStretch/res/values/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<resources>
+
+    <string name="app_name">SquashAndStretch</string>
+    <string name="hello_world">Hello world!</string>
+    <string name="menu_slow_animations">Slow</string>
+
+</resources>
\ No newline at end of file
diff --git a/samples/devbytes/animation/SquashAndStretch/res/values/styles.xml b/samples/devbytes/animation/SquashAndStretch/res/values/styles.xml
new file mode 100644
index 0000000..27658b7
--- /dev/null
+++ b/samples/devbytes/animation/SquashAndStretch/res/values/styles.xml
@@ -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.
+-->
+<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/samples/devbytes/animation/SquashAndStretch/src/com/example/squashandstretch/SquashAndStretch.java b/samples/devbytes/animation/SquashAndStretch/src/com/example/squashandstretch/SquashAndStretch.java
new file mode 100644
index 0000000..328dd50
--- /dev/null
+++ b/samples/devbytes/animation/SquashAndStretch/src/com/example/squashandstretch/SquashAndStretch.java
@@ -0,0 +1,114 @@
+/*
+ * 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.example.squashandstretch;
+
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.animation.PropertyValuesHolder;
+import android.animation.ValueAnimator;
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.animation.AccelerateInterpolator;
+import android.view.animation.DecelerateInterpolator;
+
+/**
+ * This example shows how to add some life to a view during animation by deforming the shape.
+ * As the button "falls", it stretches along the line of travel. When it hits the bottom, it
+ * squashes, like a real object when hitting a surface. Then the button reverses these actions
+ * to bounce back up to the start.
+ *
+ * Watch the associated video for this demo on the DevBytes channel of developer.android.com
+ * or on the DevBytes playlist in the androiddevelopers channel on YouTube at
+ * https://www.youtube.com/playlist?list=PLWz5rJ2EKKc_XOgcRukSoKKjewFJZrKV0.
+ */
+public class SquashAndStretch extends Activity {
+
+    private static final AccelerateInterpolator sAccelerator = new AccelerateInterpolator();
+    private static final DecelerateInterpolator sDecelerator = new DecelerateInterpolator();
+
+    ViewGroup mContainer = null;
+    private static final long BASE_DURATION = 300;
+    private long sAnimatorScale = 1;
+    
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.main);
+        
+        mContainer = (ViewGroup) findViewById(R.id.container);
+    }
+
+    @Override
+    public boolean onCreateOptionsMenu(Menu menu) {
+        getMenuInflater().inflate(R.menu.main, menu);
+        return true;
+    }
+    
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        if (item.getItemId() == R.id.menu_slow) {
+            sAnimatorScale = item.isChecked() ? 1 : 5;
+            item.setChecked(!item.isChecked());
+        }
+        return super.onOptionsItemSelected(item);
+    }
+
+    public void onButtonClick(View view) {
+        long animationDuration = (long) (BASE_DURATION * sAnimatorScale);
+
+        // Scale around bottom/middle to simplify squash against the window bottom
+        view.setPivotX(view.getWidth() / 2);
+        view.setPivotY(view.getHeight());
+        
+        // Animate the button down, accelerating, while also stretching in Y and squashing in X
+        PropertyValuesHolder pvhTY = PropertyValuesHolder.ofFloat(View.TRANSLATION_Y,
+                mContainer.getHeight() - view.getHeight());
+        PropertyValuesHolder pvhSX = PropertyValuesHolder.ofFloat(View.SCALE_X, .7f);
+        PropertyValuesHolder pvhSY = PropertyValuesHolder.ofFloat(View.SCALE_Y, 1.2f);
+        ObjectAnimator downAnim = ObjectAnimator.ofPropertyValuesHolder(
+                view, pvhTY, pvhSX, pvhSY);
+        downAnim.setInterpolator(sAccelerator);
+        downAnim.setDuration((long) (animationDuration * 2));
+
+        // Stretch in X, squash in Y, then reverse
+        pvhSX = PropertyValuesHolder.ofFloat(View.SCALE_X, 2);
+        pvhSY = PropertyValuesHolder.ofFloat(View.SCALE_Y, .5f);
+        ObjectAnimator stretchAnim =
+                ObjectAnimator.ofPropertyValuesHolder(view, pvhSX, pvhSY);
+        stretchAnim.setRepeatCount(1);
+        stretchAnim.setRepeatMode(ValueAnimator.REVERSE);
+        stretchAnim.setInterpolator(sDecelerator);
+        stretchAnim.setDuration(animationDuration);
+        
+        // Animate back to the start
+        pvhTY = PropertyValuesHolder.ofFloat(View.TRANSLATION_Y, 0);
+        pvhSX = PropertyValuesHolder.ofFloat(View.SCALE_X, 1);
+        pvhSY = PropertyValuesHolder.ofFloat(View.SCALE_Y, 1);
+        ObjectAnimator upAnim =
+                ObjectAnimator.ofPropertyValuesHolder(view, pvhTY, pvhSX, pvhSY);
+        upAnim.setDuration((long) (animationDuration * 2));
+        upAnim.setInterpolator(sDecelerator);
+
+        AnimatorSet set = new AnimatorSet();
+        set.playSequentially(downAnim, stretchAnim, upAnim);
+        set.start();
+    }
+}
diff --git a/samples/devbytes/animation/ToonGame/AndroidManifest.xml b/samples/devbytes/animation/ToonGame/AndroidManifest.xml
new file mode 100644
index 0000000..505b7ce
--- /dev/null
+++ b/samples/devbytes/animation/ToonGame/AndroidManifest.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.example.android.toongame"
+    android:versionCode="1"
+    android:versionName="1.0" >
+
+    <uses-sdk
+        android:minSdkVersion="16"
+        android:targetSdkVersion="17" />
+
+    <application
+        android:allowBackup="true"
+        android:icon="@drawable/ic_launcher"
+        android:label="@string/app_name"
+        android:theme="@style/AppTheme" >
+        <activity
+            android:name="com.example.android.toongame.ToonGame"
+            android:label="@string/app_name" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+        <activity
+            android:name="com.example.android.toongame.PlayerSetupActivity"
+            android:windowSoftInputMode="adjustResize"
+            android:label="@string/app_name" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+            </intent-filter>
+        </activity>
+        </application>
+
+</manifest>
\ No newline at end of file
diff --git a/samples/devbytes/animation/ToonGame/res/drawable-hdpi/ic_launcher.png b/samples/devbytes/animation/ToonGame/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..96a442e
--- /dev/null
+++ b/samples/devbytes/animation/ToonGame/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/samples/devbytes/animation/ToonGame/res/drawable-mdpi/blue_oval.xml b/samples/devbytes/animation/ToonGame/res/drawable-mdpi/blue_oval.xml
new file mode 100644
index 0000000..2ffe16a
--- /dev/null
+++ b/samples/devbytes/animation/ToonGame/res/drawable-mdpi/blue_oval.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="oval">
+    
+    <solid android:color="#00f"/>
+
+</shape>
\ No newline at end of file
diff --git a/samples/devbytes/animation/ToonGame/res/drawable-mdpi/cyan_oval.xml b/samples/devbytes/animation/ToonGame/res/drawable-mdpi/cyan_oval.xml
new file mode 100644
index 0000000..53ea6ac
--- /dev/null
+++ b/samples/devbytes/animation/ToonGame/res/drawable-mdpi/cyan_oval.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="oval">
+    
+    <solid android:color="#0ff"/>
+
+</shape>
\ No newline at end of file
diff --git a/samples/devbytes/animation/ToonGame/res/drawable-mdpi/green_button.xml b/samples/devbytes/animation/ToonGame/res/drawable-mdpi/green_button.xml
new file mode 100644
index 0000000..3ed5b67
--- /dev/null
+++ b/samples/devbytes/animation/ToonGame/res/drawable-mdpi/green_button.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android" >
+    <item android:drawable="@drawable/green_down" android:state_pressed="true"/>
+    <item android:drawable="@drawable/green_up"/>
+</selector>
\ No newline at end of file
diff --git a/samples/devbytes/animation/ToonGame/res/drawable-mdpi/green_down.9.png b/samples/devbytes/animation/ToonGame/res/drawable-mdpi/green_down.9.png
new file mode 100644
index 0000000..db974ba
--- /dev/null
+++ b/samples/devbytes/animation/ToonGame/res/drawable-mdpi/green_down.9.png
Binary files differ
diff --git a/samples/devbytes/animation/ToonGame/res/drawable-mdpi/green_oval.xml b/samples/devbytes/animation/ToonGame/res/drawable-mdpi/green_oval.xml
new file mode 100644
index 0000000..03b83c3
--- /dev/null
+++ b/samples/devbytes/animation/ToonGame/res/drawable-mdpi/green_oval.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="oval">
+    
+    <solid android:color="#0f0"/>
+
+</shape>
\ No newline at end of file
diff --git a/samples/devbytes/animation/ToonGame/res/drawable-mdpi/green_up.9.png b/samples/devbytes/animation/ToonGame/res/drawable-mdpi/green_up.9.png
new file mode 100644
index 0000000..0c2f5c8
--- /dev/null
+++ b/samples/devbytes/animation/ToonGame/res/drawable-mdpi/green_up.9.png
Binary files differ
diff --git a/samples/devbytes/animation/ToonGame/res/drawable-mdpi/ic_launcher.png b/samples/devbytes/animation/ToonGame/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..359047d
--- /dev/null
+++ b/samples/devbytes/animation/ToonGame/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/samples/devbytes/animation/ToonGame/res/drawable-mdpi/magenta_oval.xml b/samples/devbytes/animation/ToonGame/res/drawable-mdpi/magenta_oval.xml
new file mode 100644
index 0000000..675b0dc
--- /dev/null
+++ b/samples/devbytes/animation/ToonGame/res/drawable-mdpi/magenta_oval.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="oval">
+    
+    <solid android:color="#f0f"/>
+
+</shape>
\ No newline at end of file
diff --git a/samples/devbytes/animation/ToonGame/res/drawable-mdpi/red_oval.xml b/samples/devbytes/animation/ToonGame/res/drawable-mdpi/red_oval.xml
new file mode 100644
index 0000000..f2276a6
--- /dev/null
+++ b/samples/devbytes/animation/ToonGame/res/drawable-mdpi/red_oval.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="oval">
+    
+    <solid android:color="#f00"/>
+
+</shape>
\ No newline at end of file
diff --git a/samples/devbytes/animation/ToonGame/res/drawable-mdpi/yellow_oval.xml b/samples/devbytes/animation/ToonGame/res/drawable-mdpi/yellow_oval.xml
new file mode 100644
index 0000000..d03f684
--- /dev/null
+++ b/samples/devbytes/animation/ToonGame/res/drawable-mdpi/yellow_oval.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="oval">
+    
+    <solid android:color="#ff0"/>
+
+</shape>
\ No newline at end of file
diff --git a/samples/devbytes/animation/ToonGame/res/drawable-xhdpi/ic_launcher.png b/samples/devbytes/animation/ToonGame/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..71c6d76
--- /dev/null
+++ b/samples/devbytes/animation/ToonGame/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/devbytes/animation/ToonGame/res/layout/activity_toon_game.xml b/samples/devbytes/animation/ToonGame/res/layout/activity_toon_game.xml
new file mode 100644
index 0000000..d65301b
--- /dev/null
+++ b/samples/devbytes/animation/ToonGame/res/layout/activity_toon_game.xml
@@ -0,0 +1,47 @@
+<!-- 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.
+-->
+<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=".ToonGame" >
+
+    <Button
+        android:id="@+id/startButton"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:textSize="64dip"
+        android:layout_centerHorizontal="true"
+        android:layout_centerVertical="true"
+        android:textColor="#00c"
+        android:text="Play!"
+        android:background="@drawable/green_button"
+        android:visibility="invisible"
+        android:onClick="play"
+        android:textStyle="bold" />
+
+    <TextView
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_above="@+id/startButton"
+        android:layout_centerHorizontal="true"
+        android:layout_marginBottom="39dp"
+        android:text="@string/welcome"
+        android:textColor="@android:color/holo_blue_bright"
+        android:textSize="64dip"
+        android:textStyle="bold" />
+
+</RelativeLayout>
\ No newline at end of file
diff --git a/samples/devbytes/animation/ToonGame/res/layout/player_setup_layout.xml b/samples/devbytes/animation/ToonGame/res/layout/player_setup_layout.xml
new file mode 100644
index 0000000..c55d39b
--- /dev/null
+++ b/samples/devbytes/animation/ToonGame/res/layout/player_setup_layout.xml
@@ -0,0 +1,187 @@
+<!-- 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.
+-->
+<?xml version="1.0" encoding="utf-8"?>
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent" >
+
+    <RelativeLayout 
+        android:id="@+id/container"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:clipChildren="false">
+    
+        <view
+            android:id="@+id/nameTV"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_alignParentTop="true"
+            android:layout_centerHorizontal="true"
+            android:layout_marginTop="120dp"
+            class="com.example.android.toongame.SkewableTextView"
+            android:text="Name?"
+            android:textAppearance="?android:attr/textAppearanceMedium"
+            android:textSize="@dimen/bigText" />
+    
+        <view
+            class="com.example.android.toongame.SkewableTextView"
+            android:id="@+id/ageTV"
+            android:visibility="gone"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_alignParentTop="true"
+            android:layout_centerHorizontal="true"
+            android:layout_marginTop="120dp"
+            android:text="Difficulty?"
+            android:textAppearance="?android:attr/textAppearanceLarge"
+            android:textSize="@dimen/bigText" />
+    
+        <view
+            class="com.example.android.toongame.SkewableTextView"
+            android:id="@+id/creditTV"
+            android:visibility="gone"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_alignParentTop="true"
+            android:layout_centerHorizontal="true"
+            android:layout_marginTop="120dp"
+            android:gravity="center"
+            android:text="Parent's Credit Card Number?"
+            android:textAppearance="?android:attr/textAppearanceMedium"
+            android:textSize="64sp" />
+
+        <LinearLayout
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_centerHorizontal="true"
+            android:layout_alignParentBottom="true"
+            android:visibility="gone"
+            android:id="@+id/nameButtons"
+            android:layout_marginBottom="132dp" >
+            
+            <Button
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_margin="10dip"
+                android:padding="15dip"
+                android:background="@drawable/green_oval"
+                android:text="Bob"
+                android:textSize="36sp"
+                android:textColor="#fff"
+                android:textStyle="bold"
+                android:onClick="selectName"
+                android:id="@+id/bobButton"/>
+
+            <Button
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_margin="10dip"
+                android:padding="15dip"
+                android:background="@drawable/blue_oval"
+                android:text="Jane"
+                android:textSize="36sp"
+                android:textColor="#fff"
+                android:textStyle="bold"
+                android:onClick="selectName"
+                android:id="@+id/janeButton"/>
+
+            <Button
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_margin="10dip"
+                android:padding="15dip"
+                android:background="@drawable/magenta_oval"
+                android:text="Pat"
+                android:textSize="36sp"
+                android:textColor="#fff"
+                android:textStyle="bold"
+                 android:onClick="selectName"
+                android:id="@+id/patButton"/>
+
+        </LinearLayout>
+
+        <LinearLayout
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_centerHorizontal="true"
+            android:layout_alignParentBottom="true"
+            android:visibility="gone"
+            android:gravity="center"
+            android:orientation="vertical"
+            android:id="@+id/difficultyButtons"
+            android:layout_marginBottom="50dp" >
+            
+            <Button
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_margin="10dip"
+                android:padding="15dip"
+                android:background="@drawable/green_oval"
+                android:text="Easy"
+                android:textSize="36sp"
+                android:textColor="#fff"
+                android:textStyle="bold"
+                android:onClick="selectDifficulty"
+                android:id="@+id/easyButton"/>
+
+            <Button
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_margin="10dip"
+                android:padding="15dip"
+                android:background="@drawable/blue_oval"
+                android:text="Hard"
+                android:textSize="36sp"
+                android:textColor="#fff"
+                android:textStyle="bold"
+                android:onClick="selectDifficulty"
+                android:id="@+id/hardButton"/>
+
+            <Button
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_margin="10dip"
+                android:padding="15dip"
+                android:background="@drawable/red_oval"
+                android:text="Mega Hard"
+                android:textSize="36sp"
+                android:textColor="#000"
+                android:textStyle="bold|italic"
+                android:onClick="selectDifficulty"
+                android:id="@+id/megaHardButton"/>
+
+        </LinearLayout>
+        
+        <LinearLayout
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_centerHorizontal="true"
+            android:layout_alignParentBottom="true"
+            android:visibility="gone"
+            android:id="@+id/creditButtons1"
+            android:layout_marginBottom="132dp" />
+        
+        <LinearLayout
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_centerHorizontal="true"
+            android:layout_alignParentBottom="true"
+            android:visibility="gone"
+            android:id="@+id/creditButtons2"
+            android:layout_marginBottom="70dp" />
+        
+        
+    </RelativeLayout>
+</FrameLayout>
\ No newline at end of file
diff --git a/samples/devbytes/animation/ToonGame/res/values/dimens.xml b/samples/devbytes/animation/ToonGame/res/values/dimens.xml
new file mode 100644
index 0000000..fc229f6
--- /dev/null
+++ b/samples/devbytes/animation/ToonGame/res/values/dimens.xml
@@ -0,0 +1,22 @@
+<!-- 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.
+-->
+<resources>
+
+    <!-- Default screen margins, per the Android Design guidelines. -->
+    <dimen name="activity_horizontal_margin">16dp</dimen>
+    <dimen name="activity_vertical_margin">16dp</dimen>
+    <dimen name="bigText">64dip</dimen>
+
+</resources>
\ No newline at end of file
diff --git a/samples/devbytes/animation/ToonGame/res/values/strings.xml b/samples/devbytes/animation/ToonGame/res/values/strings.xml
new file mode 100644
index 0000000..fb256e6
--- /dev/null
+++ b/samples/devbytes/animation/ToonGame/res/values/strings.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<resources>
+
+    <string name="app_name">ToonGame</string>
+    <string name="action_settings">Settings</string>
+    <string name="hello_world">Hello world!</string>
+    <string name="welcome">Welcome!</string>
+
+</resources>
\ No newline at end of file
diff --git a/samples/devbytes/animation/ToonGame/res/values/styles.xml b/samples/devbytes/animation/ToonGame/res/values/styles.xml
new file mode 100644
index 0000000..9d91d6a
--- /dev/null
+++ b/samples/devbytes/animation/ToonGame/res/values/styles.xml
@@ -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.
+-->
+<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">
+        <item name="android:windowNoTitle">true</item>
+    </style>
+
+</resources>
\ No newline at end of file
diff --git a/samples/devbytes/animation/ToonGame/src/com/example/android/toongame/PlayerSetupActivity.java b/samples/devbytes/animation/ToonGame/src/com/example/android/toongame/PlayerSetupActivity.java
new file mode 100644
index 0000000..fce11c3
--- /dev/null
+++ b/samples/devbytes/animation/ToonGame/src/com/example/android/toongame/PlayerSetupActivity.java
@@ -0,0 +1,360 @@
+/*
+ * 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.example.android.toongame;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.animation.PropertyValuesHolder;
+import android.animation.TimeInterpolator;
+import android.animation.ValueAnimator;
+import android.app.Activity;
+import android.content.res.ColorStateList;
+import android.graphics.Color;
+import android.graphics.Typeface;
+import android.graphics.drawable.ShapeDrawable;
+import android.graphics.drawable.shapes.OvalShape;
+import android.os.Bundle;
+import android.util.TypedValue;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewTreeObserver;
+import android.view.animation.AccelerateInterpolator;
+import android.view.animation.DecelerateInterpolator;
+import android.view.animation.LinearInterpolator;
+import android.view.animation.OvershootInterpolator;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.RelativeLayout;
+
+/**
+ * This activity, launched from the ToonGame activity, takes the user between three
+ * different setup screens where they choose a name, choose a difficulty rating, and
+ * enter important financial information. All of the screens are meant to be
+ * simple, engaging, and fun.
+ */
+public class PlayerSetupActivity extends Activity {
+
+    private static final AccelerateInterpolator sAccelerator = new AccelerateInterpolator();
+    private static final LinearInterpolator sLinearInterpolator = new LinearInterpolator();
+    ViewGroup mContainer;
+    EditText mEditText;
+    
+    private static final int NAME_STATE = 0;
+    private static final int DIFFICULTY_STATE = 1;
+    private static final int CREDIT_STATE = 2;
+    private int mEntryState = NAME_STATE;
+
+    SkewableTextView mNameTV, mDifficultyTV, mCreditTV;
+    
+    ViewGroup mNameButtons, mDifficultyButtons, mCreditButtons1, mCreditButtons2;
+    
+    Button mBobButton, mJaneButton, mPatButton;
+    
+    private static final TimeInterpolator sOvershooter = new OvershootInterpolator();
+    private static final DecelerateInterpolator sDecelerator = new DecelerateInterpolator();
+    
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.player_setup_layout);
+        overridePendingTransition(0, 0);
+        
+        mContainer = (ViewGroup) findViewById(R.id.container);
+        mContainer.getViewTreeObserver().addOnPreDrawListener(mPreDrawListener);
+        
+        mNameTV = (SkewableTextView) findViewById(R.id.nameTV);
+        mDifficultyTV = (SkewableTextView) findViewById(R.id.ageTV);
+        mCreditTV = (SkewableTextView) findViewById(R.id.creditTV);
+        
+        mBobButton = setupButton(R.id.bobButton);
+        setupButton(R.id.janeButton);
+        setupButton(R.id.patButton);
+        setupButton(R.id.easyButton);
+        setupButton(R.id.hardButton);
+        setupButton(R.id.megaHardButton);
+        
+        mNameButtons = (ViewGroup) findViewById(R.id.nameButtons);
+        mDifficultyButtons = (ViewGroup) findViewById(R.id.difficultyButtons);
+        mCreditButtons1 = (ViewGroup) findViewById(R.id.creditButtons1);
+        mCreditButtons2 = (ViewGroup) findViewById(R.id.creditButtons2);
+    }
+    
+    @Override
+    public void finish() {
+        super.finish();
+        overridePendingTransition(0, 0);
+    }
+
+    private Button setupButton(int resourceId) {
+        Button button = (Button) findViewById(resourceId);
+        button.setOnTouchListener(mButtonPressListener);
+        return button;
+    }
+    
+    private View.OnTouchListener mButtonPressListener =
+            new View.OnTouchListener() {
+                public boolean onTouch(View v, MotionEvent event) {
+                    switch (event.getAction()) {
+                    case MotionEvent.ACTION_DOWN:
+                        v.animate().setDuration(ToonGame.SHORT_DURATION).
+                                scaleX(.8f).scaleY(.8f).setInterpolator(sDecelerator);
+                        break;
+                    case MotionEvent.ACTION_UP:
+                        v.animate().setDuration(ToonGame.SHORT_DURATION).
+                                scaleX(1).scaleY(1).setInterpolator(sAccelerator);
+                        break;
+                    default:
+                        break;
+                    }
+                    return false;
+                }
+            };
+
+    public void buttonClick(View clickedView, int alignmentRule) {
+        ViewGroup parent = (ViewGroup) clickedView.getParent();
+        for (int i = 0; i < parent.getChildCount(); ++i) {
+            Button child = (Button) parent.getChildAt(i);
+            if (child != clickedView) {
+                child.animate().alpha(0);
+            } else {
+                final Button buttonCopy = new Button(this);
+                child.setVisibility(View.INVISIBLE);
+                buttonCopy.setBackground(child.getBackground());
+                buttonCopy.setText(((Button) child).getText());
+                RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(
+                        RelativeLayout.LayoutParams.WRAP_CONTENT,
+                        RelativeLayout.LayoutParams.WRAP_CONTENT);
+                params.addRule(RelativeLayout.ALIGN_PARENT_TOP);
+                params.addRule(alignmentRule);
+                params.setMargins(25, 50, 25, 50);
+                buttonCopy.setLayoutParams(params);
+                buttonCopy.setPadding(child.getPaddingLeft(), child.getPaddingTop(),
+                        child.getPaddingRight(), child.getPaddingBottom());
+                buttonCopy.setTextSize(TypedValue.COMPLEX_UNIT_PX, child.getTextSize());
+                buttonCopy.setTypeface(child.getTypeface(), Typeface.BOLD);
+                ColorStateList colors = child.getTextColors();
+                buttonCopy.setTextColor(colors.getDefaultColor());
+                final int[] oldLocationInWindow = new int[2];
+                child.getLocationInWindow(oldLocationInWindow);
+                mContainer.addView(buttonCopy);
+                buttonCopy.getViewTreeObserver().addOnPreDrawListener(
+                        new ViewTreeObserver.OnPreDrawListener() {
+                    
+                    @Override
+                    public boolean onPreDraw() {
+                        buttonCopy.getViewTreeObserver().removeOnPreDrawListener(this);
+                        int[] locationInWindow = new int[2];
+                        buttonCopy.getLocationInWindow(locationInWindow);
+                        float deltaX = oldLocationInWindow[0] - locationInWindow[0];
+                        float deltaY = oldLocationInWindow[1] - locationInWindow[1];
+    
+                        buttonCopy.setTranslationX(deltaX);
+                        buttonCopy.setTranslationY(deltaY);
+                        
+                        PropertyValuesHolder pvhSX =
+                                PropertyValuesHolder.ofFloat(View.SCALE_X, 3);
+                        PropertyValuesHolder pvhSY =
+                                PropertyValuesHolder.ofFloat(View.SCALE_Y, 3);
+                        ObjectAnimator bounceAnim = ObjectAnimator.ofPropertyValuesHolder(
+                                buttonCopy, pvhSX, pvhSY);
+                        bounceAnim.setRepeatCount(1);
+                        bounceAnim.setRepeatMode(ValueAnimator.REVERSE);
+                        bounceAnim.setInterpolator(sDecelerator);
+                        bounceAnim.setDuration(300);
+                        
+                        PropertyValuesHolder pvhTX =
+                                PropertyValuesHolder.ofFloat(View.TRANSLATION_X, 0);
+                        PropertyValuesHolder pvhTY =
+                                PropertyValuesHolder.ofFloat(View.TRANSLATION_Y, 0);
+                        ObjectAnimator moveAnim = ObjectAnimator.ofPropertyValuesHolder(
+                                buttonCopy, pvhTX, pvhTY);
+                        moveAnim.setDuration(600);
+                        bounceAnim.start();
+                        moveAnim.start();
+                        moveAnim.addListener(new AnimatorListenerAdapter() {
+                            public void onAnimationEnd(Animator animation) {
+                                switch (mEntryState) {
+                                case (NAME_STATE) :
+                                {
+                                    Runnable runnable = new Runnable() {
+                                        public void run() {
+                                            mDifficultyButtons.setVisibility(View.VISIBLE);
+                                            mNameButtons.setVisibility(View.GONE);
+                                            popChildrenIn(mDifficultyButtons, null);
+                                        }
+                                    };
+                                    slideToNext(mNameTV, mDifficultyTV, runnable);
+                                    mEntryState = DIFFICULTY_STATE;
+                                    break;
+                                }
+                                case (DIFFICULTY_STATE) :
+                                {
+                                    mDifficultyButtons.setVisibility(View.GONE);
+                                    for (int i = 0; i < 5; ++i) {
+                                        mCreditButtons1.addView(setupNumberButton(i));
+                                    }
+                                    for (int i = 5; i < 10; ++i) {
+                                        mCreditButtons2.addView(setupNumberButton(i));
+                                    }
+                                    Runnable runnable = new Runnable() {
+                                        public void run() {
+                                            mCreditButtons1.setVisibility(View.VISIBLE);
+                                            Runnable runnable = new Runnable() {
+                                                public void run() {
+                                                    mCreditButtons2.setVisibility(View.VISIBLE);
+                                                    popChildrenIn(mCreditButtons2, null);
+                                                }
+                                            };
+                                            popChildrenIn(mCreditButtons1, runnable);
+                                        }
+                                    };
+                                    slideToNext(mDifficultyTV, mCreditTV, runnable);
+                                    mEntryState = CREDIT_STATE;
+                                }
+                                    break;
+                                }
+                            }
+                        });
+                        return true;
+                    }
+                });
+            }
+        }
+    }
+    
+    public void selectDifficulty(View clickedView) {
+        buttonClick(clickedView, RelativeLayout.ALIGN_PARENT_RIGHT);
+    }
+    
+    public void selectName(View clickedView) {
+        buttonClick(clickedView, RelativeLayout.ALIGN_PARENT_LEFT);
+    }
+    
+    private Button setupNumberButton(int number) {
+        Button button = new Button(PlayerSetupActivity.this);
+        button.setTextSize(15);
+        button.setTextColor(Color.WHITE);
+        button.setTypeface(mBobButton.getTypeface(), Typeface.BOLD);
+        button.setText(Integer.toString(number));
+        button.setPadding(0, 0, 0, 0);
+        
+        OvalShape oval = new OvalShape();
+        ShapeDrawable drawable = new ShapeDrawable(oval);
+        drawable.getPaint().setColor(0xFF << 24 | (int) (50 + 150 * Math.random()) << 16 |
+                (int) (50 + 150 * Math.random()) << 8 |  (int) (50 + 150 * Math.random()));
+        button.setBackground(drawable);
+
+        button.setOnTouchListener(mButtonPressListener);
+
+        return button;
+    }
+
+    ViewTreeObserver.OnPreDrawListener mPreDrawListener =
+            new ViewTreeObserver.OnPreDrawListener() {
+        
+        @Override
+        public boolean onPreDraw() {
+            mContainer.getViewTreeObserver().removeOnPreDrawListener(this);
+            mContainer.setScaleX(0);
+            mContainer.setScaleY(0);
+            mContainer.animate().scaleX(1).scaleY(1).setInterpolator(new OvershootInterpolator());
+            mContainer.animate().setDuration(ToonGame.LONG_DURATION).withEndAction(new Runnable() {
+                
+                @Override
+                public void run() {
+                    ViewGroup buttonsParent = (ViewGroup) findViewById(R.id.nameButtons);
+                    buttonsParent.setVisibility(View.VISIBLE);
+                    popChildrenIn(buttonsParent, null);
+                }
+            });
+            return false;
+        }
+    };
+    
+    private void popChildrenIn(ViewGroup parent, final Runnable endAction) {
+        // for all children, scale in one at a time
+        TimeInterpolator overshooter = new OvershootInterpolator();
+        int childCount = parent.getChildCount();
+        ObjectAnimator[] childAnims = new ObjectAnimator[childCount];
+        for (int i = 0; i < childCount; ++i) {
+            View child = parent.getChildAt(i);
+            child.setScaleX(0);
+            child.setScaleY(0);
+            PropertyValuesHolder pvhSX = PropertyValuesHolder.ofFloat(View.SCALE_X, 1);
+            PropertyValuesHolder pvhSY = PropertyValuesHolder.ofFloat(View.SCALE_Y, 1);
+            ObjectAnimator anim = ObjectAnimator.ofPropertyValuesHolder(child, pvhSX, pvhSY);
+            anim.setDuration(150);
+            anim.setInterpolator(overshooter);
+            childAnims[i] = anim;
+        }
+        AnimatorSet set = new AnimatorSet();
+        set.playSequentially(childAnims);
+        set.start();
+        if (endAction != null) {
+            set.addListener(new AnimatorListenerAdapter() {
+                public void onAnimationEnd(Animator animation) {
+                    endAction.run();
+                }
+            });
+        }
+    }
+    
+    private void slideToNext(final SkewableTextView currentView,
+            final SkewableTextView nextView, final Runnable endAction) {
+        // skew/anticipate current view, slide off, set GONE, restore translation
+        ObjectAnimator currentSkewer = ObjectAnimator.ofFloat(currentView, "skewX", -.5f);
+        currentSkewer.setInterpolator(sDecelerator);
+        ObjectAnimator currentMover = ObjectAnimator.ofFloat(currentView, View.TRANSLATION_X,
+                -mContainer.getWidth());
+        currentMover.setInterpolator(sLinearInterpolator);
+        currentMover.setDuration(ToonGame.MEDIUM_DURATION);
+        
+        // set next view visible, translate off to right, skew,
+        // slide on in parallel, overshoot/wobble, unskew
+        nextView.setVisibility(View.VISIBLE);
+        nextView.setSkewX(-.5f);
+        nextView.setTranslationX(mContainer.getWidth());
+        
+        ObjectAnimator nextMover = ObjectAnimator.ofFloat(nextView, View.TRANSLATION_X, 0);
+        nextMover.setInterpolator(sAccelerator);
+        nextMover.setDuration(ToonGame.MEDIUM_DURATION);
+        ObjectAnimator nextSkewer = ObjectAnimator.ofFloat(nextView, "skewX", 0);
+        nextSkewer.setInterpolator(sOvershooter);
+        
+        AnimatorSet moverSet = new AnimatorSet();
+        moverSet.playTogether(currentMover, nextMover);
+        AnimatorSet fullSet = new AnimatorSet();
+        fullSet.playSequentially(currentSkewer, moverSet, nextSkewer);
+        fullSet.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                currentView.setSkewX(0);
+                currentView.setVisibility(View.GONE);
+                currentView.setTranslationX(0);
+                if (endAction != null) {
+                    endAction.run();
+                }
+            }
+        });
+        
+        fullSet.start();
+    }
+
+}
diff --git a/samples/devbytes/animation/ToonGame/src/com/example/android/toongame/SkewableTextView.java b/samples/devbytes/animation/ToonGame/src/com/example/android/toongame/SkewableTextView.java
new file mode 100644
index 0000000..9ea15ca
--- /dev/null
+++ b/samples/devbytes/animation/ToonGame/src/com/example/android/toongame/SkewableTextView.java
@@ -0,0 +1,84 @@
+/*
+ * 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.example.android.toongame;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Matrix;
+import android.graphics.RectF;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.TextView;
+
+/**
+ * This custom TextView can be skewed to the left or right to enable anticipation and
+ * follow-through effects
+ */
+public class SkewableTextView extends TextView {
+
+    private float mSkewX;
+    RectF mTempRect = new RectF();
+    
+    public SkewableTextView(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+    }
+
+    public SkewableTextView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public SkewableTextView(Context context) {
+        super(context);
+    }
+
+    @Override
+    protected void onDraw(Canvas canvas) {
+        if (mSkewX != 0) {
+            canvas.translate(0, getHeight());
+            canvas.skew(mSkewX, 0);
+            canvas.translate(0,  -getHeight());
+        }
+        super.onDraw(canvas);
+    }
+
+    public float getSkewX() {
+        return mSkewX;
+    }
+    
+    public void setSkewX(float value) {
+        if (value != mSkewX) {
+            mSkewX = value;
+            invalidate();             // force redraw with new skew value
+            invalidateSkewedBounds(); // also invalidate appropriate area of parent
+        }
+    }
+    
+    /**
+     * Need to invalidate proper area of parent for skewed bounds
+     */
+    private void invalidateSkewedBounds() {
+        if (mSkewX != 0) {
+            Matrix matrix = new Matrix();
+            matrix.setSkew(-mSkewX, 0);
+            mTempRect.set(0, 0, getRight(), getBottom());
+            matrix.mapRect(mTempRect);
+            mTempRect.offset(getLeft() + getTranslationX(), getTop() + getTranslationY());
+            ((View) getParent()).invalidate((int) mTempRect.left, (int) mTempRect.top,
+                    (int) (mTempRect.right +.5f), (int) (mTempRect.bottom + .5f));
+        }
+    }
+}
diff --git a/samples/devbytes/animation/ToonGame/src/com/example/android/toongame/ToonGame.java b/samples/devbytes/animation/ToonGame/src/com/example/android/toongame/ToonGame.java
new file mode 100644
index 0000000..b03eeeb
--- /dev/null
+++ b/samples/devbytes/animation/ToonGame/src/com/example/android/toongame/ToonGame.java
@@ -0,0 +1,219 @@
+/*
+ * 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.example.android.toongame;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.animation.PropertyValuesHolder;
+import android.animation.ValueAnimator;
+import android.app.Activity;
+import android.content.Intent;
+import android.graphics.Color;
+import android.os.Bundle;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.View.OnTouchListener;
+import android.view.ViewGroup;
+import android.view.ViewTreeObserver;
+import android.view.animation.AccelerateInterpolator;
+import android.view.animation.DecelerateInterpolator;
+import android.view.animation.LinearInterpolator;
+import android.widget.Button;
+
+/**
+ * This application shows various cartoon animation techniques in the context of
+ * a larger application, to show how such animations might be used to create a more
+ * interactive, fun, and engaging experience.
+ *
+ * This main activity launches a sub-activity when the Play button is clicked. The
+ * main action in this master activity is bouncing the Play button in, randomly
+ * bouncing it while waiting for input, and animating its press and click behaviors
+ * when the user interacts with it. 
+ *
+ * Watch the associated video for this demo on the DevBytes channel of developer.android.com
+ * or on the DevBytes playlist in the androiddevelopers channel on YouTube at
+ * https://www.youtube.com/playlist?list=PLWz5rJ2EKKc_XOgcRukSoKKjewFJZrKV0.
+ */
+public class ToonGame extends Activity {
+
+    Button mStarter;
+    ViewGroup mContainer;
+    private static final AccelerateInterpolator sAccelerator = new AccelerateInterpolator();
+    private static final DecelerateInterpolator sDecelerator = new DecelerateInterpolator();
+    private static final LinearInterpolator sLinearInterpolator = new LinearInterpolator();
+    static long SHORT_DURATION = 100;
+    static long MEDIUM_DURATION = 200;
+    static long REGULAR_DURATION = 300;
+    static long LONG_DURATION = 500;
+    
+    private static float sDurationScale = 1f;
+    
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        overridePendingTransition(0, 0);
+        setContentView(R.layout.activity_toon_game);
+        
+        mStarter = (Button) findViewById(R.id.startButton);
+        mContainer = (ViewGroup) findViewById(R.id.container);
+        mStarter.setOnTouchListener(funButtonListener);
+        mStarter.animate().setDuration(100);
+        
+    }
+    
+    @Override
+    protected void onResume() {
+        super.onResume();
+        mContainer.setScaleX(1);
+        mContainer.setScaleY(1);
+        mContainer.setAlpha(1);
+        mStarter.setVisibility(View.INVISIBLE);
+        mContainer.getViewTreeObserver().addOnPreDrawListener(mOnPreDrawListener);
+    }
+
+    @Override
+    protected void onPause() {
+        super.onPause();
+        mStarter.removeCallbacks(mSquishRunnable);
+    }
+
+    private OnTouchListener funButtonListener = new OnTouchListener() {
+        
+        @Override
+        public boolean onTouch(View v, MotionEvent event) {
+            switch (event.getAction()) {
+            case MotionEvent.ACTION_DOWN:
+                mStarter.animate().scaleX(.8f).scaleY(.8f).setInterpolator(sDecelerator);
+                mStarter.setTextColor(Color.CYAN);
+                mStarter.removeCallbacks(mSquishRunnable);
+                mStarter.setPressed(true);
+                break;
+            case MotionEvent.ACTION_MOVE:
+                float x = event.getX();
+                float y = event.getY();
+                boolean isInside = (x > 0 && x < mStarter.getWidth() &&
+                        y > 0 && y < mStarter.getHeight());
+                if (mStarter.isPressed() != isInside) {
+                    mStarter.setPressed(isInside);
+                }
+                break;
+            case MotionEvent.ACTION_UP:
+                if (mStarter.isPressed()) {
+                    mStarter.performClick();
+                    mStarter.setPressed(false);
+                } else {
+                    mStarter.animate().scaleX(1).scaleY(1).setInterpolator(sAccelerator);
+                }
+                mStarter.setTextColor(Color.BLUE);
+                break;
+            }
+            return true;
+        }
+    };
+
+    private Runnable mSquishRunnable = new Runnable() {
+        public void run() {
+            squishyBounce(mStarter, 0,
+                    mContainer.getHeight() - mStarter.getTop() - mStarter.getHeight(),
+                    0, .5f, 1.5f);
+        }
+    };
+    
+    public void play(View view) {
+        mContainer.animate().scaleX(5).scaleY(5).alpha(0).setDuration(LONG_DURATION).
+                setInterpolator(sLinearInterpolator).
+                withEndAction(new Runnable() {
+            @Override
+            public void run() {
+                mStarter.postOnAnimation(new Runnable() {
+                    public void run() {
+                        Intent intent = new Intent(ToonGame.this,
+                                PlayerSetupActivity.class);
+                        startActivity(intent);
+                        overridePendingTransition(0, 0);
+                    }
+                });
+            }
+        });
+        view.removeCallbacks(mSquishRunnable);
+    }
+    
+    private ViewTreeObserver.OnPreDrawListener mOnPreDrawListener =
+            new ViewTreeObserver.OnPreDrawListener() {
+                
+                @Override
+                public boolean onPreDraw() {
+                    mContainer.getViewTreeObserver().removeOnPreDrawListener(this);
+                    mContainer.postDelayed(new Runnable() {
+                        public void run() {
+                            // Drop in the button from off the top of the screen
+                            mStarter.setVisibility(View.VISIBLE);
+                            mStarter.setY(-mStarter.getHeight());
+                            squishyBounce(mStarter, 
+                                    -(mStarter.getTop() + mStarter.getHeight()),
+                                    mContainer.getHeight() - mStarter.getTop() -
+                                            mStarter.getHeight(),
+                                    0, .5f, 1.5f);
+                        }
+                    }, 500);
+                    return true;
+                }
+            };
+
+    private void squishyBounce(final View view, final float startTY, final float bottomTY,
+            final float endTY, final float squash, final float stretch) {
+        view.setPivotX(view.getWidth() / 2);
+        view.setPivotY(view.getHeight());
+        PropertyValuesHolder pvhTY = PropertyValuesHolder.ofFloat(View.TRANSLATION_Y,
+                startTY, bottomTY);
+        PropertyValuesHolder pvhSX = PropertyValuesHolder.ofFloat(View.SCALE_X, .7f);
+        PropertyValuesHolder pvhSY = PropertyValuesHolder.ofFloat(View.SCALE_Y, 1.2f);
+        ObjectAnimator downAnim = ObjectAnimator.ofPropertyValuesHolder(view, pvhTY, pvhSX, pvhSY);
+        downAnim.setInterpolator(sAccelerator);
+
+        pvhTY = PropertyValuesHolder.ofFloat(View.TRANSLATION_Y, bottomTY, endTY);
+        pvhSX = PropertyValuesHolder.ofFloat(View.SCALE_X, 1);
+        pvhSY = PropertyValuesHolder.ofFloat(View.SCALE_Y, 1);
+        ObjectAnimator upAnim = ObjectAnimator.ofPropertyValuesHolder(view, pvhTY, pvhSX, pvhSY);
+        upAnim.setInterpolator(sDecelerator);
+        
+        pvhSX = PropertyValuesHolder.ofFloat(View.SCALE_X, stretch);
+        pvhSY = PropertyValuesHolder.ofFloat(View.SCALE_Y, squash);
+        ObjectAnimator stretchAnim = ObjectAnimator.ofPropertyValuesHolder(view, pvhSX, pvhSY);
+        stretchAnim.setRepeatCount(1);
+        stretchAnim.setRepeatMode(ValueAnimator.REVERSE);
+        stretchAnim.setInterpolator(sDecelerator);
+        
+        AnimatorSet set = new AnimatorSet();
+        set.playSequentially(downAnim, stretchAnim, upAnim);
+        set.setDuration(getDuration(SHORT_DURATION));
+        set.start();
+        set.addListener(new AnimatorListenerAdapter() {
+            public void onAnimationEnd(Animator animation) {
+                view.postDelayed(mSquishRunnable, (long) (500 + Math.random() * 2000));
+            }
+        });
+    }
+    
+    public static long getDuration(long baseDuration) {
+        return (long) (baseDuration * sDurationScale);
+    }
+    
+
+}