am 80bc4f93: Merge "Refresh 64-bit headers/libs (WW20)"

* commit '80bc4f931edb0c56473ba89a132e56ac99995420':
  Refresh 64-bit headers/libs (WW20)
diff --git a/build/sdk.atree b/build/sdk.atree
index fbf121c..f4d1004 100644
--- a/build/sdk.atree
+++ b/build/sdk.atree
@@ -83,25 +83,27 @@
 external/clang/LICENSE.TXT                    build-tools/${PLATFORM_NAME}/renderscript/clang-include/LICENSE.TXT
 
 prebuilts/sdk/renderscript/lib/javalib.jar            build-tools/${PLATFORM_NAME}/renderscript/lib/renderscript-v8.jar
-prebuilts/sdk/renderscript/lib/arm/libclcore.bc       build-tools/${PLATFORM_NAME}/renderscript/lib/libclcore.bc
 
 prebuilts/sdk/renderscript/lib/arm/libc.so            build-tools/${PLATFORM_NAME}/renderscript/lib/intermediates/armeabi-v7a/libc.so
 prebuilts/sdk/renderscript/lib/arm/libm.so            build-tools/${PLATFORM_NAME}/renderscript/lib/intermediates/armeabi-v7a/libm.so
 prebuilts/sdk/renderscript/lib/arm/libcompiler_rt.a   build-tools/${PLATFORM_NAME}/renderscript/lib/intermediates/armeabi-v7a/libcompiler_rt.a
 prebuilts/sdk/renderscript/lib/arm/libRSSupport.so    build-tools/${PLATFORM_NAME}/renderscript/lib/packaged/armeabi-v7a/libRSSupport.so
 prebuilts/sdk/renderscript/lib/arm/librsjni.so        build-tools/${PLATFORM_NAME}/renderscript/lib/packaged/armeabi-v7a/librsjni.so
+prebuilts/sdk/renderscript/lib/arm/libclcore.bc       build-tools/${PLATFORM_NAME}/renderscript/lib/bc/armeabi-v7a/libclcore.bc
 
 prebuilts/sdk/renderscript/lib/mips/libc.so            build-tools/${PLATFORM_NAME}/renderscript/lib/intermediates/mips/libc.so
 prebuilts/sdk/renderscript/lib/mips/libm.so            build-tools/${PLATFORM_NAME}/renderscript/lib/intermediates/mips/libm.so
 prebuilts/sdk/renderscript/lib/mips/libcompiler_rt.a   build-tools/${PLATFORM_NAME}/renderscript/lib/intermediates/mips/libcompiler_rt.a
 prebuilts/sdk/renderscript/lib/mips/libRSSupport.so    build-tools/${PLATFORM_NAME}/renderscript/lib/packaged/mips/libRSSupport.so
 prebuilts/sdk/renderscript/lib/mips/librsjni.so        build-tools/${PLATFORM_NAME}/renderscript/lib/packaged/mips/librsjni.so
+prebuilts/sdk/renderscript/lib/mips/libclcore.bc       build-tools/${PLATFORM_NAME}/renderscript/lib/bc/mips/libclcore.bc
 
 prebuilts/sdk/renderscript/lib/x86/libc.so            build-tools/${PLATFORM_NAME}/renderscript/lib/intermediates/x86/libc.so
 prebuilts/sdk/renderscript/lib/x86/libm.so            build-tools/${PLATFORM_NAME}/renderscript/lib/intermediates/x86/libm.so
 prebuilts/sdk/renderscript/lib/x86/libcompiler_rt.a   build-tools/${PLATFORM_NAME}/renderscript/lib/intermediates/x86/libcompiler_rt.a
 prebuilts/sdk/renderscript/lib/x86/libRSSupport.so    build-tools/${PLATFORM_NAME}/renderscript/lib/packaged/x86/libRSSupport.so
 prebuilts/sdk/renderscript/lib/x86/librsjni.so        build-tools/${PLATFORM_NAME}/renderscript/lib/packaged/x86/librsjni.so
+prebuilts/sdk/renderscript/lib/x86/libclcore.bc       build-tools/${PLATFORM_NAME}/renderscript/lib/bc/x86/libclcore.bc
 
 
 
@@ -168,6 +170,7 @@
 
 # fonts for layoutlib.
 frameworks/base/data/fonts    platforms/${PLATFORM_NAME}/data/fonts
+external/noto-fonts           platforms/${PLATFORM_NAME}/data/fonts
 
 # NOTICE files are copied by build/core/Makefile from sdk.git
 sdk/files/sdk_files_NOTICE.txt platforms/${PLATFORM_NAME}/templates/NOTICE.txt
@@ -218,14 +221,51 @@
 # Note: Some samples reference a shared "common" directory. In the future
 # this will be copied in automatically via a templating system. For now,
 # we need to copy it in here as needed.
-developers/samples/android/connectivity        samples/${PLATFORM_NAME}/connectivity
-developers/samples/android/common              samples/${PLATFORM_NAME}/connectivity/sync/BasicSyncAdapter/BasicSyncAdapter/src/main/java/com/example/android/common
-developers/samples/android/content             samples/${PLATFORM_NAME}/content
-developers/samples/android/input               samples/${PLATFORM_NAME}/input
-developers/samples/android/media               samples/${PLATFORM_NAME}/media
-developers/samples/android/security            samples/${PLATFORM_NAME}/security
-developers/samples/android/testing             samples/${PLATFORM_NAME}/testing
-developers/samples/android/ui                  samples/${PLATFORM_NAME}/ui
+developers/build/prebuilts/gradle/BasicAndroidKeyStore/                      samples/${PLATFORM_NAME}/security/BasicAndroidKeyStore
+developers/build/prebuilts/gradle/BasicSyncAdapter/                          samples/${PLATFORM_NAME}/connectivity/BasicSyncAdapter
+developers/build/prebuilts/gradle/NetworkConnect/                            samples/${PLATFORM_NAME}/connectivity/NetworkConnect
+developers/build/prebuilts/gradle/BasicNetworking/                           samples/${PLATFORM_NAME}/connectivity/BasicNetworking
+developers/build/prebuilts/gradle/BluetoothLeGatt/                           samples/${PLATFORM_NAME}/connectivity/BluetoothLeGatt
+developers/build/prebuilts/gradle/AppRestrictions/                           samples/${PLATFORM_NAME}/content/AppRestrictions
+developers/build/prebuilts/gradle/BasicContactables/                         samples/${PLATFORM_NAME}/content/BasicContactables
+developers/build/prebuilts/gradle/StorageClient/                             samples/${PLATFORM_NAME}/content/StorageClient
+developers/build/prebuilts/gradle/StorageProvider/                           samples/${PLATFORM_NAME}/content/StorageProvider
+developers/build/prebuilts/gradle/BasicGestureDetect/                        samples/${PLATFORM_NAME}/input/BasicGestureDetect
+developers/build/prebuilts/gradle/BasicMultitouch/                           samples/${PLATFORM_NAME}/input/BasicMultitouch
+developers/build/prebuilts/gradle/ActivityInstrumentation/                   samples/${PLATFORM_NAME}/testing/ActivityInstrumentation
+developers/build/prebuilts/gradle/MediaRecorder/                             samples/${PLATFORM_NAME}/media/MediaRecorder
+developers/build/prebuilts/gradle/BasicMediaRouter/                          samples/${PLATFORM_NAME}/media/BasicMediaRouter
+developers/build/prebuilts/gradle/BasicMediaDecoder/                         samples/${PLATFORM_NAME}/media/BasicMediaDecoder
+developers/build/prebuilts/gradle/BorderlessButtons/                         samples/${PLATFORM_NAME}/ui/BorderlessButtons
+developers/build/prebuilts/gradle/BasicAccessibility/                        samples/${PLATFORM_NAME}/ui/BasicAccessibility
+developers/build/prebuilts/gradle/CustomChoiceList/                          samples/${PLATFORM_NAME}/ui/CustomChoiceList
+developers/build/prebuilts/gradle/TextSwitcher/                              samples/${PLATFORM_NAME}/ui/TextSwitcher
+developers/build/prebuilts/gradle/HorizontalPaging/                          samples/${PLATFORM_NAME}/ui/HorizontalPaging
+developers/build/prebuilts/gradle/ActionBarCompat-Styled/                    samples/${PLATFORM_NAME}/ui/ActionBarCompat-Styled
+developers/build/prebuilts/gradle/ActionBarCompat-ListPopupMenu/             samples/${PLATFORM_NAME}/ui/ActionBarCompat-ListPopupMenu
+developers/build/prebuilts/gradle/ActionBarCompat-ShareActionProvider/       samples/${PLATFORM_NAME}/ui/ActionBarCompat-ShareActionProvider
+developers/build/prebuilts/gradle/ActionBarCompat-Basic/                     samples/${PLATFORM_NAME}/ui/ActionBarCompat-Basic
+developers/build/prebuilts/gradle/BasicNotifications/                        samples/${PLATFORM_NAME}/ui/BasicNotifications
+developers/build/prebuilts/gradle/CustomNotifications/                       samples/${PLATFORM_NAME}/ui/CustomNotifications
+developers/build/prebuilts/gradle/DoneBar/                                   samples/${PLATFORM_NAME}/ui/DoneBar
+developers/build/prebuilts/gradle/BasicImmersiveMode/                        samples/${PLATFORM_NAME}/ui/BasicImmersiveMode
+developers/build/prebuilts/gradle/AdvancedImmersiveMode/                     samples/${PLATFORM_NAME}/ui/AdvancedImmersiveMode
+developers/build/prebuilts/gradle/ImmersiveMode/                             samples/${PLATFORM_NAME}/ui/ImmersiveMode
+developers/build/prebuilts/gradle/RepeatingAlarm/                            samples/${PLATFORM_NAME}/background/RepeatingAlarm
+developers/build/prebuilts/gradle/TextLinkify/                               samples/${PLATFORM_NAME}/ui/TextLinkify
+developers/build/prebuilts/gradle/BasicRenderScript                          samples/${PLATFORM_NAME}/renderscript/BasicRenderScript
+developers/build/prebuilts/gradle/RenderScriptIntrinsic                      samples/${PLATFORM_NAME}/renderscript/RenderScriptIntrinsic
+developers/build/prebuilts/gradle/SlidingTabsBasic                           samples/${PLATFORM_NAME}/ui/SlidingTabsBasic
+developers/build/prebuilts/gradle/SlidingTabsColors                          samples/${PLATFORM_NAME}/ui/SlidingTabsColors
+developers/build/prebuilts/gradle/CardEmulation                              samples/${PLATFORM_NAME}/connectivity/CardEmulation
+developers/build/prebuilts/gradle/CardReader                                 samples/${PLATFORM_NAME}/connectivity/CardReader
+developers/build/prebuilts/gradle/BatchStepSensor                            samples/${PLATFORM_NAME}/sensors/BatchStepSensor
+developers/build/prebuilts/gradle/DisplayingBitmaps                          samples/${PLATFORM_NAME}/ui/DisplayingBitmaps
+developers/build/prebuilts/gradle/BasicTransition                            samples/${PLATFORM_NAME}/ui/BasicTransition
+developers/build/prebuilts/gradle/AdapterTransition                          samples/${PLATFORM_NAME}/ui/AdapterTransition
+developers/build/prebuilts/gradle/MediaRouter                                samples/${PLATFORM_NAME}/media/MediaRouter
+
+
 
 # Old sample tree
 development/samples/AccelerometerPlay          samples/${PLATFORM_NAME}/legacy/AccelerometerPlay
@@ -339,5 +379,6 @@
 # Tests Component
 ##############################################################################
 framework/layoutlib-tests.jar tests/libtests/layoutlib-tests.jar
-system/app/EmulatorSmokeTests.apk tests/emulator-test-apps/EmulatorSmokeTests.apk
+system/app/ConnectivityTest.apk tests/emulator-test-apps/ConnectivityTest.apk
+system/app/GpsLocationTest.apk tests/emulator-test-apps/GpsLocationTest.apk
 
diff --git a/samples/ApiDemos/AndroidManifest.xml b/samples/ApiDemos/AndroidManifest.xml
index d7bda31..f202d59 100644
--- a/samples/ApiDemos/AndroidManifest.xml
+++ b/samples/ApiDemos/AndroidManifest.xml
@@ -2469,6 +2469,16 @@
             </intent-filter>
         </activity>
 
+        <activity android:name=".view.GameActivity"
+                android:label="Views/System UI Visibility/Game"
+                android:theme="@android:style/Theme.Holo.NoActionBar"
+                android:enabled="@bool/atLeastKitKat">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.SAMPLE_CODE" />
+            </intent-filter>
+        </activity>
+
         <activity android:name=".view.Switches" android:label="Views/Switches">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
diff --git a/samples/ApiDemos/res/layout/game.xml b/samples/ApiDemos/res/layout/game.xml
new file mode 100644
index 0000000..809a253
--- /dev/null
+++ b/samples/ApiDemos/res/layout/game.xml
@@ -0,0 +1,48 @@
+<?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.
+-->
+
+<!-- BEGIN_INCLUDE(complete) -->
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent" android:layout_height="match_parent"
+    >
+    <!-- This is the outer area of the entire game screen, extending out under
+         system UI elements. -->
+    <view class="com.example.android.apis.view.GameActivity$Content"
+        android:id="@+id/content"
+        android:src="@drawable/frantic"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:scaleType="center"
+        />
+    <!-- This is the inner area of the game, not covered by system UI elements.
+        Any UI elements that need to be accessible when the game is paused or other
+        states where the system UI is shown (such as in menus) should go here. -->
+    <FrameLayout
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:fitsSystemWindows="true"
+        android:animateLayoutChanges="true"
+        >
+        <Button
+            android:id="@+id/play"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="top|right"
+            android:textSize="28dp"
+            />
+    </FrameLayout>
+</FrameLayout>
+<!-- END_INCLUDE(complete) -->
diff --git a/samples/ApiDemos/src/com/example/android/apis/app/LoaderCustom.java b/samples/ApiDemos/src/com/example/android/apis/app/LoaderCustom.java
index ffcf890..e21ca80 100644
--- a/samples/ApiDemos/src/com/example/android/apis/app/LoaderCustom.java
+++ b/samples/ApiDemos/src/com/example/android/apis/app/LoaderCustom.java
@@ -266,7 +266,7 @@
                     onReleaseResources(apps);
                 }
             }
-            List<AppEntry> oldApps = apps;
+            List<AppEntry> oldApps = mApps;
             mApps = apps;
 
             if (isStarted()) {
diff --git a/samples/ApiDemos/src/com/example/android/apis/graphics/TouchPaint.java b/samples/ApiDemos/src/com/example/android/apis/graphics/TouchPaint.java
index c3c8a6c..a863014 100644
--- a/samples/ApiDemos/src/com/example/android/apis/graphics/TouchPaint.java
+++ b/samples/ApiDemos/src/com/example/android/apis/graphics/TouchPaint.java
@@ -26,6 +26,7 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Message;
+import android.util.AttributeSet;
 import android.view.Menu;
 import android.view.MenuItem;
 import android.view.MotionEvent;
@@ -87,9 +88,6 @@
     /** Is fading mode enabled? */
     boolean mFading;
 
-    /** The index of the current color to use. */
-    int mColorIndex;
-
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
@@ -104,10 +102,10 @@
         // the contents of the bitmap.
         if (savedInstanceState != null) {
             mFading = savedInstanceState.getBoolean("fading", true);
-            mColorIndex = savedInstanceState.getInt("color", 0);
+            mView.mColorIndex = savedInstanceState.getInt("color", 0);
         } else {
             mFading = true;
-            mColorIndex = 0;
+            mView.mColorIndex = 0;
         }
     }
 
@@ -161,7 +159,7 @@
         // Save away the fading state to restore if needed later.  Note that
         // we do not currently save the contents of the display.
         outState.putBoolean("fading", mFading);
-        outState.putInt("color", mColorIndex);
+        outState.putInt("color", mView.mColorIndex);
     }
 
     @Override
@@ -225,9 +223,9 @@
      *
      * It handles all of the input events and drawing functions.
      */
-    class PaintView extends View {
+    public static class PaintView extends View {
         private static final int FADE_ALPHA = 0x06;
-        private static final int MAX_FADE_STEPS = 256 / FADE_ALPHA + 4;
+        private static final int MAX_FADE_STEPS = 256 / (FADE_ALPHA/2) + 4;
         private static final int TRACKBALL_SCALE = 10;
 
         private static final int SPLAT_VECTORS = 40;
@@ -235,21 +233,31 @@
         private final Random mRandom = new Random();
         private Bitmap mBitmap;
         private Canvas mCanvas;
-        private final Paint mPaint;
-        private final Paint mFadePaint;
+        private final Paint mPaint = new Paint();
+        private final Paint mFadePaint = new Paint();
         private float mCurX;
         private float mCurY;
         private int mOldButtonState;
         private int mFadeSteps = MAX_FADE_STEPS;
 
+        /** The index of the current color to use. */
+        int mColorIndex;
+
         public PaintView(Context c) {
             super(c);
+            init();
+        }
+
+        public PaintView(Context c, AttributeSet attrs) {
+            super(c, attrs);
+            init();
+        }
+
+        private void init() {
             setFocusable(true);
 
-            mPaint = new Paint();
             mPaint.setAntiAlias(true);
 
-            mFadePaint = new Paint();
             mFadePaint.setColor(BACKGROUND_COLOR);
             mFadePaint.setAlpha(FADE_ALPHA);
         }
@@ -273,6 +281,31 @@
             }
         }
 
+        public void text(String text) {
+            if (mBitmap != null) {
+                final int width = mBitmap.getWidth();
+                final int height = mBitmap.getHeight();
+                mPaint.setColor(COLORS[mColorIndex]);
+                mPaint.setAlpha(255);
+                int size = height;
+                mPaint.setTextSize(size);
+                Rect bounds = new Rect();
+                mPaint.getTextBounds(text, 0, text.length(), bounds);
+                int twidth = bounds.width();
+                twidth += (twidth/4);
+                if (twidth > width) {
+                    size = (size*width)/twidth;
+                    mPaint.setTextSize(size);
+                    mPaint.getTextBounds(text, 0, text.length(), bounds);
+                }
+                Paint.FontMetrics fm = mPaint.getFontMetrics();
+                mCanvas.drawText(text, (width-bounds.width())/2,
+                        ((height-size)/2) - fm.ascent, mPaint);
+                mFadeSteps = 0;
+                invalidate();
+            }
+        }
+
         @Override
         protected void onSizeChanged(int w, int h, int oldw, int oldh) {
             int curW = mBitmap != null ? mBitmap.getWidth() : 0;
diff --git a/samples/ApiDemos/src/com/example/android/apis/view/GameActivity.java b/samples/ApiDemos/src/com/example/android/apis/view/GameActivity.java
new file mode 100644
index 0000000..a025427
--- /dev/null
+++ b/samples/ApiDemos/src/com/example/android/apis/view/GameActivity.java
@@ -0,0 +1,189 @@
+/*
+ * Copyright (C) 2011 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.apis.view;
+
+import android.app.ActionBar;
+import android.app.ActionBar.Tab;
+import android.app.Activity;
+import android.app.FragmentTransaction;
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Handler;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.Window;
+import android.widget.Button;
+import android.widget.ImageView;
+import android.widget.SearchView;
+import android.widget.SeekBar;
+import android.widget.ShareActionProvider;
+import android.widget.TextView;
+import android.widget.Toast;
+import android.widget.SearchView.OnQueryTextListener;
+
+import com.example.android.apis.R;
+import com.example.android.apis.graphics.TouchPaint;
+
+/**
+ * This activity demonstrates how to use the system UI flags to
+ * implement an immersive game.
+ */
+public class GameActivity extends Activity {
+
+    /**
+     * Implementation of a view for the game, filling the entire screen.
+     */
+//BEGIN_INCLUDE(content)
+    public static class Content extends TouchPaint.PaintView implements
+            View.OnSystemUiVisibilityChangeListener, View.OnClickListener {
+        Activity mActivity;
+        Button mPlayButton;
+        boolean mPaused;
+        int mLastSystemUiVis;
+        boolean mUpdateSystemUi;
+
+        Runnable mFader = new Runnable() {
+            @Override public void run() {
+                fade();
+                if (mUpdateSystemUi) {
+                    updateNavVisibility();
+                }
+                if (!mPaused) {
+                    getHandler().postDelayed(mFader, 1000/30);
+                }
+            }
+        };
+
+        public Content(Context context, AttributeSet attrs) {
+            super(context, attrs);
+            setOnSystemUiVisibilityChangeListener(this);
+        }
+
+        public void init(Activity activity, Button playButton) {
+            // This called by the containing activity to supply the surrounding
+            // state of the game that it will interact with.
+            mActivity = activity;
+            mPlayButton = playButton;
+            mPlayButton.setOnClickListener(this);
+            setGamePaused(true);
+        }
+
+        @Override public void onSystemUiVisibilityChange(int visibility) {
+            // Detect when we go out of nav-hidden mode, to reset back to having
+            // it hidden; our game wants those elements to stay hidden as long
+            // as it is being played and stay shown when paused.
+            int diff = mLastSystemUiVis ^ visibility;
+            mLastSystemUiVis = visibility;
+            if (!mPaused && (diff&SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0
+                    && (visibility&SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0) {
+                // We are running and the system UI navigation has become
+                // shown...  we want it to remain hidden, so update our system
+                // UI state at the next game loop.
+                mUpdateSystemUi = true;
+            }
+        }
+
+        @Override protected void onWindowVisibilityChanged(int visibility) {
+            super.onWindowVisibilityChanged(visibility);
+
+            // When we become visible or invisible, play is paused.
+            setGamePaused(true);
+        }
+
+        @Override
+        public void onWindowFocusChanged(boolean hasWindowFocus) {
+            super.onWindowFocusChanged(hasWindowFocus);
+
+            // When we become visible or invisible, play is paused.
+            // Optional: pause game when window loses focus.  This will cause it to
+            // pause, for example, when the notification shade is pulled down.
+            if (!hasWindowFocus) {
+                //setGamePaused(true);
+            }
+        }
+
+        @Override public void onClick(View v) {
+            if (v == mPlayButton) {
+                // Clicking on the play/pause button toggles its state.
+                setGamePaused(!mPaused);
+            }
+        }
+
+        void setGamePaused(boolean paused) {
+            mPaused = paused;
+            mPlayButton.setText(paused ? R.string.play : R.string.pause);
+            setKeepScreenOn(!paused);
+            updateNavVisibility();
+            Handler h = getHandler();
+            if (h != null) {
+                getHandler().removeCallbacks(mFader);
+                if (!paused) {
+                    mFader.run();
+                    text("Draw!");
+                }
+            }
+        }
+
+        void updateNavVisibility() {
+            int newVis = SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
+                    | SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
+                    | SYSTEM_UI_FLAG_LAYOUT_STABLE;
+            if (!mPaused) {
+                newVis |= SYSTEM_UI_FLAG_LOW_PROFILE | SYSTEM_UI_FLAG_FULLSCREEN
+                        | SYSTEM_UI_FLAG_HIDE_NAVIGATION  | SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
+            }
+
+            // Set the new desired visibility.
+            setSystemUiVisibility(newVis);
+            mUpdateSystemUi = false;
+        }
+    }
+//END_INCLUDE(content)
+
+    Content mContent;
+
+    public GameActivity() {
+    }
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        setContentView(R.layout.game);
+        mContent = (Content)findViewById(R.id.content);
+        mContent.init(this, (Button)findViewById(R.id.play));
+    }
+
+    @Override
+    public void onAttachedToWindow() {
+        super.onAttachedToWindow();
+    }
+
+    @Override
+    protected void onPause() {
+        super.onPause();
+
+        // Pause game when its activity is paused.
+        mContent.setGamePaused(true);
+    }
+}
diff --git a/samples/ControllerSample/AndroidManifest.xml b/samples/ControllerSample/AndroidManifest.xml
new file mode 100644
index 0000000..49b67d7
--- /dev/null
+++ b/samples/ControllerSample/AndroidManifest.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.example.controllersample"
+    android:versionCode="1"
+    android:versionName="1.0" >
+
+    <uses-permission android:name="android.permission.VIBRATE" />
+
+    <uses-sdk
+        android:minSdkVersion="9"
+        android:targetSdkVersion="18" />
+
+    <application
+        android:allowBackup="true"
+        android:icon="@drawable/ic_launcher"
+        android:label="@string/app_name"
+        android:theme="@style/AppTheme" >
+        <activity
+            android:name=".GameViewActivity"
+            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/ControllerSample/libs/android-support-v4.jar b/samples/ControllerSample/libs/android-support-v4.jar
new file mode 100644
index 0000000..65ebaf8
--- /dev/null
+++ b/samples/ControllerSample/libs/android-support-v4.jar
Binary files differ
diff --git a/samples/ControllerSample/proguard-project.txt b/samples/ControllerSample/proguard-project.txt
new file mode 100644
index 0000000..f2fe155
--- /dev/null
+++ b/samples/ControllerSample/proguard-project.txt
@@ -0,0 +1,20 @@
+# To enable ProGuard in your project, edit project.properties
+# to define the proguard.config property as described in that file.
+#
+# Add project specific ProGuard rules here.
+# By default, the flags in this file are appended to flags specified
+# in ${sdk.dir}/tools/proguard/proguard-android.txt
+# You can edit the include path and order by changing the ProGuard
+# include property in project.properties.
+#
+# For more details, see
+#   http://developer.android.com/guide/developing/tools/proguard.html
+
+# Add any project specific keep options here:
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+#   public *;
+#}
diff --git a/samples/ControllerSample/project.properties b/samples/ControllerSample/project.properties
new file mode 100644
index 0000000..ce39f2d
--- /dev/null
+++ b/samples/ControllerSample/project.properties
@@ -0,0 +1,14 @@
+# This file is automatically generated by Android Tools.
+# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
+#
+# This file must be checked in Version Control Systems.
+#
+# To customize properties used by the Ant build system edit
+# "ant.properties", and override values to adapt the script to your
+# project structure.
+#
+# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
+#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
+
+# Project target.
+target=android-18
diff --git a/samples/ControllerSample/res/drawable-hdpi/ic_launcher.png b/samples/ControllerSample/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..4f421f9
--- /dev/null
+++ b/samples/ControllerSample/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/samples/ControllerSample/res/drawable-mdpi/ic_launcher.png b/samples/ControllerSample/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..38651fd
--- /dev/null
+++ b/samples/ControllerSample/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/samples/ControllerSample/res/drawable-xhdpi/ic_launcher.png b/samples/ControllerSample/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..c6f6d82
--- /dev/null
+++ b/samples/ControllerSample/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/ControllerSample/res/drawable-xxhdpi/ic_launcher.png b/samples/ControllerSample/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..eef1c76
--- /dev/null
+++ b/samples/ControllerSample/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/ControllerSample/res/layout/game_controller_input.xml b/samples/ControllerSample/res/layout/game_controller_input.xml
new file mode 100644
index 0000000..4e4a735
--- /dev/null
+++ b/samples/ControllerSample/res/layout/game_controller_input.xml
@@ -0,0 +1,40 @@
+<?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.
+-->
+
+
+<!-- Game controller input demo. -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical" >
+
+    <TextView
+        android:id="@+id/description"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:padding="12dip"
+        android:text="@string/game_controller_input_description" />
+
+    <com.example.controllersample.GameView
+        android:id="@+id/game"
+        android:layout_width="match_parent"
+        android:layout_height="0dip"
+        android:layout_margin="15dip"
+        android:layout_weight="1"
+        android:background="#000000" />
+
+</LinearLayout>
\ No newline at end of file
diff --git a/samples/ControllerSample/res/values-v11/styles.xml b/samples/ControllerSample/res/values-v11/styles.xml
new file mode 100644
index 0000000..541752f
--- /dev/null
+++ b/samples/ControllerSample/res/values-v11/styles.xml
@@ -0,0 +1,11 @@
+<resources>
+
+    <!--
+        Base application theme for API 11+. This theme completely replaces
+        AppBaseTheme from res/values/styles.xml on API 11+ devices.
+    -->
+    <style name="AppBaseTheme" parent="android:Theme.Holo.Light">
+        <!-- API 11 theme customizations can go here. -->
+    </style>
+
+</resources>
\ No newline at end of file
diff --git a/samples/ControllerSample/res/values-v14/styles.xml b/samples/ControllerSample/res/values-v14/styles.xml
new file mode 100644
index 0000000..f20e015
--- /dev/null
+++ b/samples/ControllerSample/res/values-v14/styles.xml
@@ -0,0 +1,12 @@
+<resources>
+
+    <!--
+        Base application theme for API 14+. This theme completely replaces
+        AppBaseTheme from BOTH res/values/styles.xml and
+        res/values-v11/styles.xml on API 14+ devices.
+    -->
+    <style name="AppBaseTheme" parent="android:Theme.Holo.Light.DarkActionBar">
+        <!-- API 14 theme customizations can go here. -->
+    </style>
+
+</resources>
\ No newline at end of file
diff --git a/samples/ControllerSample/res/values/strings.xml b/samples/ControllerSample/res/values/strings.xml
new file mode 100644
index 0000000..ba8e7d7
--- /dev/null
+++ b/samples/ControllerSample/res/values/strings.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <string name="app_name">Controller Sample</string>
+    <string name="game_controller_input_description">
+        This activity demonstrates how to process input events received from
+        game controllers.  Please connect your game controller now and try
+        moving the joysticks or pressing buttons.  If it helps, try to imagine
+        that you are a lone space cowboy in hot pursuit of the aliens who kidnapped
+        your favorite llama on their way back to Andromeda&#8230;
+    </string>
+</resources>
\ No newline at end of file
diff --git a/samples/ControllerSample/res/values/styles.xml b/samples/ControllerSample/res/values/styles.xml
new file mode 100644
index 0000000..4a10ca4
--- /dev/null
+++ b/samples/ControllerSample/res/values/styles.xml
@@ -0,0 +1,20 @@
+<resources>
+
+    <!--
+        Base application theme, dependent on API level. This theme is replaced
+        by AppBaseTheme from res/values-vXX/styles.xml on newer devices.
+    -->
+    <style name="AppBaseTheme" parent="android:Theme.Light">
+        <!--
+            Theme customizations available in newer API levels can go in
+            res/values-vXX/styles.xml, while customizations related to
+            backward-compatibility can go here.
+        -->
+    </style>
+
+    <!-- Application theme. -->
+    <style name="AppTheme" parent="AppBaseTheme">
+        <!-- All customizations that are NOT specific to a particular API-level can go here. -->
+    </style>
+
+</resources>
\ No newline at end of file
diff --git a/samples/ControllerSample/src/com/example/controllersample/GameView.java b/samples/ControllerSample/src/com/example/controllersample/GameView.java
new file mode 100644
index 0000000..6481a2a
--- /dev/null
+++ b/samples/ControllerSample/src/com/example/controllersample/GameView.java
@@ -0,0 +1,1159 @@
+/*
+ * 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.controllersample;
+
+import com.example.inputmanagercompat.InputManagerCompat;
+import com.example.inputmanagercompat.InputManagerCompat.InputDeviceListener;
+
+import android.annotation.SuppressLint;
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Paint.Style;
+import android.graphics.Path;
+import android.os.Build;
+import android.os.SystemClock;
+import android.os.Vibrator;
+import android.util.AttributeSet;
+import android.util.SparseArray;
+import android.view.InputDevice;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+import android.view.View;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Random;
+
+/*
+ * A trivial joystick based physics game to demonstrate joystick handling. If
+ * the game controller has a vibrator, then it is used to provide feedback when
+ * a bullet is fired or the ship crashes into an obstacle. Otherwise, the system
+ * vibrator is used for that purpose.
+ */
+@TargetApi(Build.VERSION_CODES.HONEYCOMB_MR1)
+public class GameView extends View implements InputDeviceListener {
+    private static final int MAX_OBSTACLES = 12;
+
+    private static final int DPAD_STATE_LEFT = 1 << 0;
+    private static final int DPAD_STATE_RIGHT = 1 << 1;
+    private static final int DPAD_STATE_UP = 1 << 2;
+    private static final int DPAD_STATE_DOWN = 1 << 3;
+
+    private final Random mRandom;
+    /*
+     * Each ship is created as an event comes in from a new Joystick device
+     */
+    private final SparseArray<Ship> mShips;
+    private final Map<String, Integer> mDescriptorMap;
+    private final List<Bullet> mBullets;
+    private final List<Obstacle> mObstacles;
+
+    private long mLastStepTime;
+    private final InputManagerCompat mInputManager;
+
+    private final float mBaseSpeed;
+
+    private final float mShipSize;
+
+    private final float mBulletSize;
+
+    private final float mMinObstacleSize;
+    private final float mMaxObstacleSize;
+    private final float mMinObstacleSpeed;
+    private final float mMaxObstacleSpeed;
+
+    public GameView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+
+        mRandom = new Random();
+        mShips = new SparseArray<Ship>();
+        mDescriptorMap = new HashMap<String, Integer>();
+        mBullets = new ArrayList<Bullet>();
+        mObstacles = new ArrayList<Obstacle>();
+
+        setFocusable(true);
+        setFocusableInTouchMode(true);
+
+        float baseSize = getContext().getResources().getDisplayMetrics().density * 5f;
+        mBaseSpeed = baseSize * 3;
+
+        mShipSize = baseSize * 3;
+
+        mBulletSize = baseSize;
+
+        mMinObstacleSize = baseSize * 2;
+        mMaxObstacleSize = baseSize * 12;
+        mMinObstacleSpeed = mBaseSpeed;
+        mMaxObstacleSpeed = mBaseSpeed * 3;
+
+        mInputManager = InputManagerCompat.Factory.getInputManager(this.getContext());
+        mInputManager.registerInputDeviceListener(this, null);
+    }
+
+    // Iterate through the input devices, looking for controllers. Create a ship
+    // for every device that reports itself as a gamepad or joystick.
+    void findControllersAndAttachShips() {
+        int[] deviceIds = mInputManager.getInputDeviceIds();
+        for (int deviceId : deviceIds) {
+            InputDevice dev = mInputManager.getInputDevice(deviceId);
+            int sources = dev.getSources();
+            // if the device is a gamepad/joystick, create a ship to represent it
+            if (((sources & InputDevice.SOURCE_GAMEPAD) == InputDevice.SOURCE_GAMEPAD) ||
+                    ((sources & InputDevice.SOURCE_JOYSTICK) == InputDevice.SOURCE_JOYSTICK)) {
+                // if the device has a gamepad or joystick
+                getShipForId(deviceId);
+            }
+        }
+    }
+
+    @Override
+    public boolean onKeyDown(int keyCode, KeyEvent event) {
+        int deviceId = event.getDeviceId();
+        if (deviceId != -1) {
+            Ship currentShip = getShipForId(deviceId);
+            if (currentShip.onKeyDown(keyCode, event)) {
+                step(event.getEventTime());
+                return true;
+            }
+        }
+
+        return super.onKeyDown(keyCode, event);
+    }
+
+    @Override
+    public boolean onKeyUp(int keyCode, KeyEvent event) {
+        int deviceId = event.getDeviceId();
+        if (deviceId != -1) {
+            Ship currentShip = getShipForId(deviceId);
+            if (currentShip.onKeyUp(keyCode, event)) {
+                step(event.getEventTime());
+                return true;
+            }
+        }
+
+        return super.onKeyUp(keyCode, event);
+    }
+
+    @Override
+    public boolean onGenericMotionEvent(MotionEvent event) {
+        mInputManager.onGenericMotionEvent(event);
+
+        // Check that the event came from a joystick or gamepad since a generic
+        // motion event could be almost anything. API level 18 adds the useful
+        // event.isFromSource() helper function.
+        int eventSource = event.getSource();
+        if ((((eventSource & InputDevice.SOURCE_GAMEPAD) == InputDevice.SOURCE_GAMEPAD) ||
+                ((eventSource & InputDevice.SOURCE_JOYSTICK) == InputDevice.SOURCE_JOYSTICK))
+                && event.getAction() == MotionEvent.ACTION_MOVE) {
+            int id = event.getDeviceId();
+            if (-1 != id) {
+                Ship curShip = getShipForId(id);
+                if (curShip.onGenericMotionEvent(event)) {
+                    return true;
+                }
+            }
+        }
+        return super.onGenericMotionEvent(event);
+    }
+
+    @Override
+    public void onWindowFocusChanged(boolean hasWindowFocus) {
+        // Turn on and off animations based on the window focus.
+        // Alternately, we could update the game state using the Activity
+        // onResume()
+        // and onPause() lifecycle events.
+        if (hasWindowFocus) {
+            mLastStepTime = SystemClock.uptimeMillis();
+            mInputManager.onResume();
+        } else {
+            int numShips = mShips.size();
+            for (int i = 0; i < numShips; i++) {
+                Ship currentShip = mShips.valueAt(i);
+                if (currentShip != null) {
+                    currentShip.setHeading(0, 0);
+                    currentShip.setVelocity(0, 0);
+                    currentShip.mDPadState = 0;
+                }
+            }
+            mInputManager.onPause();
+        }
+
+        super.onWindowFocusChanged(hasWindowFocus);
+    }
+
+    @Override
+    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
+        super.onSizeChanged(w, h, oldw, oldh);
+
+        // Reset the game when the view changes size.
+        reset();
+    }
+
+    @Override
+    protected void onDraw(Canvas canvas) {
+        super.onDraw(canvas);
+        // Update the animation
+        animateFrame();
+
+        // Draw the ships.
+        int numShips = mShips.size();
+        for (int i = 0; i < numShips; i++) {
+            Ship currentShip = mShips.valueAt(i);
+            if (currentShip != null) {
+                currentShip.draw(canvas);
+            }
+        }
+
+        // Draw bullets.
+        int numBullets = mBullets.size();
+        for (int i = 0; i < numBullets; i++) {
+            final Bullet bullet = mBullets.get(i);
+            bullet.draw(canvas);
+        }
+
+        // Draw obstacles.
+        int numObstacles = mObstacles.size();
+        for (int i = 0; i < numObstacles; i++) {
+            final Obstacle obstacle = mObstacles.get(i);
+            obstacle.draw(canvas);
+        }
+    }
+
+    /**
+     * Uses the device descriptor to try to assign the same color to the same
+     * joystick. If there are two joysticks of the same type connected over USB,
+     * or the API is < API level 16, it will be unable to distinguish the two
+     * devices.
+     *
+     * @param shipID
+     * @return
+     */
+    @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
+    private Ship getShipForId(int shipID) {
+        Ship currentShip = mShips.get(shipID);
+        if (null == currentShip) {
+
+            // do we know something about this ship already?
+            InputDevice dev = InputDevice.getDevice(shipID);
+            String deviceString = null;
+            Integer shipColor = null;
+            if (null != dev) {
+                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
+                    deviceString = dev.getDescriptor();
+                } else {
+                    deviceString = dev.getName();
+                }
+                shipColor = mDescriptorMap.get(deviceString);
+            }
+
+            if (null != shipColor) {
+                int color = shipColor;
+                int numShips = mShips.size();
+                // do we already have a ship with this color?
+                for (int i = 0; i < numShips; i++) {
+                    if (mShips.valueAt(i).getColor() == color) {
+                        shipColor = null;
+                        // we won't store this value either --- if the first
+                        // controller gets disconnected/connected, it will get
+                        // the same color.
+                        deviceString = null;
+                    }
+                }
+            }
+            if (null != shipColor) {
+                currentShip = new Ship(shipColor);
+                if (null != deviceString) {
+                    mDescriptorMap.remove(deviceString);
+                }
+            } else {
+                currentShip = new Ship(getNextShipColor());
+            }
+            mShips.append(shipID, currentShip);
+            currentShip.setInputDevice(dev);
+
+            if (null != deviceString) {
+                mDescriptorMap.put(deviceString, currentShip.getColor());
+            }
+        }
+        return currentShip;
+    }
+
+    /**
+     * Remove the ship from the array of active ships by ID.
+     *
+     * @param shipID
+     */
+    private void removeShipForID(int shipID) {
+        mShips.remove(shipID);
+    }
+
+    private void reset() {
+        mShips.clear();
+        mBullets.clear();
+        mObstacles.clear();
+        findControllersAndAttachShips();
+    }
+
+    private void animateFrame() {
+        long currentStepTime = SystemClock.uptimeMillis();
+        step(currentStepTime);
+        invalidate();
+    }
+
+    private void step(long currentStepTime) {
+        float tau = (currentStepTime - mLastStepTime) * 0.001f;
+        mLastStepTime = currentStepTime;
+
+        // Move the ships
+        int numShips = mShips.size();
+        for (int i = 0; i < numShips; i++) {
+            Ship currentShip = mShips.valueAt(i);
+            if (currentShip != null) {
+                currentShip.accelerate(tau);
+                if (!currentShip.step(tau)) {
+                    currentShip.reincarnate();
+                }
+            }
+        }
+
+        // Move the bullets.
+        int numBullets = mBullets.size();
+        for (int i = 0; i < numBullets; i++) {
+            final Bullet bullet = mBullets.get(i);
+            if (!bullet.step(tau)) {
+                mBullets.remove(i);
+                i -= 1;
+                numBullets -= 1;
+            }
+        }
+
+        // Move obstacles.
+        int numObstacles = mObstacles.size();
+        for (int i = 0; i < numObstacles; i++) {
+            final Obstacle obstacle = mObstacles.get(i);
+            if (!obstacle.step(tau)) {
+                mObstacles.remove(i);
+                i -= 1;
+                numObstacles -= 1;
+            }
+        }
+
+        // Check for collisions between bullets and obstacles.
+        for (int i = 0; i < numBullets; i++) {
+            final Bullet bullet = mBullets.get(i);
+            for (int j = 0; j < numObstacles; j++) {
+                final Obstacle obstacle = mObstacles.get(j);
+                if (bullet.collidesWith(obstacle)) {
+                    bullet.destroy();
+                    obstacle.destroy();
+                    break;
+                }
+            }
+        }
+
+        // Check for collisions between the ship and obstacles --- this could
+        // get slow
+        for (int i = 0; i < numObstacles; i++) {
+            final Obstacle obstacle = mObstacles.get(i);
+            for (int j = 0; j < numShips; j++) {
+                Ship currentShip = mShips.valueAt(j);
+                if (currentShip != null) {
+                    if (currentShip.collidesWith(obstacle)) {
+                        currentShip.destroy();
+                        obstacle.destroy();
+                        break;
+                    }
+                }
+            }
+        }
+
+        // Spawn more obstacles offscreen when needed.
+        // Avoid putting them right on top of the ship.
+        int tries = MAX_OBSTACLES - mObstacles.size() + 10;
+        final float minDistance = mShipSize * 4;
+        while (mObstacles.size() < MAX_OBSTACLES && tries-- > 0) {
+            float size = mRandom.nextFloat() * (mMaxObstacleSize - mMinObstacleSize)
+                    + mMinObstacleSize;
+            float positionX, positionY;
+            int edge = mRandom.nextInt(4);
+            switch (edge) {
+                case 0:
+                    positionX = -size;
+                    positionY = mRandom.nextInt(getHeight());
+                    break;
+                case 1:
+                    positionX = getWidth() + size;
+                    positionY = mRandom.nextInt(getHeight());
+                    break;
+                case 2:
+                    positionX = mRandom.nextInt(getWidth());
+                    positionY = -size;
+                    break;
+                default:
+                    positionX = mRandom.nextInt(getWidth());
+                    positionY = getHeight() + size;
+                    break;
+            }
+            boolean positionSafe = true;
+
+            // If the obstacle is too close to any ships, we don't want to
+            // spawn it.
+            for (int i = 0; i < numShips; i++) {
+                Ship currentShip = mShips.valueAt(i);
+                if (currentShip != null) {
+                    if (currentShip.distanceTo(positionX, positionY) < minDistance) {
+                        // try to spawn again
+                        positionSafe = false;
+                        break;
+                    }
+                }
+            }
+
+            // if the position is safe, add the obstacle and reset the retry
+            // counter
+            if (positionSafe) {
+                tries = MAX_OBSTACLES - mObstacles.size() + 10;
+                // we can add the obstacle now since it isn't close to any ships
+                float direction = mRandom.nextFloat() * (float) Math.PI * 2;
+                float speed = mRandom.nextFloat() * (mMaxObstacleSpeed - mMinObstacleSpeed)
+                        + mMinObstacleSpeed;
+                float velocityX = (float) Math.cos(direction) * speed;
+                float velocityY = (float) Math.sin(direction) * speed;
+
+                Obstacle obstacle = new Obstacle();
+                obstacle.setPosition(positionX, positionY);
+                obstacle.setSize(size);
+                obstacle.setVelocity(velocityX, velocityY);
+                mObstacles.add(obstacle);
+            }
+        }
+    }
+
+    private static float pythag(float x, float y) {
+        return (float) Math.sqrt(x * x + y * y);
+    }
+
+    private static int blend(float alpha, int from, int to) {
+        return from + (int) ((to - from) * alpha);
+    }
+
+    private static void setPaintARGBBlend(Paint paint, float alpha,
+            int a1, int r1, int g1, int b1,
+            int a2, int r2, int g2, int b2) {
+        paint.setARGB(blend(alpha, a1, a2), blend(alpha, r1, r2),
+                blend(alpha, g1, g2), blend(alpha, b1, b2));
+    }
+
+    private static float getCenteredAxis(MotionEvent event, InputDevice device,
+            int axis, int historyPos) {
+        final InputDevice.MotionRange range = device.getMotionRange(axis, event.getSource());
+        if (range != null) {
+            final float flat = range.getFlat();
+            final float value = historyPos < 0 ? event.getAxisValue(axis)
+                    : event.getHistoricalAxisValue(axis, historyPos);
+
+            // Ignore axis values that are within the 'flat' region of the
+            // joystick axis center.
+            // A joystick at rest does not always report an absolute position of
+            // (0,0).
+            if (Math.abs(value) > flat) {
+                return value;
+            }
+        }
+        return 0;
+    }
+
+    /**
+     * Any gamepad button + the spacebar or DPAD_CENTER will be used as the fire
+     * key.
+     *
+     * @param keyCode
+     * @return true of it's a fire key.
+     */
+    private static boolean isFireKey(int keyCode) {
+        return KeyEvent.isGamepadButton(keyCode)
+                || keyCode == KeyEvent.KEYCODE_DPAD_CENTER
+                || keyCode == KeyEvent.KEYCODE_SPACE;
+    }
+
+    private abstract class Sprite {
+        protected float mPositionX;
+        protected float mPositionY;
+        protected float mVelocityX;
+        protected float mVelocityY;
+        protected float mSize;
+        protected boolean mDestroyed;
+        protected float mDestroyAnimProgress;
+
+        public void setPosition(float x, float y) {
+            mPositionX = x;
+            mPositionY = y;
+        }
+
+        public void setVelocity(float x, float y) {
+            mVelocityX = x;
+            mVelocityY = y;
+        }
+
+        public void setSize(float size) {
+            mSize = size;
+        }
+
+        public float distanceTo(float x, float y) {
+            return pythag(mPositionX - x, mPositionY - y);
+        }
+
+        public float distanceTo(Sprite other) {
+            return distanceTo(other.mPositionX, other.mPositionY);
+        }
+
+        public boolean collidesWith(Sprite other) {
+            // Really bad collision detection.
+            return !mDestroyed && !other.mDestroyed
+                    && distanceTo(other) <= Math.max(mSize, other.mSize)
+                            + Math.min(mSize, other.mSize) * 0.5f;
+        }
+
+        public boolean isDestroyed() {
+            return mDestroyed;
+        }
+
+        /**
+         * Moves the sprite based on the elapsed time defined by tau.
+         *
+         * @param tau the elapsed time in seconds since the last step
+         * @return false if the sprite is to be removed from the display
+         */
+        public boolean step(float tau) {
+            mPositionX += mVelocityX * tau;
+            mPositionY += mVelocityY * tau;
+
+            if (mDestroyed) {
+                mDestroyAnimProgress += tau / getDestroyAnimDuration();
+                if (mDestroyAnimProgress >= getDestroyAnimCycles()) {
+                    return false;
+                }
+            }
+            return true;
+        }
+
+        /**
+         * Draws the sprite.
+         *
+         * @param canvas the Canvas upon which to draw the sprite.
+         */
+        public abstract void draw(Canvas canvas);
+
+        /**
+         * Returns the duration of the destruction animation of the sprite in
+         * seconds.
+         *
+         * @return the float duration in seconds of the destruction animation
+         */
+        public abstract float getDestroyAnimDuration();
+
+        /**
+         * Returns the number of cycles to play the destruction animation. A
+         * destruction animation has a duration and a number of cycles to play
+         * it for, so we can have an extended death sequence when a ship or
+         * object is destroyed.
+         *
+         * @return the float number of cycles to play the destruction animation
+         */
+        public abstract float getDestroyAnimCycles();
+
+        protected boolean isOutsidePlayfield() {
+            final int width = GameView.this.getWidth();
+            final int height = GameView.this.getHeight();
+            return mPositionX < 0 || mPositionX >= width
+                    || mPositionY < 0 || mPositionY >= height;
+        }
+
+        protected void wrapAtPlayfieldBoundary() {
+            final int width = GameView.this.getWidth();
+            final int height = GameView.this.getHeight();
+            while (mPositionX <= -mSize) {
+                mPositionX += width + mSize * 2;
+            }
+            while (mPositionX >= width + mSize) {
+                mPositionX -= width + mSize * 2;
+            }
+            while (mPositionY <= -mSize) {
+                mPositionY += height + mSize * 2;
+            }
+            while (mPositionY >= height + mSize) {
+                mPositionY -= height + mSize * 2;
+            }
+        }
+
+        public void destroy() {
+            mDestroyed = true;
+            step(0);
+        }
+    }
+
+    private static int sShipColor = 0;
+
+    /**
+     * Returns the next ship color in the sequence. Very simple. Does not in any
+     * way guarantee that there are not multiple ships with the same color on
+     * the screen.
+     *
+     * @return an int containing the index of the next ship color
+     */
+    private static int getNextShipColor() {
+        int color = sShipColor & 0x07;
+        if (0 == color) {
+            color++;
+            sShipColor++;
+        }
+        sShipColor++;
+        return color;
+    }
+
+    /*
+     * Static constants associated with Ship inner class
+     */
+    private static final long[] sDestructionVibratePattern = new long[] {
+            0, 20, 20, 40, 40, 80, 40, 300
+    };
+
+    private class Ship extends Sprite {
+        private static final float CORNER_ANGLE = (float) Math.PI * 2 / 3;
+        private static final float TO_DEGREES = (float) (180.0 / Math.PI);
+
+        private final float mMaxShipThrust = mBaseSpeed * 0.25f;
+        private final float mMaxSpeed = mBaseSpeed * 12;
+
+        // The ship actually determines the speed of the bullet, not the bullet
+        // itself
+        private final float mBulletSpeed = mBaseSpeed * 12;
+
+        private final Paint mPaint;
+        private final Path mPath;
+        private final int mR, mG, mB;
+        private final int mColor;
+
+        // The current device that is controlling the ship
+        private InputDevice mInputDevice;
+
+        private float mHeadingX;
+        private float mHeadingY;
+        private float mHeadingAngle;
+        private float mHeadingMagnitude;
+
+        private int mDPadState;
+
+        /**
+         * The colorIndex is used to create the color based on the lower three
+         * bits of the value in the current implementation.
+         *
+         * @param colorIndex
+         */
+        public Ship(int colorIndex) {
+            mPaint = new Paint();
+            mPaint.setStyle(Style.FILL);
+
+            setPosition(getWidth() * 0.5f, getHeight() * 0.5f);
+            setVelocity(0, 0);
+            setSize(mShipSize);
+
+            mPath = new Path();
+            mPath.moveTo(0, 0);
+            mPath.lineTo((float) Math.cos(-CORNER_ANGLE) * mSize,
+                    (float) Math.sin(-CORNER_ANGLE) * mSize);
+            mPath.lineTo(mSize, 0);
+            mPath.lineTo((float) Math.cos(CORNER_ANGLE) * mSize,
+                    (float) Math.sin(CORNER_ANGLE) * mSize);
+            mPath.lineTo(0, 0);
+
+            mR = (colorIndex & 0x01) == 0 ? 63 : 255;
+            mG = (colorIndex & 0x02) == 0 ? 63 : 255;
+            mB = (colorIndex & 0x04) == 0 ? 63 : 255;
+
+            mColor = colorIndex;
+        }
+
+        public boolean onKeyUp(int keyCode, KeyEvent event) {
+
+            // Handle keys going up.
+            boolean handled = false;
+            switch (keyCode) {
+                case KeyEvent.KEYCODE_DPAD_LEFT:
+                    setHeadingX(0);
+                    mDPadState &= ~DPAD_STATE_LEFT;
+                    handled = true;
+                    break;
+                case KeyEvent.KEYCODE_DPAD_RIGHT:
+                    setHeadingX(0);
+                    mDPadState &= ~DPAD_STATE_RIGHT;
+                    handled = true;
+                    break;
+                case KeyEvent.KEYCODE_DPAD_UP:
+                    setHeadingY(0);
+                    mDPadState &= ~DPAD_STATE_UP;
+                    handled = true;
+                    break;
+                case KeyEvent.KEYCODE_DPAD_DOWN:
+                    setHeadingY(0);
+                    mDPadState &= ~DPAD_STATE_DOWN;
+                    handled = true;
+                    break;
+                default:
+                    if (isFireKey(keyCode)) {
+                        handled = true;
+                    }
+                    break;
+            }
+            return handled;
+        }
+
+        /*
+         * Firing is a unique case where a ship creates a bullet. A bullet needs
+         * to be created with a position near the ship that is firing with a
+         * velocity that is based upon the speed of the ship.
+         */
+        private void fire() {
+            if (!isDestroyed()) {
+                Bullet bullet = new Bullet();
+                bullet.setPosition(getBulletInitialX(), getBulletInitialY());
+                bullet.setVelocity(getBulletVelocityX(),
+                        getBulletVelocityY());
+                mBullets.add(bullet);
+                vibrateController(20);
+            }
+        }
+
+        public boolean onKeyDown(int keyCode, KeyEvent event) {
+            // Handle DPad keys and fire button on initial down but not on
+            // auto-repeat.
+            boolean handled = false;
+            if (event.getRepeatCount() == 0) {
+                switch (keyCode) {
+                    case KeyEvent.KEYCODE_DPAD_LEFT:
+                        setHeadingX(-1);
+                        mDPadState |= DPAD_STATE_LEFT;
+                        handled = true;
+                        break;
+                    case KeyEvent.KEYCODE_DPAD_RIGHT:
+                        setHeadingX(1);
+                        mDPadState |= DPAD_STATE_RIGHT;
+                        handled = true;
+                        break;
+                    case KeyEvent.KEYCODE_DPAD_UP:
+                        setHeadingY(-1);
+                        mDPadState |= DPAD_STATE_UP;
+                        handled = true;
+                        break;
+                    case KeyEvent.KEYCODE_DPAD_DOWN:
+                        setHeadingY(1);
+                        mDPadState |= DPAD_STATE_DOWN;
+                        handled = true;
+                        break;
+                    default:
+                        if (isFireKey(keyCode)) {
+                            fire();
+                            handled = true;
+                        }
+                        break;
+                }
+            }
+            return handled;
+        }
+
+        /**
+         * Gets the vibrator from the controller if it is present. Note that it
+         * would be easy to get the system vibrator here if the controller one
+         * is not present, but we don't choose to do it in this case.
+         *
+         * @return the Vibrator for the controller, or null if it is not
+         *         present. or the API level cannot support it
+         */
+        @SuppressLint("NewApi")
+        private final Vibrator getVibrator() {
+            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN &&
+                    null != mInputDevice) {
+                return mInputDevice.getVibrator();
+            }
+            return null;
+        }
+
+        private void vibrateController(int time) {
+            Vibrator vibrator = getVibrator();
+            if (null != vibrator) {
+                vibrator.vibrate(time);
+            }
+        }
+
+        private void vibrateController(long[] pattern, int repeat) {
+            Vibrator vibrator = getVibrator();
+            if (null != vibrator) {
+                vibrator.vibrate(pattern, repeat);
+            }
+        }
+
+        /**
+         * The ship directly handles joystick input.
+         *
+         * @param event
+         * @param historyPos
+         */
+        private void processJoystickInput(MotionEvent event, int historyPos) {
+            // Get joystick position.
+            // Many game pads with two joysticks report the position of the
+            // second
+            // joystick
+            // using the Z and RZ axes so we also handle those.
+            // In a real game, we would allow the user to configure the axes
+            // manually.
+            if (null == mInputDevice) {
+                mInputDevice = event.getDevice();
+            }
+            float x = getCenteredAxis(event, mInputDevice, MotionEvent.AXIS_X, historyPos);
+            if (x == 0) {
+                x = getCenteredAxis(event, mInputDevice, MotionEvent.AXIS_HAT_X, historyPos);
+            }
+            if (x == 0) {
+                x = getCenteredAxis(event, mInputDevice, MotionEvent.AXIS_Z, historyPos);
+            }
+
+            float y = getCenteredAxis(event, mInputDevice, MotionEvent.AXIS_Y, historyPos);
+            if (y == 0) {
+                y = getCenteredAxis(event, mInputDevice, MotionEvent.AXIS_HAT_Y, historyPos);
+            }
+            if (y == 0) {
+                y = getCenteredAxis(event, mInputDevice, MotionEvent.AXIS_RZ, historyPos);
+            }
+
+            // Set the ship heading.
+            setHeading(x, y);
+            GameView.this.step(historyPos < 0 ? event.getEventTime() : event
+                    .getHistoricalEventTime(historyPos));
+        }
+
+        public boolean onGenericMotionEvent(MotionEvent event) {
+            if (0 == mDPadState) {
+                // Process all historical movement samples in the batch.
+                final int historySize = event.getHistorySize();
+                for (int i = 0; i < historySize; i++) {
+                    processJoystickInput(event, i);
+                }
+
+                // Process the current movement sample in the batch.
+                processJoystickInput(event, -1);
+            }
+            return true;
+        }
+
+        /**
+         * Set the game controller to be used to control the ship.
+         *
+         * @param dev the input device that will be controlling the ship
+         */
+        public void setInputDevice(InputDevice dev) {
+            mInputDevice = dev;
+        }
+
+        /**
+         * Sets the X component of the joystick heading value, defined by the
+         * platform as being from -1.0 (left) to 1.0 (right). This function is
+         * generally used to change the heading in response to a button-style
+         * DPAD event.
+         *
+         * @param x the float x component of the joystick heading value
+         */
+        public void setHeadingX(float x) {
+            mHeadingX = x;
+            updateHeading();
+        }
+
+        /**
+         * Sets the Y component of the joystick heading value, defined by the
+         * platform as being from -1.0 (top) to 1.0 (bottom). This function is
+         * generally used to change the heading in response to a button-style
+         * DPAD event.
+         *
+         * @param y the float y component of the joystick heading value
+         */
+        public void setHeadingY(float y) {
+            mHeadingY = y;
+            updateHeading();
+        }
+
+        /**
+         * Sets the heading as floating point values returned by a joystick.
+         * These values are normalized by the Android platform to be from -1.0
+         * (left, top) to 1.0 (right, bottom)
+         *
+         * @param x the float x component of the joystick heading value
+         * @param y the float y component of the joystick heading value
+         */
+        public void setHeading(float x, float y) {
+            mHeadingX = x;
+            mHeadingY = y;
+            updateHeading();
+        }
+
+        /**
+         * Converts the heading values from joystick devices to the polar
+         * representation of the heading angle if the magnitude of the heading
+         * is significant (> 0.1f).
+         */
+        private void updateHeading() {
+            mHeadingMagnitude = pythag(mHeadingX, mHeadingY);
+            if (mHeadingMagnitude > 0.1f) {
+                mHeadingAngle = (float) Math.atan2(mHeadingY, mHeadingX);
+            }
+        }
+
+        /**
+         * Bring our ship back to life, stopping the destroy animation.
+         */
+        public void reincarnate() {
+            mDestroyed = false;
+            mDestroyAnimProgress = 0.0f;
+        }
+
+        private float polarX(float radius) {
+            return (float) Math.cos(mHeadingAngle) * radius;
+        }
+
+        private float polarY(float radius) {
+            return (float) Math.sin(mHeadingAngle) * radius;
+        }
+
+        /**
+         * Gets the initial x coordinate for the bullet.
+         *
+         * @return the x coordinate of the bullet adjusted for the position and
+         *         direction of the ship
+         */
+        public float getBulletInitialX() {
+            return mPositionX + polarX(mSize);
+        }
+
+        /**
+         * Gets the initial y coordinate for the bullet.
+         *
+         * @return the y coordinate of the bullet adjusted for the position and
+         *         direction of the ship
+         */
+        public float getBulletInitialY() {
+            return mPositionY + polarY(mSize);
+        }
+
+        /**
+         * Returns the bullet speed Y component.
+         *
+         * @return adjusted Y component bullet speed for the velocity and
+         *         direction of the ship
+         */
+        public float getBulletVelocityY() {
+            return mVelocityY + polarY(mBulletSpeed);
+        }
+
+        /**
+         * Returns the bullet speed X component
+         *
+         * @return adjusted X component bullet speed for the velocity and
+         *         direction of the ship
+         */
+        public float getBulletVelocityX() {
+            return mVelocityX + polarX(mBulletSpeed);
+        }
+
+        /**
+         * Uses the heading magnitude and direction to change the acceleration
+         * of the ship. In theory, this should be scaled according to the
+         * elapsed time.
+         *
+         * @param tau the elapsed time in seconds between the last step
+         */
+        public void accelerate(float tau) {
+            final float thrust = mHeadingMagnitude * mMaxShipThrust;
+            mVelocityX += polarX(thrust) * tau * mMaxSpeed / 4;
+            mVelocityY += polarY(thrust) * tau * mMaxSpeed / 4;
+
+            final float speed = pythag(mVelocityX, mVelocityY);
+            if (speed > mMaxSpeed) {
+                final float scale = mMaxSpeed / speed;
+                mVelocityX = mVelocityX * scale * scale;
+                mVelocityY = mVelocityY * scale * scale;
+            }
+        }
+
+        @Override
+        public boolean step(float tau) {
+            if (!super.step(tau)) {
+                return false;
+            }
+            wrapAtPlayfieldBoundary();
+            return true;
+        }
+
+        @Override
+        public void draw(Canvas canvas) {
+            setPaintARGBBlend(mPaint, mDestroyAnimProgress - (int) (mDestroyAnimProgress),
+                    255, mR, mG, mB,
+                    0, 255, 0, 0);
+
+            canvas.save(Canvas.MATRIX_SAVE_FLAG);
+            canvas.translate(mPositionX, mPositionY);
+            canvas.rotate(mHeadingAngle * TO_DEGREES);
+            canvas.drawPath(mPath, mPaint);
+            canvas.restore();
+        }
+
+        @Override
+        public float getDestroyAnimDuration() {
+            return 1.0f;
+        }
+
+        @Override
+        public void destroy() {
+            super.destroy();
+            vibrateController(sDestructionVibratePattern, -1);
+        }
+
+        @Override
+        public float getDestroyAnimCycles() {
+            return 5.0f;
+        }
+
+        public int getColor() {
+            return mColor;
+        }
+    }
+
+    private static final Paint mBulletPaint;
+    static {
+        mBulletPaint = new Paint();
+        mBulletPaint.setStyle(Style.FILL);
+    }
+
+    private class Bullet extends Sprite {
+
+        public Bullet() {
+            setSize(mBulletSize);
+        }
+
+        @Override
+        public boolean step(float tau) {
+            if (!super.step(tau)) {
+                return false;
+            }
+            return !isOutsidePlayfield();
+        }
+
+        @Override
+        public void draw(Canvas canvas) {
+            setPaintARGBBlend(mBulletPaint, mDestroyAnimProgress,
+                    255, 255, 255, 0,
+                    0, 255, 255, 255);
+            canvas.drawCircle(mPositionX, mPositionY, mSize, mBulletPaint);
+        }
+
+        @Override
+        public float getDestroyAnimDuration() {
+            return 0.125f;
+        }
+
+        @Override
+        public float getDestroyAnimCycles() {
+            return 1.0f;
+        }
+
+    }
+
+    private static final Paint mObstaclePaint;
+    static {
+        mObstaclePaint = new Paint();
+        mObstaclePaint.setARGB(255, 127, 127, 255);
+        mObstaclePaint.setStyle(Style.FILL);
+    }
+
+    private class Obstacle extends Sprite {
+
+        @Override
+        public boolean step(float tau) {
+            if (!super.step(tau)) {
+                return false;
+            }
+            wrapAtPlayfieldBoundary();
+            return true;
+        }
+
+        @Override
+        public void draw(Canvas canvas) {
+            setPaintARGBBlend(mObstaclePaint, mDestroyAnimProgress,
+                    255, 127, 127, 255,
+                    0, 255, 0, 0);
+            canvas.drawCircle(mPositionX, mPositionY,
+                    mSize * (1.0f - mDestroyAnimProgress), mObstaclePaint);
+        }
+
+        @Override
+        public float getDestroyAnimDuration() {
+            return 0.25f;
+        }
+
+        @Override
+        public float getDestroyAnimCycles() {
+            return 1.0f;
+        }
+    }
+
+    /*
+     * When an input device is added, we add a ship based upon the device.
+     * @see
+     * com.example.inputmanagercompat.InputManagerCompat.InputDeviceListener
+     * #onInputDeviceAdded(int)
+     */
+    @Override
+    public void onInputDeviceAdded(int deviceId) {
+        getShipForId(deviceId);
+    }
+
+    /*
+     * This is an unusual case. Input devices don't typically change, but they
+     * certainly can --- for example a device may have different modes. We use
+     * this to make sure that the ship has an up-to-date InputDevice.
+     * @see
+     * com.example.inputmanagercompat.InputManagerCompat.InputDeviceListener
+     * #onInputDeviceChanged(int)
+     */
+    @Override
+    public void onInputDeviceChanged(int deviceId) {
+        Ship ship = getShipForId(deviceId);
+        ship.setInputDevice(InputDevice.getDevice(deviceId));
+    }
+
+    /*
+     * Remove any ship associated with the ID.
+     * @see
+     * com.example.inputmanagercompat.InputManagerCompat.InputDeviceListener
+     * #onInputDeviceRemoved(int)
+     */
+    @Override
+    public void onInputDeviceRemoved(int deviceId) {
+        removeShipForID(deviceId);
+    }
+}
diff --git a/samples/ControllerSample/src/com/example/controllersample/GameViewActivity.java b/samples/ControllerSample/src/com/example/controllersample/GameViewActivity.java
new file mode 100644
index 0000000..aaf8bae
--- /dev/null
+++ b/samples/ControllerSample/src/com/example/controllersample/GameViewActivity.java
@@ -0,0 +1,30 @@
+/*
+ * 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.controllersample;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+public class GameViewActivity extends Activity {
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        this.setContentView(R.layout.game_controller_input);
+    }
+
+}
diff --git a/samples/ControllerSample/src/com/example/inputmanagercompat/InputManagerCompat.java b/samples/ControllerSample/src/com/example/inputmanagercompat/InputManagerCompat.java
new file mode 100644
index 0000000..fabc876
--- /dev/null
+++ b/samples/ControllerSample/src/com/example/inputmanagercompat/InputManagerCompat.java
@@ -0,0 +1,140 @@
+/*
+ * 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.inputmanagercompat;
+
+import android.content.Context;
+import android.os.Build;
+import android.os.Handler;
+import android.view.InputDevice;
+import android.view.MotionEvent;
+
+public interface InputManagerCompat {
+    /**
+     * Gets information about the input device with the specified id.
+     *
+     * @param id The device id
+     * @return The input device or null if not found
+     */
+    public InputDevice getInputDevice(int id);
+
+    /**
+     * Gets the ids of all input devices in the system.
+     *
+     * @return The input device ids.
+     */
+    public int[] getInputDeviceIds();
+
+    /**
+     * Registers an input device listener to receive notifications about when
+     * input devices are added, removed or changed.
+     *
+     * @param listener The listener to register.
+     * @param handler The handler on which the listener should be invoked, or
+     *            null if the listener should be invoked on the calling thread's
+     *            looper.
+     */
+    public void registerInputDeviceListener(InputManagerCompat.InputDeviceListener listener,
+            Handler handler);
+
+    /**
+     * Unregisters an input device listener.
+     *
+     * @param listener The listener to unregister.
+     */
+    public void unregisterInputDeviceListener(InputManagerCompat.InputDeviceListener listener);
+
+    /*
+     * The following three calls are to simulate V16 behavior on pre-Jellybean
+     * devices. If you don't call them, your callback will never be called
+     * pre-API 16.
+     */
+
+    /**
+     * Pass the motion events to the InputManagerCompat. This is used to
+     * optimize for polling for controllers. If you do not pass these events in,
+     * polling will cause regular object creation.
+     *
+     * @param event the motion event from the app
+     */
+    public void onGenericMotionEvent(MotionEvent event);
+
+    /**
+     * Tell the V9 input manager that it should stop polling for disconnected
+     * devices. You can call this during onPause in your activity, although you
+     * might want to call it whenever your game is not active (or whenever you
+     * don't care about being notified of new input devices)
+     */
+    public void onPause();
+
+    /**
+     * Tell the V9 input manager that it should start polling for disconnected
+     * devices. You can call this during onResume in your activity, although you
+     * might want to call it less often (only when the gameplay is actually
+     * active)
+     */
+    public void onResume();
+
+    public interface InputDeviceListener {
+        /**
+         * Called whenever the input manager detects that a device has been
+         * added. This will only be called in the V9 version when a motion event
+         * is detected.
+         *
+         * @param deviceId The id of the input device that was added.
+         */
+        void onInputDeviceAdded(int deviceId);
+
+        /**
+         * Called whenever the properties of an input device have changed since
+         * they were last queried. This will not be called for the V9 version of
+         * the API.
+         *
+         * @param deviceId The id of the input device that changed.
+         */
+        void onInputDeviceChanged(int deviceId);
+
+        /**
+         * Called whenever the input manager detects that a device has been
+         * removed. For the V9 version, this can take some time depending on the
+         * poll rate.
+         *
+         * @param deviceId The id of the input device that was removed.
+         */
+        void onInputDeviceRemoved(int deviceId);
+    }
+
+    /**
+     * Use this to construct a compatible InputManager.
+     */
+    public static class Factory {
+
+        /**
+         * Constructs and returns a compatible InputManger
+         *
+         * @param context the Context that will be used to get the system
+         *            service from
+         * @return a compatible implementation of InputManager
+         */
+        public static InputManagerCompat getInputManager(Context context) {
+            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
+                return new InputManagerV16(context);
+            } else {
+                return new InputManagerV9();
+            }
+        }
+    }
+}
diff --git a/samples/ControllerSample/src/com/example/inputmanagercompat/InputManagerV16.java b/samples/ControllerSample/src/com/example/inputmanagercompat/InputManagerV16.java
new file mode 100644
index 0000000..d26581e
--- /dev/null
+++ b/samples/ControllerSample/src/com/example/inputmanagercompat/InputManagerV16.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.inputmanagercompat;
+
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.hardware.input.InputManager;
+import android.os.Build;
+import android.os.Handler;
+import android.view.InputDevice;
+import android.view.MotionEvent;
+
+import java.util.HashMap;
+import java.util.Map;
+
+@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
+public class InputManagerV16 implements InputManagerCompat {
+
+    private final InputManager mInputManager;
+    private final Map<InputManagerCompat.InputDeviceListener, V16InputDeviceListener> mListeners;
+
+    public InputManagerV16(Context context) {
+        mInputManager = (InputManager) context.getSystemService(Context.INPUT_SERVICE);
+        mListeners = new HashMap<InputManagerCompat.InputDeviceListener, V16InputDeviceListener>();
+    }
+
+    @Override
+    public InputDevice getInputDevice(int id) {
+        return mInputManager.getInputDevice(id);
+    }
+
+    @Override
+    public int[] getInputDeviceIds() {
+        return mInputManager.getInputDeviceIds();
+    }
+
+    static class V16InputDeviceListener implements InputManager.InputDeviceListener {
+        final InputManagerCompat.InputDeviceListener mIDL;
+
+        public V16InputDeviceListener(InputDeviceListener idl) {
+            mIDL = idl;
+        }
+
+        @Override
+        public void onInputDeviceAdded(int deviceId) {
+            mIDL.onInputDeviceAdded(deviceId);
+        }
+
+        @Override
+        public void onInputDeviceChanged(int deviceId) {
+            mIDL.onInputDeviceChanged(deviceId);
+        }
+
+        @Override
+        public void onInputDeviceRemoved(int deviceId) {
+            mIDL.onInputDeviceRemoved(deviceId);
+        }
+
+    }
+
+    @Override
+    public void registerInputDeviceListener(InputDeviceListener listener, Handler handler) {
+        V16InputDeviceListener v16Listener = new V16InputDeviceListener(listener);
+        mInputManager.registerInputDeviceListener(v16Listener, handler);
+        mListeners.put(listener, v16Listener);
+    }
+
+    @Override
+    public void unregisterInputDeviceListener(InputDeviceListener listener) {
+        V16InputDeviceListener curListener = mListeners.remove(listener);
+        if (null != curListener)
+        {
+            mInputManager.unregisterInputDeviceListener(curListener);
+        }
+
+    }
+
+    @Override
+    public void onGenericMotionEvent(MotionEvent event) {
+        // unused in V16
+    }
+
+    @Override
+    public void onPause() {
+        // unused in V16
+    }
+
+    @Override
+    public void onResume() {
+        // unused in V16
+    }
+
+}
diff --git a/samples/ControllerSample/src/com/example/inputmanagercompat/InputManagerV9.java b/samples/ControllerSample/src/com/example/inputmanagercompat/InputManagerV9.java
new file mode 100644
index 0000000..dcd8988
--- /dev/null
+++ b/samples/ControllerSample/src/com/example/inputmanagercompat/InputManagerV9.java
@@ -0,0 +1,211 @@
+/*
+ * 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.inputmanagercompat;
+
+import android.os.Handler;
+import android.os.Message;
+import android.os.SystemClock;
+import android.util.Log;
+import android.util.SparseArray;
+import android.view.InputDevice;
+import android.view.MotionEvent;
+
+import java.lang.ref.WeakReference;
+import java.util.ArrayDeque;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Queue;
+
+public class InputManagerV9 implements InputManagerCompat {
+    private static final String LOG_TAG = "InputManagerV9";
+    private static final int MESSAGE_TEST_FOR_DISCONNECT = 101;
+    private static final long CHECK_ELAPSED_TIME = 3000L;
+
+    private static final int ON_DEVICE_ADDED = 0;
+    private static final int ON_DEVICE_CHANGED = 1;
+    private static final int ON_DEVICE_REMOVED = 2;
+
+    private final SparseArray<long[]> mDevices;
+    private final Map<InputDeviceListener, Handler> mListeners;
+    private final Handler mDefaultHandler;
+
+    private static class PollingMessageHandler extends Handler {
+        private final WeakReference<InputManagerV9> mInputManager;
+
+        PollingMessageHandler(InputManagerV9 im) {
+            mInputManager = new WeakReference<InputManagerV9>(im);
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            super.handleMessage(msg);
+            switch (msg.what) {
+                case MESSAGE_TEST_FOR_DISCONNECT:
+                    InputManagerV9 imv = mInputManager.get();
+                    if (null != imv) {
+                        long time = SystemClock.elapsedRealtime();
+                        int size = imv.mDevices.size();
+                        for (int i = 0; i < size; i++) {
+                            long[] lastContact = imv.mDevices.valueAt(i);
+                            if (null != lastContact) {
+                                if (time - lastContact[0] > CHECK_ELAPSED_TIME) {
+                                    // check to see if the device has been
+                                    // disconnected
+                                    int id = imv.mDevices.keyAt(i);
+                                    if (null == InputDevice.getDevice(id)) {
+                                        // disconnected!
+                                        imv.notifyListeners(ON_DEVICE_REMOVED, id);
+                                        imv.mDevices.remove(id);
+                                    } else {
+                                        lastContact[0] = time;
+                                    }
+                                }
+                            }
+                        }
+                        sendEmptyMessageDelayed(MESSAGE_TEST_FOR_DISCONNECT,
+                                CHECK_ELAPSED_TIME);
+                    }
+                    break;
+            }
+        }
+
+    }
+
+    public InputManagerV9() {
+        mDevices = new SparseArray<long[]>();
+        mListeners = new HashMap<InputDeviceListener, Handler>();
+        mDefaultHandler = new PollingMessageHandler(this);
+        // as a side-effect, populates our collection of watched
+        // input devices
+        getInputDeviceIds();
+    }
+
+    @Override
+    public InputDevice getInputDevice(int id) {
+        return InputDevice.getDevice(id);
+    }
+
+    @Override
+    public int[] getInputDeviceIds() {
+        // add any hitherto unknown devices to our
+        // collection of watched input devices
+        int[] activeDevices = InputDevice.getDeviceIds();
+        long time = SystemClock.elapsedRealtime();
+        for ( int id : activeDevices ) {
+            long[] lastContact = mDevices.get(id);
+            if ( null == lastContact ) {
+                // we have a new device
+                mDevices.put(id, new long[] { time });
+            }
+        }
+        return activeDevices;
+    }
+
+    @Override
+    public void registerInputDeviceListener(InputDeviceListener listener, Handler handler) {
+        mListeners.remove(listener);
+        if (handler == null) {
+            handler = mDefaultHandler;
+        }
+        mListeners.put(listener, handler);
+    }
+
+    @Override
+    public void unregisterInputDeviceListener(InputDeviceListener listener) {
+        mListeners.remove(listener);
+    }
+
+    private void notifyListeners(int why, int deviceId) {
+        // the state of some device has changed
+        if (!mListeners.isEmpty()) {
+            // yes... this will cause an object to get created... hopefully
+            // it won't happen very often
+            for (InputDeviceListener listener : mListeners.keySet()) {
+                Handler handler = mListeners.get(listener);
+                DeviceEvent odc = DeviceEvent.getDeviceEvent(why, deviceId, listener);
+                handler.post(odc);
+            }
+        }
+    }
+
+    private static class DeviceEvent implements Runnable {
+        private int mMessageType;
+        private int mId;
+        private InputDeviceListener mListener;
+        private static Queue<DeviceEvent> sEventQueue = new ArrayDeque<DeviceEvent>();
+
+        private DeviceEvent() {
+        }
+
+        static DeviceEvent getDeviceEvent(int messageType, int id,
+                InputDeviceListener listener) {
+            DeviceEvent curChanged = sEventQueue.poll();
+            if (null == curChanged) {
+                curChanged = new DeviceEvent();
+            }
+            curChanged.mMessageType = messageType;
+            curChanged.mId = id;
+            curChanged.mListener = listener;
+            return curChanged;
+        }
+
+        @Override
+        public void run() {
+            switch (mMessageType) {
+                case ON_DEVICE_ADDED:
+                    mListener.onInputDeviceAdded(mId);
+                    break;
+                case ON_DEVICE_CHANGED:
+                    mListener.onInputDeviceChanged(mId);
+                    break;
+                case ON_DEVICE_REMOVED:
+                    mListener.onInputDeviceRemoved(mId);
+                    break;
+                default:
+                    Log.e(LOG_TAG, "Unknown Message Type");
+                    break;
+            }
+            // dump this runnable back in the queue
+            sEventQueue.offer(this);
+        }
+    }
+
+    @Override
+    public void onGenericMotionEvent(MotionEvent event) {
+        // detect new devices
+        int id = event.getDeviceId();
+        long[] timeArray = mDevices.get(id);
+        if (null == timeArray) {
+            notifyListeners(ON_DEVICE_ADDED, id);
+            timeArray = new long[1];
+            mDevices.put(id, timeArray);
+        }
+        long time = SystemClock.elapsedRealtime();
+        timeArray[0] = time;
+    }
+
+    @Override
+    public void onPause() {
+        mDefaultHandler.removeMessages(MESSAGE_TEST_FOR_DISCONNECT);
+    }
+
+    @Override
+    public void onResume() {
+        mDefaultHandler.sendEmptyMessage(MESSAGE_TEST_FOR_DISCONNECT);
+    }
+
+}
diff --git a/samples/Support4Demos/AndroidManifest.xml b/samples/Support4Demos/AndroidManifest.xml
index 46a4831..5b43488 100644
--- a/samples/Support4Demos/AndroidManifest.xml
+++ b/samples/Support4Demos/AndroidManifest.xml
@@ -305,6 +305,15 @@
             </intent-filter>
         </activity>
 
+        <activity android:name=".widget.SwipeRefreshLayoutActivity"
+                  android:label="@string/swipe"
+                  android:theme="@style/ThemeHoloLight">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="com.example.android.supportv4.SUPPORT4_SAMPLE_CODE" />
+            </intent-filter>
+        </activity>
+
         <activity android:name=".widget.ContentLoadingProgressBarActivity"
                   android:label="@string/content_loading_progress_bar">
             <intent-filter>
diff --git a/samples/Support4Demos/res/drawable-hdpi/refresh.png b/samples/Support4Demos/res/drawable-hdpi/refresh.png
new file mode 100644
index 0000000..d65c15f
--- /dev/null
+++ b/samples/Support4Demos/res/drawable-hdpi/refresh.png
Binary files differ
diff --git a/samples/Support4Demos/res/drawable-mdpi/refresh.png b/samples/Support4Demos/res/drawable-mdpi/refresh.png
new file mode 100644
index 0000000..dc96718
--- /dev/null
+++ b/samples/Support4Demos/res/drawable-mdpi/refresh.png
Binary files differ
diff --git a/samples/Support4Demos/res/drawable-xhdpi/refresh.png b/samples/Support4Demos/res/drawable-xhdpi/refresh.png
new file mode 100644
index 0000000..47da13e
--- /dev/null
+++ b/samples/Support4Demos/res/drawable-xhdpi/refresh.png
Binary files differ
diff --git a/samples/Support4Demos/res/layout/swipe_refresh_widget_sample.xml b/samples/Support4Demos/res/layout/swipe_refresh_widget_sample.xml
new file mode 100644
index 0000000..698024e
--- /dev/null
+++ b/samples/Support4Demos/res/layout/swipe_refresh_widget_sample.xml
@@ -0,0 +1,26 @@
+<?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.
+-->
+
+<android.support.v4.widget.SwipeRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/swipe_refresh_widget"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+    <!-- some full screen pullable view that will be the offsetable content -->
+    <ListView
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:id="@+id/content"/>
+</android.support.v4.widget.SwipeRefreshLayout>
\ No newline at end of file
diff --git a/samples/Support4Demos/res/menu/swipe_refresh_menu.xml b/samples/Support4Demos/res/menu/swipe_refresh_menu.xml
new file mode 100644
index 0000000..214c637
--- /dev/null
+++ b/samples/Support4Demos/res/menu/swipe_refresh_menu.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.
+-->
+
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:id="@+id/force_refresh"
+        android:showAsAction="ifRoom"
+        android:icon="@drawable/refresh"
+        android:title="Refresh" />
+</menu>
\ No newline at end of file
diff --git a/samples/Support4Demos/res/values-v11/styles.xml b/samples/Support4Demos/res/values-v11/styles.xml
index 04c6f3f..c21e6d8 100644
--- a/samples/Support4Demos/res/values-v11/styles.xml
+++ b/samples/Support4Demos/res/values-v11/styles.xml
@@ -19,6 +19,10 @@
     <style name="ThemeHolo" parent="android:Theme.Holo">
     </style>
 
+    <!-- For API level 11 or later, the Holo theme is available and we prefer that. -->
+    <style name="ThemeHoloLight" parent="android:Theme.Holo.Light">
+    </style>
+
     <!-- For API level 11 or later, we can use the magical DialogWhenLarge theme. -->
     <style name="ThemeDialogWhenLarge" parent="android:style/Theme.Holo.DialogWhenLarge">
     </style>
diff --git a/samples/Support4Demos/res/values/colors.xml b/samples/Support4Demos/res/values/colors.xml
index a52502e..ce3d633 100644
--- a/samples/Support4Demos/res/values/colors.xml
+++ b/samples/Support4Demos/res/values/colors.xml
@@ -18,5 +18,9 @@
     <drawable name="red">#7f00</drawable>
     <drawable name="blue">#770000ff</drawable>
     <drawable name="green">#7700ff00</drawable>
-	<drawable name="yellow">#77ffff00</drawable>
+    <drawable name="yellow">#77ffff00</drawable>
+    <color name="color1">#ff0f9d58</color>
+    <color name="color2">#ffdb4437</color>
+    <color name="color3">#ff4285f4</color>
+    <color name="color4">#fff4b400</color>
 </resources>
diff --git a/samples/Support4Demos/res/values/strings.xml b/samples/Support4Demos/res/values/strings.xml
index ce41aaf..91b5c42 100644
--- a/samples/Support4Demos/res/values/strings.xml
+++ b/samples/Support4Demos/res/values/strings.xml
@@ -160,7 +160,13 @@
 
     <string name="drawer_layout_summary">This activity illustrates the use of sliding drawers. The drawer may be pulled out from the starting edge, which is left on left-to-right locales, with an edge swipe. If this demo is running on Ice Cream Sandwich or newer you may tap the icon at the starting side of the action bar to open the drawer as well.</string>
 
+    <!-- Title of the navigation drawer, used by accessibility to announce state changes. -->
+    <string name="drawer_title">Navigation</string>
+
+    <!-- Description of the icon that opens the navigation drawer, used by accessibility. -->
     <string name="drawer_open">Open navigation drawer</string>
+
+    <!-- Description of the icon that closes the navigation drawer, used by accessibility. -->
     <string name="drawer_close">Close navigation drawer</string>
 
     <string name="sliding_pane_layout_support">Widget/Sliding pane layout</string>
@@ -176,4 +182,6 @@
     <!-- ContentLoadingProgressBar -->
     <string name="content_loading_progress_bar">Widget/Content Loading Progress Bar</string>
 
+    <!--  Swipe refresh -->
+    <string name="swipe">Widget/SwipeRefreshLayout</string>
 </resources>
diff --git a/samples/Support4Demos/res/values/styles.xml b/samples/Support4Demos/res/values/styles.xml
index 97cdb6f..689555b 100644
--- a/samples/Support4Demos/res/values/styles.xml
+++ b/samples/Support4Demos/res/values/styles.xml
@@ -21,7 +21,14 @@
          selected when the holographic theme is available. -->
     <style name="ThemeHolo" parent="android:Theme">
     </style>
-    
+
+    <!-- This is a theme that will adjust itself depending on the API version.
+         The default definition is the safe one, using a theme that has always
+         been defined.  Look at values-11/styles.xml for a variation that is
+         selected when the holographic theme is available. -->
+    <style name="ThemeHoloLight" parent="android:Theme.Light">
+    </style>
+
     <!-- Older platforms don't have Theme.Holo.DialogWhenLarge; we will define
          our own wrapper theme that uses it only when running on the appropriate
          platform version.  On older platforms, we always use the generic
diff --git a/samples/Support4Demos/src/com/example/android/supportv4/widget/DrawerLayoutActivity.java b/samples/Support4Demos/src/com/example/android/supportv4/widget/DrawerLayoutActivity.java
index 7b88faa..b8735b4 100644
--- a/samples/Support4Demos/src/com/example/android/supportv4/widget/DrawerLayoutActivity.java
+++ b/samples/Support4Demos/src/com/example/android/supportv4/widget/DrawerLayoutActivity.java
@@ -89,6 +89,11 @@
         mDrawerLayout.setDrawerListener(new DemoDrawerListener());
         mDrawerLayout.setDrawerShadow(R.drawable.drawer_shadow, GravityCompat.START);
 
+        // The drawer title must be set in order to announce state changes when
+        // accessibility is turned on. This is typically a simple description,
+        // e.g. "Navigation".
+        mDrawerLayout.setDrawerTitle(GravityCompat.START, getString(R.string.drawer_title));
+
         mDrawer.setAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1,
                 Shakespeare.TITLES));
         mDrawer.setOnItemClickListener(new DrawerItemClickListener());
diff --git a/samples/Support4Demos/src/com/example/android/supportv4/widget/SwipeRefreshLayoutActivity.java b/samples/Support4Demos/src/com/example/android/supportv4/widget/SwipeRefreshLayoutActivity.java
new file mode 100644
index 0000000..7a0543c
--- /dev/null
+++ b/samples/Support4Demos/src/com/example/android/supportv4/widget/SwipeRefreshLayoutActivity.java
@@ -0,0 +1,139 @@
+/*
+ * 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.supportv4.widget;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.os.Handler;
+import android.support.v4.widget.SwipeRefreshLayout;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.ArrayAdapter;
+import android.widget.Button;
+import android.widget.ListView;
+import android.widget.Toast;
+
+import com.example.android.supportv4.R;
+import com.example.android.supportv4.Shakespeare;
+
+import android.support.v4.widget.SwipeRefreshLayout.OnRefreshListener;
+
+/**
+ * Example of using the SwipeRefreshLayout.
+ */
+public class SwipeRefreshLayoutActivity extends Activity implements OnRefreshListener {
+    public static final String[] TITLES =
+    {
+            "Henry IV (1)",
+            "Henry V",
+            "Henry VIII",
+            "Richard II",
+            "Richard III",
+            "Merchant of Venice",
+            "Othello",
+            "King Lear",
+            "Henry IV (1)",
+            "Henry V",
+            "Henry VIII",
+            "Richard II",
+            "Richard III",
+            "Merchant of Venice",
+            "Othello",
+            "King Lear",
+            "Henry IV (1)",
+            "Henry V",
+            "Henry VIII",
+            "Richard II",
+            "Richard III",
+            "Merchant of Venice",
+            "Othello",
+            "King Lear",
+            "Henry IV (1)",
+            "Henry V",
+            "Henry VIII",
+            "Richard II",
+            "Richard III",
+            "Merchant of Venice",
+            "Othello",
+            "King Lear"
+    };
+    // Try a SUPER quick refresh to make sure we don't get extra refreshes
+    // while the user's finger is still down.
+    private static final boolean SUPER_QUICK_REFRESH = false;
+    private View mContent;
+    private SwipeRefreshLayout mSwipeRefreshWidget;
+    private ListView mList;
+    private Handler mHandler = new Handler();
+    private final Runnable mRefreshDone = new Runnable() {
+
+        @Override
+        public void run() {
+            mSwipeRefreshWidget.setRefreshing(false);
+        }
+
+    };
+    @Override
+    public void onCreate(Bundle bundle) {
+        super.onCreate(bundle);
+        setContentView(R.layout.swipe_refresh_widget_sample);
+        mSwipeRefreshWidget = (SwipeRefreshLayout) findViewById(R.id.swipe_refresh_widget);
+        mSwipeRefreshWidget.setColorScheme(R.color.color1, R.color.color2, R.color.color3,
+                R.color.color4);
+        mList = (ListView) findViewById(R.id.content);
+        ArrayAdapter<String> arrayAdapter = new ArrayAdapter<String>(this,
+                android.R.layout.simple_list_item_1, android.R.id.text1, TITLES);
+        mList.setAdapter(arrayAdapter);
+        mSwipeRefreshWidget.setOnRefreshListener(this);
+    }
+
+    @Override
+    public void onRefresh() {
+        refresh();
+    }
+
+
+    @Override
+    public boolean onCreateOptionsMenu(Menu menu) {
+        MenuInflater inflater = getMenuInflater();
+        inflater.inflate(R.menu.swipe_refresh_menu, menu);
+        return true;
+    }
+
+    /**
+     * Click handler for the menu item to force a refresh.
+     */
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        final int id = item.getItemId();
+        switch(id) {
+            case R.id.force_refresh:
+                mSwipeRefreshWidget.setRefreshing(true);
+                refresh();
+                return true;
+        }
+        return false;
+    }
+
+    private void refresh() {
+        mHandler.removeCallbacks(mRefreshDone);
+        mHandler.postDelayed(mRefreshDone, 1000);
+    }
+}
\ No newline at end of file
diff --git a/samples/browseable/Basic/AndroidManifest.xml b/samples/browseable/ActionBarCompat-Basic/AndroidManifest.xml
similarity index 100%
rename from samples/browseable/Basic/AndroidManifest.xml
rename to samples/browseable/ActionBarCompat-Basic/AndroidManifest.xml
diff --git a/samples/browseable/Basic/_index.jd b/samples/browseable/ActionBarCompat-Basic/_index.jd
similarity index 93%
rename from samples/browseable/Basic/_index.jd
rename to samples/browseable/ActionBarCompat-Basic/_index.jd
index 72cffd9..4e77371 100644
--- a/samples/browseable/Basic/_index.jd
+++ b/samples/browseable/ActionBarCompat-Basic/_index.jd
@@ -1,7 +1,7 @@
 
 
 
-page.tags="Basic ActionBarCompat"
+page.tags="ActionBarCompat-Basic"
 sample.group=UI
 @jd:body
 
diff --git a/samples/browseable/Basic/res/drawable-hdpi/ic_action_location.png b/samples/browseable/ActionBarCompat-Basic/res/drawable-hdpi/ic_action_location.png
similarity index 100%
rename from samples/browseable/Basic/res/drawable-hdpi/ic_action_location.png
rename to samples/browseable/ActionBarCompat-Basic/res/drawable-hdpi/ic_action_location.png
Binary files differ
diff --git a/samples/browseable/Basic/res/drawable-hdpi/ic_action_refresh.png b/samples/browseable/ActionBarCompat-Basic/res/drawable-hdpi/ic_action_refresh.png
similarity index 100%
rename from samples/browseable/Basic/res/drawable-hdpi/ic_action_refresh.png
rename to samples/browseable/ActionBarCompat-Basic/res/drawable-hdpi/ic_action_refresh.png
Binary files differ
diff --git a/samples/browseable/Basic/res/drawable-hdpi/ic_action_settings.png b/samples/browseable/ActionBarCompat-Basic/res/drawable-hdpi/ic_action_settings.png
similarity index 100%
rename from samples/browseable/Basic/res/drawable-hdpi/ic_action_settings.png
rename to samples/browseable/ActionBarCompat-Basic/res/drawable-hdpi/ic_action_settings.png
Binary files differ
diff --git a/samples/browseable/Basic/res/drawable-hdpi/ic_launcher.png b/samples/browseable/ActionBarCompat-Basic/res/drawable-hdpi/ic_launcher.png
similarity index 100%
rename from samples/browseable/Basic/res/drawable-hdpi/ic_launcher.png
rename to samples/browseable/ActionBarCompat-Basic/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/Basic/res/drawable-hdpi/tile.9.png b/samples/browseable/ActionBarCompat-Basic/res/drawable-hdpi/tile.9.png
similarity index 100%
copy from samples/browseable/Basic/res/drawable-hdpi/tile.9.png
copy to samples/browseable/ActionBarCompat-Basic/res/drawable-hdpi/tile.9.png
Binary files differ
diff --git a/samples/browseable/Basic/res/drawable-mdpi/ic_action_location.png b/samples/browseable/ActionBarCompat-Basic/res/drawable-mdpi/ic_action_location.png
similarity index 100%
rename from samples/browseable/Basic/res/drawable-mdpi/ic_action_location.png
rename to samples/browseable/ActionBarCompat-Basic/res/drawable-mdpi/ic_action_location.png
Binary files differ
diff --git a/samples/browseable/Basic/res/drawable-mdpi/ic_action_refresh.png b/samples/browseable/ActionBarCompat-Basic/res/drawable-mdpi/ic_action_refresh.png
similarity index 100%
rename from samples/browseable/Basic/res/drawable-mdpi/ic_action_refresh.png
rename to samples/browseable/ActionBarCompat-Basic/res/drawable-mdpi/ic_action_refresh.png
Binary files differ
diff --git a/samples/browseable/Basic/res/drawable-mdpi/ic_action_settings.png b/samples/browseable/ActionBarCompat-Basic/res/drawable-mdpi/ic_action_settings.png
similarity index 100%
rename from samples/browseable/Basic/res/drawable-mdpi/ic_action_settings.png
rename to samples/browseable/ActionBarCompat-Basic/res/drawable-mdpi/ic_action_settings.png
Binary files differ
diff --git a/samples/browseable/Basic/res/drawable-mdpi/ic_launcher.png b/samples/browseable/ActionBarCompat-Basic/res/drawable-mdpi/ic_launcher.png
similarity index 100%
rename from samples/browseable/Basic/res/drawable-mdpi/ic_launcher.png
rename to samples/browseable/ActionBarCompat-Basic/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/Basic/res/drawable-xhdpi/ic_action_location.png b/samples/browseable/ActionBarCompat-Basic/res/drawable-xhdpi/ic_action_location.png
similarity index 100%
rename from samples/browseable/Basic/res/drawable-xhdpi/ic_action_location.png
rename to samples/browseable/ActionBarCompat-Basic/res/drawable-xhdpi/ic_action_location.png
Binary files differ
diff --git a/samples/browseable/Basic/res/drawable-xhdpi/ic_action_refresh.png b/samples/browseable/ActionBarCompat-Basic/res/drawable-xhdpi/ic_action_refresh.png
similarity index 100%
rename from samples/browseable/Basic/res/drawable-xhdpi/ic_action_refresh.png
rename to samples/browseable/ActionBarCompat-Basic/res/drawable-xhdpi/ic_action_refresh.png
Binary files differ
diff --git a/samples/browseable/Basic/res/drawable-xhdpi/ic_action_settings.png b/samples/browseable/ActionBarCompat-Basic/res/drawable-xhdpi/ic_action_settings.png
similarity index 100%
rename from samples/browseable/Basic/res/drawable-xhdpi/ic_action_settings.png
rename to samples/browseable/ActionBarCompat-Basic/res/drawable-xhdpi/ic_action_settings.png
Binary files differ
diff --git a/samples/browseable/Basic/res/drawable-xhdpi/ic_launcher.png b/samples/browseable/ActionBarCompat-Basic/res/drawable-xhdpi/ic_launcher.png
similarity index 100%
rename from samples/browseable/Basic/res/drawable-xhdpi/ic_launcher.png
rename to samples/browseable/ActionBarCompat-Basic/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/Basic/res/drawable-xxhdpi/ic_launcher.png b/samples/browseable/ActionBarCompat-Basic/res/drawable-xxhdpi/ic_launcher.png
similarity index 100%
rename from samples/browseable/Basic/res/drawable-xxhdpi/ic_launcher.png
rename to samples/browseable/ActionBarCompat-Basic/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/Basic/res/layout/activity_main.xml b/samples/browseable/ActionBarCompat-Basic/res/layout/activity_main.xml
similarity index 100%
copy from samples/browseable/Basic/res/layout/activity_main.xml
copy to samples/browseable/ActionBarCompat-Basic/res/layout/activity_main.xml
diff --git a/samples/browseable/Basic/res/layout/sample_main.xml b/samples/browseable/ActionBarCompat-Basic/res/layout/sample_main.xml
similarity index 100%
rename from samples/browseable/Basic/res/layout/sample_main.xml
rename to samples/browseable/ActionBarCompat-Basic/res/layout/sample_main.xml
diff --git a/samples/browseable/Basic/res/menu/main.xml b/samples/browseable/ActionBarCompat-Basic/res/menu/main.xml
similarity index 100%
rename from samples/browseable/Basic/res/menu/main.xml
rename to samples/browseable/ActionBarCompat-Basic/res/menu/main.xml
diff --git a/samples/browseable/Basic/res/values-sw600dp/dimens.xml b/samples/browseable/ActionBarCompat-Basic/res/values-sw600dp/template-dimens.xml
similarity index 100%
copy from samples/browseable/Basic/res/values-sw600dp/dimens.xml
copy to samples/browseable/ActionBarCompat-Basic/res/values-sw600dp/template-dimens.xml
diff --git a/samples/browseable/Basic/res/values-sw600dp/styles.xml b/samples/browseable/ActionBarCompat-Basic/res/values-sw600dp/template-styles.xml
similarity index 100%
copy from samples/browseable/Basic/res/values-sw600dp/styles.xml
copy to samples/browseable/ActionBarCompat-Basic/res/values-sw600dp/template-styles.xml
diff --git a/samples/browseable/Basic/res/values/base-strings.xml b/samples/browseable/ActionBarCompat-Basic/res/values/base-strings.xml
similarity index 94%
rename from samples/browseable/Basic/res/values/base-strings.xml
rename to samples/browseable/ActionBarCompat-Basic/res/values/base-strings.xml
index ff084ef..8edd1b2 100644
--- a/samples/browseable/Basic/res/values/base-strings.xml
+++ b/samples/browseable/ActionBarCompat-Basic/res/values/base-strings.xml
@@ -18,7 +18,7 @@
 
 
 <resources>
-    <string name="app_name">Basic</string>
+    <string name="app_name">ActionBarCompat-Basic</string>
     <string name="intro_message">
         <![CDATA[
         
diff --git a/samples/browseable/Basic/res/values/ids.xml b/samples/browseable/ActionBarCompat-Basic/res/values/ids.xml
similarity index 100%
rename from samples/browseable/Basic/res/values/ids.xml
rename to samples/browseable/ActionBarCompat-Basic/res/values/ids.xml
diff --git a/samples/browseable/Basic/res/values/strings.xml b/samples/browseable/ActionBarCompat-Basic/res/values/strings.xml
similarity index 100%
rename from samples/browseable/Basic/res/values/strings.xml
rename to samples/browseable/ActionBarCompat-Basic/res/values/strings.xml
diff --git a/samples/browseable/Basic/res/values/dimens.xml b/samples/browseable/ActionBarCompat-Basic/res/values/template-dimens.xml
similarity index 100%
copy from samples/browseable/Basic/res/values/dimens.xml
copy to samples/browseable/ActionBarCompat-Basic/res/values/template-dimens.xml
diff --git a/samples/browseable/Basic/res/values/styles.xml b/samples/browseable/ActionBarCompat-Basic/res/values/template-styles.xml
similarity index 100%
copy from samples/browseable/Basic/res/values/styles.xml
copy to samples/browseable/ActionBarCompat-Basic/res/values/template-styles.xml
diff --git a/samples/browseable/Basic/src/com.example.android.actionbarcompat.basic/MainActivity.java b/samples/browseable/ActionBarCompat-Basic/src/com.example.android.actionbarcompat.basic/MainActivity.java
similarity index 100%
rename from samples/browseable/Basic/src/com.example.android.actionbarcompat.basic/MainActivity.java
rename to samples/browseable/ActionBarCompat-Basic/src/com.example.android.actionbarcompat.basic/MainActivity.java
diff --git a/samples/browseable/ListPopupMenu/AndroidManifest.xml b/samples/browseable/ActionBarCompat-ListPopupMenu/AndroidManifest.xml
similarity index 100%
rename from samples/browseable/ListPopupMenu/AndroidManifest.xml
rename to samples/browseable/ActionBarCompat-ListPopupMenu/AndroidManifest.xml
diff --git a/samples/browseable/ListPopupMenu/_index.jd b/samples/browseable/ActionBarCompat-ListPopupMenu/_index.jd
similarity index 90%
rename from samples/browseable/ListPopupMenu/_index.jd
rename to samples/browseable/ActionBarCompat-ListPopupMenu/_index.jd
index 36090e0..9da5bdd 100644
--- a/samples/browseable/ListPopupMenu/_index.jd
+++ b/samples/browseable/ActionBarCompat-ListPopupMenu/_index.jd
@@ -1,7 +1,7 @@
 
 
 
-page.tags="ListPopupMenu"
+page.tags="ActionBarCompat-ListPopupMenu"
 sample.group=UI
 @jd:body
 
diff --git a/samples/browseable/ListPopupMenu/res/drawable-hdpi/ic_launcher.png b/samples/browseable/ActionBarCompat-ListPopupMenu/res/drawable-hdpi/ic_launcher.png
similarity index 100%
rename from samples/browseable/ListPopupMenu/res/drawable-hdpi/ic_launcher.png
rename to samples/browseable/ActionBarCompat-ListPopupMenu/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/ListPopupMenu/res/drawable-hdpi/ic_overflow.png b/samples/browseable/ActionBarCompat-ListPopupMenu/res/drawable-hdpi/ic_overflow.png
similarity index 100%
rename from samples/browseable/ListPopupMenu/res/drawable-hdpi/ic_overflow.png
rename to samples/browseable/ActionBarCompat-ListPopupMenu/res/drawable-hdpi/ic_overflow.png
Binary files differ
diff --git a/samples/browseable/ListPopupMenu/res/drawable-hdpi/tile.9.png b/samples/browseable/ActionBarCompat-ListPopupMenu/res/drawable-hdpi/tile.9.png
similarity index 100%
rename from samples/browseable/ListPopupMenu/res/drawable-hdpi/tile.9.png
rename to samples/browseable/ActionBarCompat-ListPopupMenu/res/drawable-hdpi/tile.9.png
Binary files differ
diff --git a/samples/browseable/ListPopupMenu/res/drawable-mdpi/ic_launcher.png b/samples/browseable/ActionBarCompat-ListPopupMenu/res/drawable-mdpi/ic_launcher.png
similarity index 100%
rename from samples/browseable/ListPopupMenu/res/drawable-mdpi/ic_launcher.png
rename to samples/browseable/ActionBarCompat-ListPopupMenu/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/ListPopupMenu/res/drawable-mdpi/ic_overflow.png b/samples/browseable/ActionBarCompat-ListPopupMenu/res/drawable-mdpi/ic_overflow.png
similarity index 100%
rename from samples/browseable/ListPopupMenu/res/drawable-mdpi/ic_overflow.png
rename to samples/browseable/ActionBarCompat-ListPopupMenu/res/drawable-mdpi/ic_overflow.png
Binary files differ
diff --git a/samples/browseable/ListPopupMenu/res/drawable-xhdpi/ic_launcher.png b/samples/browseable/ActionBarCompat-ListPopupMenu/res/drawable-xhdpi/ic_launcher.png
similarity index 100%
rename from samples/browseable/ListPopupMenu/res/drawable-xhdpi/ic_launcher.png
rename to samples/browseable/ActionBarCompat-ListPopupMenu/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/ListPopupMenu/res/drawable-xhdpi/ic_overflow.png b/samples/browseable/ActionBarCompat-ListPopupMenu/res/drawable-xhdpi/ic_overflow.png
similarity index 100%
rename from samples/browseable/ListPopupMenu/res/drawable-xhdpi/ic_overflow.png
rename to samples/browseable/ActionBarCompat-ListPopupMenu/res/drawable-xhdpi/ic_overflow.png
Binary files differ
diff --git a/samples/browseable/ListPopupMenu/res/drawable-xxhdpi/ic_launcher.png b/samples/browseable/ActionBarCompat-ListPopupMenu/res/drawable-xxhdpi/ic_launcher.png
similarity index 100%
rename from samples/browseable/ListPopupMenu/res/drawable-xxhdpi/ic_launcher.png
rename to samples/browseable/ActionBarCompat-ListPopupMenu/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/ListPopupMenu/res/layout/activity_main.xml b/samples/browseable/ActionBarCompat-ListPopupMenu/res/layout/activity_main.xml
similarity index 100%
rename from samples/browseable/ListPopupMenu/res/layout/activity_main.xml
rename to samples/browseable/ActionBarCompat-ListPopupMenu/res/layout/activity_main.xml
diff --git a/samples/browseable/ListPopupMenu/res/layout/list_item.xml b/samples/browseable/ActionBarCompat-ListPopupMenu/res/layout/list_item.xml
similarity index 100%
rename from samples/browseable/ListPopupMenu/res/layout/list_item.xml
rename to samples/browseable/ActionBarCompat-ListPopupMenu/res/layout/list_item.xml
diff --git a/samples/browseable/ListPopupMenu/res/layout/sample_main.xml b/samples/browseable/ActionBarCompat-ListPopupMenu/res/layout/sample_main.xml
similarity index 100%
rename from samples/browseable/ListPopupMenu/res/layout/sample_main.xml
rename to samples/browseable/ActionBarCompat-ListPopupMenu/res/layout/sample_main.xml
diff --git a/samples/browseable/ListPopupMenu/res/menu/popup.xml b/samples/browseable/ActionBarCompat-ListPopupMenu/res/menu/popup.xml
similarity index 100%
rename from samples/browseable/ListPopupMenu/res/menu/popup.xml
rename to samples/browseable/ActionBarCompat-ListPopupMenu/res/menu/popup.xml
diff --git a/samples/browseable/ListPopupMenu/res/values-sw600dp/dimens.xml b/samples/browseable/ActionBarCompat-ListPopupMenu/res/values-sw600dp/template-dimens.xml
similarity index 100%
rename from samples/browseable/ListPopupMenu/res/values-sw600dp/dimens.xml
rename to samples/browseable/ActionBarCompat-ListPopupMenu/res/values-sw600dp/template-dimens.xml
diff --git a/samples/browseable/ListPopupMenu/res/values-sw600dp/styles.xml b/samples/browseable/ActionBarCompat-ListPopupMenu/res/values-sw600dp/template-styles.xml
similarity index 100%
rename from samples/browseable/ListPopupMenu/res/values-sw600dp/styles.xml
rename to samples/browseable/ActionBarCompat-ListPopupMenu/res/values-sw600dp/template-styles.xml
diff --git a/samples/browseable/ListPopupMenu/res/values/base-strings.xml b/samples/browseable/ActionBarCompat-ListPopupMenu/res/values/base-strings.xml
similarity index 93%
rename from samples/browseable/ListPopupMenu/res/values/base-strings.xml
rename to samples/browseable/ActionBarCompat-ListPopupMenu/res/values/base-strings.xml
index a23ed75..130e2da 100644
--- a/samples/browseable/ListPopupMenu/res/values/base-strings.xml
+++ b/samples/browseable/ActionBarCompat-ListPopupMenu/res/values/base-strings.xml
@@ -18,7 +18,7 @@
 
 
 <resources>
-    <string name="app_name">ListPopupMenu</string>
+    <string name="app_name">ActionBarCompat-ListPopupMenu</string>
     <string name="intro_message">
         <![CDATA[
         
diff --git a/samples/browseable/ListPopupMenu/res/values/strings.xml b/samples/browseable/ActionBarCompat-ListPopupMenu/res/values/strings.xml
similarity index 100%
rename from samples/browseable/ListPopupMenu/res/values/strings.xml
rename to samples/browseable/ActionBarCompat-ListPopupMenu/res/values/strings.xml
diff --git a/samples/browseable/ListPopupMenu/res/values/dimens.xml b/samples/browseable/ActionBarCompat-ListPopupMenu/res/values/template-dimens.xml
similarity index 100%
rename from samples/browseable/ListPopupMenu/res/values/dimens.xml
rename to samples/browseable/ActionBarCompat-ListPopupMenu/res/values/template-dimens.xml
diff --git a/samples/browseable/ListPopupMenu/res/values/styles.xml b/samples/browseable/ActionBarCompat-ListPopupMenu/res/values/template-styles.xml
similarity index 100%
rename from samples/browseable/ListPopupMenu/res/values/styles.xml
rename to samples/browseable/ActionBarCompat-ListPopupMenu/res/values/template-styles.xml
diff --git a/samples/browseable/ListPopupMenu/src/com.example.android.actionbarcompat.listpopupmenu/Cheeses.java b/samples/browseable/ActionBarCompat-ListPopupMenu/src/com.example.android.actionbarcompat.listpopupmenu/Cheeses.java
similarity index 100%
rename from samples/browseable/ListPopupMenu/src/com.example.android.actionbarcompat.listpopupmenu/Cheeses.java
rename to samples/browseable/ActionBarCompat-ListPopupMenu/src/com.example.android.actionbarcompat.listpopupmenu/Cheeses.java
diff --git a/samples/browseable/ListPopupMenu/src/com.example.android.actionbarcompat.listpopupmenu/MainActivity.java b/samples/browseable/ActionBarCompat-ListPopupMenu/src/com.example.android.actionbarcompat.listpopupmenu/MainActivity.java
similarity index 100%
rename from samples/browseable/ListPopupMenu/src/com.example.android.actionbarcompat.listpopupmenu/MainActivity.java
rename to samples/browseable/ActionBarCompat-ListPopupMenu/src/com.example.android.actionbarcompat.listpopupmenu/MainActivity.java
diff --git a/samples/browseable/ListPopupMenu/src/com.example.android.actionbarcompat.listpopupmenu/PopupListFragment.java b/samples/browseable/ActionBarCompat-ListPopupMenu/src/com.example.android.actionbarcompat.listpopupmenu/PopupListFragment.java
similarity index 100%
rename from samples/browseable/ListPopupMenu/src/com.example.android.actionbarcompat.listpopupmenu/PopupListFragment.java
rename to samples/browseable/ActionBarCompat-ListPopupMenu/src/com.example.android.actionbarcompat.listpopupmenu/PopupListFragment.java
diff --git a/samples/browseable/ShareActionProvider/AndroidManifest.xml b/samples/browseable/ActionBarCompat-ShareActionProvider/AndroidManifest.xml
similarity index 100%
rename from samples/browseable/ShareActionProvider/AndroidManifest.xml
rename to samples/browseable/ActionBarCompat-ShareActionProvider/AndroidManifest.xml
diff --git a/samples/browseable/ShareActionProvider/_index.jd b/samples/browseable/ActionBarCompat-ShareActionProvider/_index.jd
similarity index 88%
rename from samples/browseable/ShareActionProvider/_index.jd
rename to samples/browseable/ActionBarCompat-ShareActionProvider/_index.jd
index 31d855e..63ac59a 100644
--- a/samples/browseable/ShareActionProvider/_index.jd
+++ b/samples/browseable/ActionBarCompat-ShareActionProvider/_index.jd
@@ -1,7 +1,7 @@
 
 
 
-page.tags="ShareActionProvider"
+page.tags="ActionBarCompat-ShareActionProvider"
 sample.group=UI
 @jd:body
 
diff --git a/samples/browseable/ShareActionProvider/res/drawable-hdpi/ic_launcher.png b/samples/browseable/ActionBarCompat-ShareActionProvider/res/drawable-hdpi/ic_launcher.png
similarity index 100%
rename from samples/browseable/ShareActionProvider/res/drawable-hdpi/ic_launcher.png
rename to samples/browseable/ActionBarCompat-ShareActionProvider/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/ShareActionProvider/res/drawable-hdpi/tile.9.png b/samples/browseable/ActionBarCompat-ShareActionProvider/res/drawable-hdpi/tile.9.png
similarity index 100%
rename from samples/browseable/ShareActionProvider/res/drawable-hdpi/tile.9.png
rename to samples/browseable/ActionBarCompat-ShareActionProvider/res/drawable-hdpi/tile.9.png
Binary files differ
diff --git a/samples/browseable/ShareActionProvider/res/drawable-mdpi/ic_launcher.png b/samples/browseable/ActionBarCompat-ShareActionProvider/res/drawable-mdpi/ic_launcher.png
similarity index 100%
rename from samples/browseable/ShareActionProvider/res/drawable-mdpi/ic_launcher.png
rename to samples/browseable/ActionBarCompat-ShareActionProvider/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/ShareActionProvider/res/drawable-xhdpi/ic_launcher.png b/samples/browseable/ActionBarCompat-ShareActionProvider/res/drawable-xhdpi/ic_launcher.png
similarity index 100%
rename from samples/browseable/ShareActionProvider/res/drawable-xhdpi/ic_launcher.png
rename to samples/browseable/ActionBarCompat-ShareActionProvider/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/ShareActionProvider/res/drawable-xxhdpi/ic_launcher.png b/samples/browseable/ActionBarCompat-ShareActionProvider/res/drawable-xxhdpi/ic_launcher.png
similarity index 100%
rename from samples/browseable/ShareActionProvider/res/drawable-xxhdpi/ic_launcher.png
rename to samples/browseable/ActionBarCompat-ShareActionProvider/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/ShareActionProvider/res/layout/activity_main.xml b/samples/browseable/ActionBarCompat-ShareActionProvider/res/layout/activity_main.xml
similarity index 100%
rename from samples/browseable/ShareActionProvider/res/layout/activity_main.xml
rename to samples/browseable/ActionBarCompat-ShareActionProvider/res/layout/activity_main.xml
diff --git a/samples/browseable/ShareActionProvider/res/layout/item_image.xml b/samples/browseable/ActionBarCompat-ShareActionProvider/res/layout/item_image.xml
similarity index 100%
rename from samples/browseable/ShareActionProvider/res/layout/item_image.xml
rename to samples/browseable/ActionBarCompat-ShareActionProvider/res/layout/item_image.xml
diff --git a/samples/browseable/ShareActionProvider/res/layout/item_text.xml b/samples/browseable/ActionBarCompat-ShareActionProvider/res/layout/item_text.xml
similarity index 100%
rename from samples/browseable/ShareActionProvider/res/layout/item_text.xml
rename to samples/browseable/ActionBarCompat-ShareActionProvider/res/layout/item_text.xml
diff --git a/samples/browseable/ShareActionProvider/res/layout/sample_main.xml b/samples/browseable/ActionBarCompat-ShareActionProvider/res/layout/sample_main.xml
similarity index 100%
rename from samples/browseable/ShareActionProvider/res/layout/sample_main.xml
rename to samples/browseable/ActionBarCompat-ShareActionProvider/res/layout/sample_main.xml
diff --git a/samples/browseable/ShareActionProvider/res/menu/main_menu.xml b/samples/browseable/ActionBarCompat-ShareActionProvider/res/menu/main_menu.xml
similarity index 100%
rename from samples/browseable/ShareActionProvider/res/menu/main_menu.xml
rename to samples/browseable/ActionBarCompat-ShareActionProvider/res/menu/main_menu.xml
diff --git a/samples/browseable/ShareActionProvider/res/values-sw600dp/dimens.xml b/samples/browseable/ActionBarCompat-ShareActionProvider/res/values-sw600dp/template-dimens.xml
similarity index 100%
rename from samples/browseable/ShareActionProvider/res/values-sw600dp/dimens.xml
rename to samples/browseable/ActionBarCompat-ShareActionProvider/res/values-sw600dp/template-dimens.xml
diff --git a/samples/browseable/ShareActionProvider/res/values-sw600dp/styles.xml b/samples/browseable/ActionBarCompat-ShareActionProvider/res/values-sw600dp/template-styles.xml
similarity index 100%
rename from samples/browseable/ShareActionProvider/res/values-sw600dp/styles.xml
rename to samples/browseable/ActionBarCompat-ShareActionProvider/res/values-sw600dp/template-styles.xml
diff --git a/samples/browseable/ShareActionProvider/res/values/base-strings.xml b/samples/browseable/ActionBarCompat-ShareActionProvider/res/values/base-strings.xml
similarity index 92%
rename from samples/browseable/ShareActionProvider/res/values/base-strings.xml
rename to samples/browseable/ActionBarCompat-ShareActionProvider/res/values/base-strings.xml
index 4ca9558..904f4f1 100644
--- a/samples/browseable/ShareActionProvider/res/values/base-strings.xml
+++ b/samples/browseable/ActionBarCompat-ShareActionProvider/res/values/base-strings.xml
@@ -18,7 +18,7 @@
 
 
 <resources>
-    <string name="app_name">ShareActionProvider</string>
+    <string name="app_name">ActionBarCompat-ShareActionProvider</string>
     <string name="intro_message">
         <![CDATA[
         
diff --git a/samples/browseable/ShareActionProvider/res/values/strings.xml b/samples/browseable/ActionBarCompat-ShareActionProvider/res/values/strings.xml
similarity index 100%
rename from samples/browseable/ShareActionProvider/res/values/strings.xml
rename to samples/browseable/ActionBarCompat-ShareActionProvider/res/values/strings.xml
diff --git a/samples/browseable/ShareActionProvider/res/values/dimens.xml b/samples/browseable/ActionBarCompat-ShareActionProvider/res/values/template-dimens.xml
similarity index 100%
rename from samples/browseable/ShareActionProvider/res/values/dimens.xml
rename to samples/browseable/ActionBarCompat-ShareActionProvider/res/values/template-dimens.xml
diff --git a/samples/browseable/ShareActionProvider/res/values/styles.xml b/samples/browseable/ActionBarCompat-ShareActionProvider/res/values/template-styles.xml
similarity index 100%
rename from samples/browseable/ShareActionProvider/res/values/styles.xml
rename to samples/browseable/ActionBarCompat-ShareActionProvider/res/values/template-styles.xml
diff --git a/samples/browseable/ShareActionProvider/src/com.example.android.actionbarcompat.shareactionprovider/MainActivity.java b/samples/browseable/ActionBarCompat-ShareActionProvider/src/com.example.android.actionbarcompat.shareactionprovider/MainActivity.java
similarity index 100%
rename from samples/browseable/ShareActionProvider/src/com.example.android.actionbarcompat.shareactionprovider/MainActivity.java
rename to samples/browseable/ActionBarCompat-ShareActionProvider/src/com.example.android.actionbarcompat.shareactionprovider/MainActivity.java
diff --git a/samples/browseable/ShareActionProvider/src/com.example.android.actionbarcompat.shareactionprovider/content/AssetProvider.java b/samples/browseable/ActionBarCompat-ShareActionProvider/src/com.example.android.actionbarcompat.shareactionprovider/content/AssetProvider.java
similarity index 100%
rename from samples/browseable/ShareActionProvider/src/com.example.android.actionbarcompat.shareactionprovider/content/AssetProvider.java
rename to samples/browseable/ActionBarCompat-ShareActionProvider/src/com.example.android.actionbarcompat.shareactionprovider/content/AssetProvider.java
diff --git a/samples/browseable/ShareActionProvider/src/com.example.android.actionbarcompat.shareactionprovider/content/ContentItem.java b/samples/browseable/ActionBarCompat-ShareActionProvider/src/com.example.android.actionbarcompat.shareactionprovider/content/ContentItem.java
similarity index 100%
rename from samples/browseable/ShareActionProvider/src/com.example.android.actionbarcompat.shareactionprovider/content/ContentItem.java
rename to samples/browseable/ActionBarCompat-ShareActionProvider/src/com.example.android.actionbarcompat.shareactionprovider/content/ContentItem.java
diff --git a/samples/browseable/Styled/AndroidManifest.xml b/samples/browseable/ActionBarCompat-Styled/AndroidManifest.xml
similarity index 100%
rename from samples/browseable/Styled/AndroidManifest.xml
rename to samples/browseable/ActionBarCompat-Styled/AndroidManifest.xml
diff --git a/samples/browseable/Styled/_index.jd b/samples/browseable/ActionBarCompat-Styled/_index.jd
similarity index 91%
rename from samples/browseable/Styled/_index.jd
rename to samples/browseable/ActionBarCompat-Styled/_index.jd
index 0816197..06fee1a 100644
--- a/samples/browseable/Styled/_index.jd
+++ b/samples/browseable/ActionBarCompat-Styled/_index.jd
@@ -1,7 +1,7 @@
 
 
 
-page.tags="Styled ActionBarCompat"
+page.tags="ActionBarCompat-Styled"
 sample.group=UI
 @jd:body
 
diff --git a/samples/browseable/Styled/res/drawable-hdpi/ab_bottom_solid_styled.9.png b/samples/browseable/ActionBarCompat-Styled/res/drawable-hdpi/ab_bottom_solid_styled.9.png
similarity index 100%
rename from samples/browseable/Styled/res/drawable-hdpi/ab_bottom_solid_styled.9.png
rename to samples/browseable/ActionBarCompat-Styled/res/drawable-hdpi/ab_bottom_solid_styled.9.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-hdpi/ab_solid_styled.9.png b/samples/browseable/ActionBarCompat-Styled/res/drawable-hdpi/ab_solid_styled.9.png
similarity index 100%
rename from samples/browseable/Styled/res/drawable-hdpi/ab_solid_styled.9.png
rename to samples/browseable/ActionBarCompat-Styled/res/drawable-hdpi/ab_solid_styled.9.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-hdpi/ab_stacked_solid_styled.9.png b/samples/browseable/ActionBarCompat-Styled/res/drawable-hdpi/ab_stacked_solid_styled.9.png
similarity index 100%
rename from samples/browseable/Styled/res/drawable-hdpi/ab_stacked_solid_styled.9.png
rename to samples/browseable/ActionBarCompat-Styled/res/drawable-hdpi/ab_stacked_solid_styled.9.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-hdpi/ic_action_location.png b/samples/browseable/ActionBarCompat-Styled/res/drawable-hdpi/ic_action_location.png
similarity index 100%
rename from samples/browseable/Styled/res/drawable-hdpi/ic_action_location.png
rename to samples/browseable/ActionBarCompat-Styled/res/drawable-hdpi/ic_action_location.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-hdpi/ic_action_refresh.png b/samples/browseable/ActionBarCompat-Styled/res/drawable-hdpi/ic_action_refresh.png
similarity index 100%
rename from samples/browseable/Styled/res/drawable-hdpi/ic_action_refresh.png
rename to samples/browseable/ActionBarCompat-Styled/res/drawable-hdpi/ic_action_refresh.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-hdpi/ic_action_settings.png b/samples/browseable/ActionBarCompat-Styled/res/drawable-hdpi/ic_action_settings.png
similarity index 100%
rename from samples/browseable/Styled/res/drawable-hdpi/ic_action_settings.png
rename to samples/browseable/ActionBarCompat-Styled/res/drawable-hdpi/ic_action_settings.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-hdpi/ic_launcher.png b/samples/browseable/ActionBarCompat-Styled/res/drawable-hdpi/ic_launcher.png
similarity index 100%
rename from samples/browseable/Styled/res/drawable-hdpi/ic_launcher.png
rename to samples/browseable/ActionBarCompat-Styled/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-hdpi/list_focused_styled.9.png b/samples/browseable/ActionBarCompat-Styled/res/drawable-hdpi/list_focused_styled.9.png
similarity index 100%
rename from samples/browseable/Styled/res/drawable-hdpi/list_focused_styled.9.png
rename to samples/browseable/ActionBarCompat-Styled/res/drawable-hdpi/list_focused_styled.9.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-hdpi/menu_dropdown_panel_styled.9.png b/samples/browseable/ActionBarCompat-Styled/res/drawable-hdpi/menu_dropdown_panel_styled.9.png
similarity index 100%
rename from samples/browseable/Styled/res/drawable-hdpi/menu_dropdown_panel_styled.9.png
rename to samples/browseable/ActionBarCompat-Styled/res/drawable-hdpi/menu_dropdown_panel_styled.9.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-hdpi/progress_bg_styled.9.png b/samples/browseable/ActionBarCompat-Styled/res/drawable-hdpi/progress_bg_styled.9.png
similarity index 100%
rename from samples/browseable/Styled/res/drawable-hdpi/progress_bg_styled.9.png
rename to samples/browseable/ActionBarCompat-Styled/res/drawable-hdpi/progress_bg_styled.9.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-hdpi/progress_primary_styled.9.png b/samples/browseable/ActionBarCompat-Styled/res/drawable-hdpi/progress_primary_styled.9.png
similarity index 100%
rename from samples/browseable/Styled/res/drawable-hdpi/progress_primary_styled.9.png
rename to samples/browseable/ActionBarCompat-Styled/res/drawable-hdpi/progress_primary_styled.9.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-hdpi/progress_secondary_styled.9.png b/samples/browseable/ActionBarCompat-Styled/res/drawable-hdpi/progress_secondary_styled.9.png
similarity index 100%
rename from samples/browseable/Styled/res/drawable-hdpi/progress_secondary_styled.9.png
rename to samples/browseable/ActionBarCompat-Styled/res/drawable-hdpi/progress_secondary_styled.9.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-hdpi/spinner_ab_default_styled.9.png b/samples/browseable/ActionBarCompat-Styled/res/drawable-hdpi/spinner_ab_default_styled.9.png
similarity index 100%
rename from samples/browseable/Styled/res/drawable-hdpi/spinner_ab_default_styled.9.png
rename to samples/browseable/ActionBarCompat-Styled/res/drawable-hdpi/spinner_ab_default_styled.9.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-hdpi/spinner_ab_disabled_styled.9.png b/samples/browseable/ActionBarCompat-Styled/res/drawable-hdpi/spinner_ab_disabled_styled.9.png
similarity index 100%
rename from samples/browseable/Styled/res/drawable-hdpi/spinner_ab_disabled_styled.9.png
rename to samples/browseable/ActionBarCompat-Styled/res/drawable-hdpi/spinner_ab_disabled_styled.9.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-hdpi/spinner_ab_focused_styled.9.png b/samples/browseable/ActionBarCompat-Styled/res/drawable-hdpi/spinner_ab_focused_styled.9.png
similarity index 100%
rename from samples/browseable/Styled/res/drawable-hdpi/spinner_ab_focused_styled.9.png
rename to samples/browseable/ActionBarCompat-Styled/res/drawable-hdpi/spinner_ab_focused_styled.9.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-hdpi/spinner_ab_pressed_styled.9.png b/samples/browseable/ActionBarCompat-Styled/res/drawable-hdpi/spinner_ab_pressed_styled.9.png
similarity index 100%
rename from samples/browseable/Styled/res/drawable-hdpi/spinner_ab_pressed_styled.9.png
rename to samples/browseable/ActionBarCompat-Styled/res/drawable-hdpi/spinner_ab_pressed_styled.9.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-hdpi/tab_selected_focused_styled.9.png b/samples/browseable/ActionBarCompat-Styled/res/drawable-hdpi/tab_selected_focused_styled.9.png
similarity index 100%
rename from samples/browseable/Styled/res/drawable-hdpi/tab_selected_focused_styled.9.png
rename to samples/browseable/ActionBarCompat-Styled/res/drawable-hdpi/tab_selected_focused_styled.9.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-hdpi/tab_selected_pressed_styled.9.png b/samples/browseable/ActionBarCompat-Styled/res/drawable-hdpi/tab_selected_pressed_styled.9.png
similarity index 100%
rename from samples/browseable/Styled/res/drawable-hdpi/tab_selected_pressed_styled.9.png
rename to samples/browseable/ActionBarCompat-Styled/res/drawable-hdpi/tab_selected_pressed_styled.9.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-hdpi/tab_selected_styled.9.png b/samples/browseable/ActionBarCompat-Styled/res/drawable-hdpi/tab_selected_styled.9.png
similarity index 100%
rename from samples/browseable/Styled/res/drawable-hdpi/tab_selected_styled.9.png
rename to samples/browseable/ActionBarCompat-Styled/res/drawable-hdpi/tab_selected_styled.9.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-hdpi/tab_unselected_focused_styled.9.png b/samples/browseable/ActionBarCompat-Styled/res/drawable-hdpi/tab_unselected_focused_styled.9.png
similarity index 100%
rename from samples/browseable/Styled/res/drawable-hdpi/tab_unselected_focused_styled.9.png
rename to samples/browseable/ActionBarCompat-Styled/res/drawable-hdpi/tab_unselected_focused_styled.9.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-hdpi/tab_unselected_pressed_styled.9.png b/samples/browseable/ActionBarCompat-Styled/res/drawable-hdpi/tab_unselected_pressed_styled.9.png
similarity index 100%
rename from samples/browseable/Styled/res/drawable-hdpi/tab_unselected_pressed_styled.9.png
rename to samples/browseable/ActionBarCompat-Styled/res/drawable-hdpi/tab_unselected_pressed_styled.9.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-hdpi/tile.9.png b/samples/browseable/ActionBarCompat-Styled/res/drawable-hdpi/tile.9.png
similarity index 100%
rename from samples/browseable/Styled/res/drawable-hdpi/tile.9.png
rename to samples/browseable/ActionBarCompat-Styled/res/drawable-hdpi/tile.9.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-mdpi/ab_bottom_solid_styled.9.png b/samples/browseable/ActionBarCompat-Styled/res/drawable-mdpi/ab_bottom_solid_styled.9.png
similarity index 100%
rename from samples/browseable/Styled/res/drawable-mdpi/ab_bottom_solid_styled.9.png
rename to samples/browseable/ActionBarCompat-Styled/res/drawable-mdpi/ab_bottom_solid_styled.9.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-mdpi/ab_solid_styled.9.png b/samples/browseable/ActionBarCompat-Styled/res/drawable-mdpi/ab_solid_styled.9.png
similarity index 100%
rename from samples/browseable/Styled/res/drawable-mdpi/ab_solid_styled.9.png
rename to samples/browseable/ActionBarCompat-Styled/res/drawable-mdpi/ab_solid_styled.9.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-mdpi/ab_stacked_solid_styled.9.png b/samples/browseable/ActionBarCompat-Styled/res/drawable-mdpi/ab_stacked_solid_styled.9.png
similarity index 100%
rename from samples/browseable/Styled/res/drawable-mdpi/ab_stacked_solid_styled.9.png
rename to samples/browseable/ActionBarCompat-Styled/res/drawable-mdpi/ab_stacked_solid_styled.9.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-mdpi/ic_action_location.png b/samples/browseable/ActionBarCompat-Styled/res/drawable-mdpi/ic_action_location.png
similarity index 100%
rename from samples/browseable/Styled/res/drawable-mdpi/ic_action_location.png
rename to samples/browseable/ActionBarCompat-Styled/res/drawable-mdpi/ic_action_location.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-mdpi/ic_action_refresh.png b/samples/browseable/ActionBarCompat-Styled/res/drawable-mdpi/ic_action_refresh.png
similarity index 100%
rename from samples/browseable/Styled/res/drawable-mdpi/ic_action_refresh.png
rename to samples/browseable/ActionBarCompat-Styled/res/drawable-mdpi/ic_action_refresh.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-mdpi/ic_action_settings.png b/samples/browseable/ActionBarCompat-Styled/res/drawable-mdpi/ic_action_settings.png
similarity index 100%
rename from samples/browseable/Styled/res/drawable-mdpi/ic_action_settings.png
rename to samples/browseable/ActionBarCompat-Styled/res/drawable-mdpi/ic_action_settings.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-mdpi/ic_launcher.png b/samples/browseable/ActionBarCompat-Styled/res/drawable-mdpi/ic_launcher.png
similarity index 100%
rename from samples/browseable/Styled/res/drawable-mdpi/ic_launcher.png
rename to samples/browseable/ActionBarCompat-Styled/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-mdpi/list_focused_styled.9.png b/samples/browseable/ActionBarCompat-Styled/res/drawable-mdpi/list_focused_styled.9.png
similarity index 100%
rename from samples/browseable/Styled/res/drawable-mdpi/list_focused_styled.9.png
rename to samples/browseable/ActionBarCompat-Styled/res/drawable-mdpi/list_focused_styled.9.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-mdpi/menu_dropdown_panel_styled.9.png b/samples/browseable/ActionBarCompat-Styled/res/drawable-mdpi/menu_dropdown_panel_styled.9.png
similarity index 100%
rename from samples/browseable/Styled/res/drawable-mdpi/menu_dropdown_panel_styled.9.png
rename to samples/browseable/ActionBarCompat-Styled/res/drawable-mdpi/menu_dropdown_panel_styled.9.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-mdpi/progress_bg_styled.9.png b/samples/browseable/ActionBarCompat-Styled/res/drawable-mdpi/progress_bg_styled.9.png
similarity index 100%
rename from samples/browseable/Styled/res/drawable-mdpi/progress_bg_styled.9.png
rename to samples/browseable/ActionBarCompat-Styled/res/drawable-mdpi/progress_bg_styled.9.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-mdpi/progress_primary_styled.9.png b/samples/browseable/ActionBarCompat-Styled/res/drawable-mdpi/progress_primary_styled.9.png
similarity index 100%
rename from samples/browseable/Styled/res/drawable-mdpi/progress_primary_styled.9.png
rename to samples/browseable/ActionBarCompat-Styled/res/drawable-mdpi/progress_primary_styled.9.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-mdpi/progress_secondary_styled.9.png b/samples/browseable/ActionBarCompat-Styled/res/drawable-mdpi/progress_secondary_styled.9.png
similarity index 100%
rename from samples/browseable/Styled/res/drawable-mdpi/progress_secondary_styled.9.png
rename to samples/browseable/ActionBarCompat-Styled/res/drawable-mdpi/progress_secondary_styled.9.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-mdpi/spinner_ab_default_styled.9.png b/samples/browseable/ActionBarCompat-Styled/res/drawable-mdpi/spinner_ab_default_styled.9.png
similarity index 100%
rename from samples/browseable/Styled/res/drawable-mdpi/spinner_ab_default_styled.9.png
rename to samples/browseable/ActionBarCompat-Styled/res/drawable-mdpi/spinner_ab_default_styled.9.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-mdpi/spinner_ab_disabled_styled.9.png b/samples/browseable/ActionBarCompat-Styled/res/drawable-mdpi/spinner_ab_disabled_styled.9.png
similarity index 100%
rename from samples/browseable/Styled/res/drawable-mdpi/spinner_ab_disabled_styled.9.png
rename to samples/browseable/ActionBarCompat-Styled/res/drawable-mdpi/spinner_ab_disabled_styled.9.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-mdpi/spinner_ab_focused_styled.9.png b/samples/browseable/ActionBarCompat-Styled/res/drawable-mdpi/spinner_ab_focused_styled.9.png
similarity index 100%
rename from samples/browseable/Styled/res/drawable-mdpi/spinner_ab_focused_styled.9.png
rename to samples/browseable/ActionBarCompat-Styled/res/drawable-mdpi/spinner_ab_focused_styled.9.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-mdpi/spinner_ab_pressed_styled.9.png b/samples/browseable/ActionBarCompat-Styled/res/drawable-mdpi/spinner_ab_pressed_styled.9.png
similarity index 100%
rename from samples/browseable/Styled/res/drawable-mdpi/spinner_ab_pressed_styled.9.png
rename to samples/browseable/ActionBarCompat-Styled/res/drawable-mdpi/spinner_ab_pressed_styled.9.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-mdpi/tab_selected_focused_styled.9.png b/samples/browseable/ActionBarCompat-Styled/res/drawable-mdpi/tab_selected_focused_styled.9.png
similarity index 100%
rename from samples/browseable/Styled/res/drawable-mdpi/tab_selected_focused_styled.9.png
rename to samples/browseable/ActionBarCompat-Styled/res/drawable-mdpi/tab_selected_focused_styled.9.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-mdpi/tab_selected_pressed_styled.9.png b/samples/browseable/ActionBarCompat-Styled/res/drawable-mdpi/tab_selected_pressed_styled.9.png
similarity index 100%
rename from samples/browseable/Styled/res/drawable-mdpi/tab_selected_pressed_styled.9.png
rename to samples/browseable/ActionBarCompat-Styled/res/drawable-mdpi/tab_selected_pressed_styled.9.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-mdpi/tab_selected_styled.9.png b/samples/browseable/ActionBarCompat-Styled/res/drawable-mdpi/tab_selected_styled.9.png
similarity index 100%
rename from samples/browseable/Styled/res/drawable-mdpi/tab_selected_styled.9.png
rename to samples/browseable/ActionBarCompat-Styled/res/drawable-mdpi/tab_selected_styled.9.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-mdpi/tab_unselected_focused_styled.9.png b/samples/browseable/ActionBarCompat-Styled/res/drawable-mdpi/tab_unselected_focused_styled.9.png
similarity index 100%
rename from samples/browseable/Styled/res/drawable-mdpi/tab_unselected_focused_styled.9.png
rename to samples/browseable/ActionBarCompat-Styled/res/drawable-mdpi/tab_unselected_focused_styled.9.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-mdpi/tab_unselected_pressed_styled.9.png b/samples/browseable/ActionBarCompat-Styled/res/drawable-mdpi/tab_unselected_pressed_styled.9.png
similarity index 100%
rename from samples/browseable/Styled/res/drawable-mdpi/tab_unselected_pressed_styled.9.png
rename to samples/browseable/ActionBarCompat-Styled/res/drawable-mdpi/tab_unselected_pressed_styled.9.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-xhdpi/ab_bottom_solid_styled.9.png b/samples/browseable/ActionBarCompat-Styled/res/drawable-xhdpi/ab_bottom_solid_styled.9.png
similarity index 100%
rename from samples/browseable/Styled/res/drawable-xhdpi/ab_bottom_solid_styled.9.png
rename to samples/browseable/ActionBarCompat-Styled/res/drawable-xhdpi/ab_bottom_solid_styled.9.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-xhdpi/ab_solid_styled.9.png b/samples/browseable/ActionBarCompat-Styled/res/drawable-xhdpi/ab_solid_styled.9.png
similarity index 100%
rename from samples/browseable/Styled/res/drawable-xhdpi/ab_solid_styled.9.png
rename to samples/browseable/ActionBarCompat-Styled/res/drawable-xhdpi/ab_solid_styled.9.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-xhdpi/ab_stacked_solid_styled.9.png b/samples/browseable/ActionBarCompat-Styled/res/drawable-xhdpi/ab_stacked_solid_styled.9.png
similarity index 100%
rename from samples/browseable/Styled/res/drawable-xhdpi/ab_stacked_solid_styled.9.png
rename to samples/browseable/ActionBarCompat-Styled/res/drawable-xhdpi/ab_stacked_solid_styled.9.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-xhdpi/ic_action_location.png b/samples/browseable/ActionBarCompat-Styled/res/drawable-xhdpi/ic_action_location.png
similarity index 100%
rename from samples/browseable/Styled/res/drawable-xhdpi/ic_action_location.png
rename to samples/browseable/ActionBarCompat-Styled/res/drawable-xhdpi/ic_action_location.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-xhdpi/ic_action_refresh.png b/samples/browseable/ActionBarCompat-Styled/res/drawable-xhdpi/ic_action_refresh.png
similarity index 100%
rename from samples/browseable/Styled/res/drawable-xhdpi/ic_action_refresh.png
rename to samples/browseable/ActionBarCompat-Styled/res/drawable-xhdpi/ic_action_refresh.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-xhdpi/ic_action_settings.png b/samples/browseable/ActionBarCompat-Styled/res/drawable-xhdpi/ic_action_settings.png
similarity index 100%
rename from samples/browseable/Styled/res/drawable-xhdpi/ic_action_settings.png
rename to samples/browseable/ActionBarCompat-Styled/res/drawable-xhdpi/ic_action_settings.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-xhdpi/ic_launcher.png b/samples/browseable/ActionBarCompat-Styled/res/drawable-xhdpi/ic_launcher.png
similarity index 100%
rename from samples/browseable/Styled/res/drawable-xhdpi/ic_launcher.png
rename to samples/browseable/ActionBarCompat-Styled/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-xhdpi/list_focused_styled.9.png b/samples/browseable/ActionBarCompat-Styled/res/drawable-xhdpi/list_focused_styled.9.png
similarity index 100%
rename from samples/browseable/Styled/res/drawable-xhdpi/list_focused_styled.9.png
rename to samples/browseable/ActionBarCompat-Styled/res/drawable-xhdpi/list_focused_styled.9.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-xhdpi/menu_dropdown_panel_styled.9.png b/samples/browseable/ActionBarCompat-Styled/res/drawable-xhdpi/menu_dropdown_panel_styled.9.png
similarity index 100%
rename from samples/browseable/Styled/res/drawable-xhdpi/menu_dropdown_panel_styled.9.png
rename to samples/browseable/ActionBarCompat-Styled/res/drawable-xhdpi/menu_dropdown_panel_styled.9.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-xhdpi/progress_bg_styled.9.png b/samples/browseable/ActionBarCompat-Styled/res/drawable-xhdpi/progress_bg_styled.9.png
similarity index 100%
rename from samples/browseable/Styled/res/drawable-xhdpi/progress_bg_styled.9.png
rename to samples/browseable/ActionBarCompat-Styled/res/drawable-xhdpi/progress_bg_styled.9.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-xhdpi/progress_primary_styled.9.png b/samples/browseable/ActionBarCompat-Styled/res/drawable-xhdpi/progress_primary_styled.9.png
similarity index 100%
rename from samples/browseable/Styled/res/drawable-xhdpi/progress_primary_styled.9.png
rename to samples/browseable/ActionBarCompat-Styled/res/drawable-xhdpi/progress_primary_styled.9.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-xhdpi/progress_secondary_styled.9.png b/samples/browseable/ActionBarCompat-Styled/res/drawable-xhdpi/progress_secondary_styled.9.png
similarity index 100%
rename from samples/browseable/Styled/res/drawable-xhdpi/progress_secondary_styled.9.png
rename to samples/browseable/ActionBarCompat-Styled/res/drawable-xhdpi/progress_secondary_styled.9.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-xhdpi/spinner_ab_default_styled.9.png b/samples/browseable/ActionBarCompat-Styled/res/drawable-xhdpi/spinner_ab_default_styled.9.png
similarity index 100%
rename from samples/browseable/Styled/res/drawable-xhdpi/spinner_ab_default_styled.9.png
rename to samples/browseable/ActionBarCompat-Styled/res/drawable-xhdpi/spinner_ab_default_styled.9.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-xhdpi/spinner_ab_disabled_styled.9.png b/samples/browseable/ActionBarCompat-Styled/res/drawable-xhdpi/spinner_ab_disabled_styled.9.png
similarity index 100%
rename from samples/browseable/Styled/res/drawable-xhdpi/spinner_ab_disabled_styled.9.png
rename to samples/browseable/ActionBarCompat-Styled/res/drawable-xhdpi/spinner_ab_disabled_styled.9.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-xhdpi/spinner_ab_focused_styled.9.png b/samples/browseable/ActionBarCompat-Styled/res/drawable-xhdpi/spinner_ab_focused_styled.9.png
similarity index 100%
rename from samples/browseable/Styled/res/drawable-xhdpi/spinner_ab_focused_styled.9.png
rename to samples/browseable/ActionBarCompat-Styled/res/drawable-xhdpi/spinner_ab_focused_styled.9.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-xhdpi/spinner_ab_pressed_styled.9.png b/samples/browseable/ActionBarCompat-Styled/res/drawable-xhdpi/spinner_ab_pressed_styled.9.png
similarity index 100%
rename from samples/browseable/Styled/res/drawable-xhdpi/spinner_ab_pressed_styled.9.png
rename to samples/browseable/ActionBarCompat-Styled/res/drawable-xhdpi/spinner_ab_pressed_styled.9.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-xhdpi/tab_selected_focused_styled.9.png b/samples/browseable/ActionBarCompat-Styled/res/drawable-xhdpi/tab_selected_focused_styled.9.png
similarity index 100%
rename from samples/browseable/Styled/res/drawable-xhdpi/tab_selected_focused_styled.9.png
rename to samples/browseable/ActionBarCompat-Styled/res/drawable-xhdpi/tab_selected_focused_styled.9.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-xhdpi/tab_selected_pressed_styled.9.png b/samples/browseable/ActionBarCompat-Styled/res/drawable-xhdpi/tab_selected_pressed_styled.9.png
similarity index 100%
rename from samples/browseable/Styled/res/drawable-xhdpi/tab_selected_pressed_styled.9.png
rename to samples/browseable/ActionBarCompat-Styled/res/drawable-xhdpi/tab_selected_pressed_styled.9.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-xhdpi/tab_selected_styled.9.png b/samples/browseable/ActionBarCompat-Styled/res/drawable-xhdpi/tab_selected_styled.9.png
similarity index 100%
rename from samples/browseable/Styled/res/drawable-xhdpi/tab_selected_styled.9.png
rename to samples/browseable/ActionBarCompat-Styled/res/drawable-xhdpi/tab_selected_styled.9.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-xhdpi/tab_unselected_focused_styled.9.png b/samples/browseable/ActionBarCompat-Styled/res/drawable-xhdpi/tab_unselected_focused_styled.9.png
similarity index 100%
rename from samples/browseable/Styled/res/drawable-xhdpi/tab_unselected_focused_styled.9.png
rename to samples/browseable/ActionBarCompat-Styled/res/drawable-xhdpi/tab_unselected_focused_styled.9.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-xhdpi/tab_unselected_pressed_styled.9.png b/samples/browseable/ActionBarCompat-Styled/res/drawable-xhdpi/tab_unselected_pressed_styled.9.png
similarity index 100%
rename from samples/browseable/Styled/res/drawable-xhdpi/tab_unselected_pressed_styled.9.png
rename to samples/browseable/ActionBarCompat-Styled/res/drawable-xhdpi/tab_unselected_pressed_styled.9.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable-xxhdpi/ic_launcher.png b/samples/browseable/ActionBarCompat-Styled/res/drawable-xxhdpi/ic_launcher.png
similarity index 100%
rename from samples/browseable/Styled/res/drawable-xxhdpi/ic_launcher.png
rename to samples/browseable/ActionBarCompat-Styled/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/Styled/res/drawable/pressed_background.xml b/samples/browseable/ActionBarCompat-Styled/res/drawable/pressed_background.xml
similarity index 100%
rename from samples/browseable/Styled/res/drawable/pressed_background.xml
rename to samples/browseable/ActionBarCompat-Styled/res/drawable/pressed_background.xml
diff --git a/samples/browseable/Styled/res/drawable/progress_horizontal.xml b/samples/browseable/ActionBarCompat-Styled/res/drawable/progress_horizontal.xml
similarity index 100%
rename from samples/browseable/Styled/res/drawable/progress_horizontal.xml
rename to samples/browseable/ActionBarCompat-Styled/res/drawable/progress_horizontal.xml
diff --git a/samples/browseable/Styled/res/drawable/selectable_background.xml b/samples/browseable/ActionBarCompat-Styled/res/drawable/selectable_background.xml
similarity index 100%
rename from samples/browseable/Styled/res/drawable/selectable_background.xml
rename to samples/browseable/ActionBarCompat-Styled/res/drawable/selectable_background.xml
diff --git a/samples/browseable/Styled/res/drawable/spinner_background_ab.xml b/samples/browseable/ActionBarCompat-Styled/res/drawable/spinner_background_ab.xml
similarity index 100%
rename from samples/browseable/Styled/res/drawable/spinner_background_ab.xml
rename to samples/browseable/ActionBarCompat-Styled/res/drawable/spinner_background_ab.xml
diff --git a/samples/browseable/Styled/res/drawable/tab_indicator_ab.xml b/samples/browseable/ActionBarCompat-Styled/res/drawable/tab_indicator_ab.xml
similarity index 100%
rename from samples/browseable/Styled/res/drawable/tab_indicator_ab.xml
rename to samples/browseable/ActionBarCompat-Styled/res/drawable/tab_indicator_ab.xml
diff --git a/samples/browseable/Styled/res/layout/activity_main.xml b/samples/browseable/ActionBarCompat-Styled/res/layout/activity_main.xml
similarity index 100%
rename from samples/browseable/Styled/res/layout/activity_main.xml
rename to samples/browseable/ActionBarCompat-Styled/res/layout/activity_main.xml
diff --git a/samples/browseable/Styled/res/layout/sample_main.xml b/samples/browseable/ActionBarCompat-Styled/res/layout/sample_main.xml
similarity index 100%
rename from samples/browseable/Styled/res/layout/sample_main.xml
rename to samples/browseable/ActionBarCompat-Styled/res/layout/sample_main.xml
diff --git a/samples/browseable/Styled/res/menu/main.xml b/samples/browseable/ActionBarCompat-Styled/res/menu/main.xml
similarity index 100%
rename from samples/browseable/Styled/res/menu/main.xml
rename to samples/browseable/ActionBarCompat-Styled/res/menu/main.xml
diff --git a/samples/browseable/Styled/res/values-sw600dp/dimens.xml b/samples/browseable/ActionBarCompat-Styled/res/values-sw600dp/template-dimens.xml
similarity index 100%
rename from samples/browseable/Styled/res/values-sw600dp/dimens.xml
rename to samples/browseable/ActionBarCompat-Styled/res/values-sw600dp/template-dimens.xml
diff --git a/samples/browseable/Styled/res/values-sw600dp/styles.xml b/samples/browseable/ActionBarCompat-Styled/res/values-sw600dp/template-styles.xml
similarity index 100%
rename from samples/browseable/Styled/res/values-sw600dp/styles.xml
rename to samples/browseable/ActionBarCompat-Styled/res/values-sw600dp/template-styles.xml
diff --git a/samples/browseable/Styled/res/values-v14/styles.xml b/samples/browseable/ActionBarCompat-Styled/res/values-v14/styles.xml
similarity index 100%
rename from samples/browseable/Styled/res/values-v14/styles.xml
rename to samples/browseable/ActionBarCompat-Styled/res/values-v14/styles.xml
diff --git a/samples/browseable/Styled/res/values/base-strings.xml b/samples/browseable/ActionBarCompat-Styled/res/values/base-strings.xml
similarity index 93%
rename from samples/browseable/Styled/res/values/base-strings.xml
rename to samples/browseable/ActionBarCompat-Styled/res/values/base-strings.xml
index 985b433..7adb0c6 100644
--- a/samples/browseable/Styled/res/values/base-strings.xml
+++ b/samples/browseable/ActionBarCompat-Styled/res/values/base-strings.xml
@@ -18,7 +18,7 @@
 
 
 <resources>
-    <string name="app_name">Styled</string>
+    <string name="app_name">ActionBarCompat-Styled</string>
     <string name="intro_message">
         <![CDATA[
         
diff --git a/samples/browseable/Styled/res/values/colors.xml b/samples/browseable/ActionBarCompat-Styled/res/values/colors.xml
similarity index 100%
rename from samples/browseable/Styled/res/values/colors.xml
rename to samples/browseable/ActionBarCompat-Styled/res/values/colors.xml
diff --git a/samples/browseable/Styled/res/values/strings.xml b/samples/browseable/ActionBarCompat-Styled/res/values/strings.xml
similarity index 100%
rename from samples/browseable/Styled/res/values/strings.xml
rename to samples/browseable/ActionBarCompat-Styled/res/values/strings.xml
diff --git a/samples/browseable/ActionBarCompat-Styled/res/values/styles.xml b/samples/browseable/ActionBarCompat-Styled/res/values/styles.xml
new file mode 100644
index 0000000..75b0533
--- /dev/null
+++ b/samples/browseable/ActionBarCompat-Styled/res/values/styles.xml
@@ -0,0 +1,82 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 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>
+
+    <!--
+        This is the styled theme.
+
+        It extends from Theme.AppCompat.Light, but it could extend from any of
+        the Theme.AppCompat themes depending on your color scheme. This theme can be applied to
+        your application or individual activities in the AndroidManifest.xml. In this sample it is
+        set on the application.
+
+        This differs from the version of this theme in 'res/values-v14', as not all of the
+        necessary attributes are available in the android: namespace on older versions of Android.
+        This means that for certain attributes we must set the attributes provided in
+        ActionBarCompat's namespace instead.
+    -->
+
+    <style name="Theme.Styled" parent="@style/Theme.AppCompat.Light">
+        <item name="actionBarItemBackground">@drawable/selectable_background</item>
+        <item name="actionBarTabStyle">@style/Widget.Styled.ActionBar.TabView</item>
+        <item name="actionBarStyle">@style/Widget.Styled.ActionBar</item>
+        <item name="actionDropDownStyle">@style/Widget.Styled.Spinner.DropDown.ActionBar</item>
+        <item name="dropDownListViewStyle">@style/Widget.Styled.ListView.DropDown</item>
+        <item name="popupMenuStyle">@style/Widget.Styled.PopupMenu</item>
+    </style>
+
+    <style name="Widget.Styled.ActionBar" parent="@style/Widget.AppCompat.Light.ActionBar.Solid">
+        <item name="background">@drawable/ab_solid_styled</item>
+        <item name="backgroundStacked">@drawable/ab_stacked_solid_styled</item>
+        <item name="backgroundSplit">@drawable/ab_bottom_solid_styled</item>
+        <item name="progressBarStyle">@style/Widget.Styled.ProgressBar.Horizontal</item>
+    </style>
+
+
+    <!--
+        For the following styles, the attributes are available in the android namespace which
+        means that we can set them here for all platforms (v7 through to the latest).
+    -->
+
+    <style name="Widget.Styled.ActionBar.TabView"
+           parent="@style/Widget.AppCompat.Light.ActionBar.TabView">
+        <item name="android:background">@drawable/tab_indicator_ab</item>
+    </style>
+
+    <style name="Widget.Styled.Spinner.DropDown.ActionBar"
+           parent="@style/Widget.AppCompat.Light.Spinner.DropDown.ActionBar">
+        <item name="android:background">@drawable/spinner_background_ab</item>
+        <item name="android:popupBackground">@drawable/menu_dropdown_panel_styled</item>
+        <item name="android:dropDownSelector">@drawable/selectable_background</item>
+    </style>
+
+    <style name="Widget.Styled.ProgressBar.Horizontal"
+           parent="@style/Widget.AppCompat.ProgressBar.Horizontal">
+        <item name="android:progressDrawable">@drawable/progress_horizontal</item>
+    </style>
+
+    <style name="Widget.Styled.PopupMenu" parent="@style/Widget.AppCompat.Light.PopupMenu">
+        <item name="android:popupBackground">@drawable/menu_dropdown_panel_styled</item>
+    </style>
+
+    <style name="Widget.Styled.ListView.DropDown"
+           parent="@style/Widget.AppCompat.Light.ListView.DropDown">
+        <item name="android:listSelector">@drawable/selectable_background</item>
+    </style>
+
+</resources>
\ No newline at end of file
diff --git a/samples/browseable/Styled/res/values/dimens.xml b/samples/browseable/ActionBarCompat-Styled/res/values/template-dimens.xml
similarity index 100%
rename from samples/browseable/Styled/res/values/dimens.xml
rename to samples/browseable/ActionBarCompat-Styled/res/values/template-dimens.xml
diff --git a/samples/browseable/Styled/res/values/styles.xml b/samples/browseable/ActionBarCompat-Styled/res/values/template-styles.xml
similarity index 100%
rename from samples/browseable/Styled/res/values/styles.xml
rename to samples/browseable/ActionBarCompat-Styled/res/values/template-styles.xml
diff --git a/samples/browseable/Styled/src/com.example.android.actionbarcompat.styled/MainActivity.java b/samples/browseable/ActionBarCompat-Styled/src/com.example.android.actionbarcompat.styled/MainActivity.java
similarity index 100%
rename from samples/browseable/Styled/src/com.example.android.actionbarcompat.styled/MainActivity.java
rename to samples/browseable/ActionBarCompat-Styled/src/com.example.android.actionbarcompat.styled/MainActivity.java
diff --git a/samples/browseable/ActivityInstrumentation/res/values-sw600dp/dimens.xml b/samples/browseable/ActivityInstrumentation/res/values-sw600dp/template-dimens.xml
similarity index 100%
rename from samples/browseable/ActivityInstrumentation/res/values-sw600dp/dimens.xml
rename to samples/browseable/ActivityInstrumentation/res/values-sw600dp/template-dimens.xml
diff --git a/samples/browseable/ActivityInstrumentation/res/values-sw600dp/styles.xml b/samples/browseable/ActivityInstrumentation/res/values-sw600dp/template-styles.xml
similarity index 100%
rename from samples/browseable/ActivityInstrumentation/res/values-sw600dp/styles.xml
rename to samples/browseable/ActivityInstrumentation/res/values-sw600dp/template-styles.xml
diff --git a/samples/browseable/ActivityInstrumentation/res/values/dimens.xml b/samples/browseable/ActivityInstrumentation/res/values/dimens.xml
index 39e710b..4afc9dd 100644
--- a/samples/browseable/ActivityInstrumentation/res/values/dimens.xml
+++ b/samples/browseable/ActivityInstrumentation/res/values/dimens.xml
@@ -1,32 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
 <!--
-  Copyright 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.
+  ~ Copyright 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>
-
-    <!-- Define standard dimensions to comply with Holo-style grids and rhythm. -->
-
-    <dimen name="margin_tiny">4dp</dimen>
-    <dimen name="margin_small">8dp</dimen>
-    <dimen name="margin_medium">16dp</dimen>
-    <dimen name="margin_large">32dp</dimen>
-    <dimen name="margin_huge">64dp</dimen>
-
-    <!-- Semantic definitions -->
-
-    <dimen name="horizontal_page_margin">@dimen/margin_medium</dimen>
-    <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
-
+    <!-- Default screen margins, per the Android Design guidelines. -->
+    <dimen name="activity_horizontal_margin">16dp</dimen>
+    <dimen name="activity_vertical_margin">16dp</dimen>
 </resources>
diff --git a/samples/browseable/AdvancedImmersiveMode/res/values/dimens.xml b/samples/browseable/ActivityInstrumentation/res/values/template-dimens.xml
similarity index 100%
copy from samples/browseable/AdvancedImmersiveMode/res/values/dimens.xml
copy to samples/browseable/ActivityInstrumentation/res/values/template-dimens.xml
diff --git a/samples/browseable/ActivityInstrumentation/res/values/styles.xml b/samples/browseable/ActivityInstrumentation/res/values/template-styles.xml
similarity index 100%
rename from samples/browseable/ActivityInstrumentation/res/values/styles.xml
rename to samples/browseable/ActivityInstrumentation/res/values/template-styles.xml
diff --git a/samples/browseable/AdapterTransition/AndroidManifest.xml b/samples/browseable/AdapterTransition/AndroidManifest.xml
new file mode 100644
index 0000000..01b414d
--- /dev/null
+++ b/samples/browseable/AdapterTransition/AndroidManifest.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright 2014 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.example.android.adaptertransition"
+    android:versionCode="1"
+    android:versionName="1.0">
+
+    <uses-sdk
+        android:minSdkVersion="19"
+        android:targetSdkVersion="19"/>
+
+    <application
+        android:allowBackup="true"
+        android:icon="@drawable/ic_launcher"
+        android:label="@string/app_name"
+        android:theme="@style/AppTheme">
+        <activity
+            android:name="com.example.android.adaptertransition.MainActivity"
+            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/browseable/AdapterTransition/_index.jd b/samples/browseable/AdapterTransition/_index.jd
new file mode 100644
index 0000000..d5c48a3
--- /dev/null
+++ b/samples/browseable/AdapterTransition/_index.jd
@@ -0,0 +1,12 @@
+
+
+
+page.tags="AdapterTransition"
+sample.group=UI
+@jd:body
+
+<p>
+{@link android.transition.Transition Transition} cannot be directly applied to 
+{@link android.widget.AdapterView AdapterView}s. This sample demonstrates how to 
+create a overlay layout and how to run a transition on it.
+</p>
diff --git a/samples/browseable/AdapterTransition/res/drawable-hdpi/ic_action_grid.png b/samples/browseable/AdapterTransition/res/drawable-hdpi/ic_action_grid.png
new file mode 100644
index 0000000..e04f4a7
--- /dev/null
+++ b/samples/browseable/AdapterTransition/res/drawable-hdpi/ic_action_grid.png
Binary files differ
diff --git a/samples/browseable/AdapterTransition/res/drawable-hdpi/ic_action_list.png b/samples/browseable/AdapterTransition/res/drawable-hdpi/ic_action_list.png
new file mode 100644
index 0000000..4131dba
--- /dev/null
+++ b/samples/browseable/AdapterTransition/res/drawable-hdpi/ic_action_list.png
Binary files differ
diff --git a/samples/browseable/AdapterTransition/res/drawable-hdpi/ic_launcher.png b/samples/browseable/AdapterTransition/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..b7a67c0
--- /dev/null
+++ b/samples/browseable/AdapterTransition/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/Basic/res/drawable-hdpi/tile.9.png b/samples/browseable/AdapterTransition/res/drawable-hdpi/tile.9.png
similarity index 100%
copy from samples/browseable/Basic/res/drawable-hdpi/tile.9.png
copy to samples/browseable/AdapterTransition/res/drawable-hdpi/tile.9.png
Binary files differ
diff --git a/samples/browseable/AdapterTransition/res/drawable-mdpi/ic_action_grid.png b/samples/browseable/AdapterTransition/res/drawable-mdpi/ic_action_grid.png
new file mode 100644
index 0000000..f2a83e3
--- /dev/null
+++ b/samples/browseable/AdapterTransition/res/drawable-mdpi/ic_action_grid.png
Binary files differ
diff --git a/samples/browseable/AdapterTransition/res/drawable-mdpi/ic_action_list.png b/samples/browseable/AdapterTransition/res/drawable-mdpi/ic_action_list.png
new file mode 100644
index 0000000..e248a48
--- /dev/null
+++ b/samples/browseable/AdapterTransition/res/drawable-mdpi/ic_action_list.png
Binary files differ
diff --git a/samples/browseable/AdapterTransition/res/drawable-mdpi/ic_launcher.png b/samples/browseable/AdapterTransition/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..1c9fc09
--- /dev/null
+++ b/samples/browseable/AdapterTransition/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/AdapterTransition/res/drawable-nodpi/p1.jpg b/samples/browseable/AdapterTransition/res/drawable-nodpi/p1.jpg
new file mode 100644
index 0000000..10f07ac
--- /dev/null
+++ b/samples/browseable/AdapterTransition/res/drawable-nodpi/p1.jpg
Binary files differ
diff --git a/samples/browseable/AdapterTransition/res/drawable-nodpi/p10.jpg b/samples/browseable/AdapterTransition/res/drawable-nodpi/p10.jpg
new file mode 100644
index 0000000..4272f4c
--- /dev/null
+++ b/samples/browseable/AdapterTransition/res/drawable-nodpi/p10.jpg
Binary files differ
diff --git a/samples/browseable/AdapterTransition/res/drawable-nodpi/p11.jpg b/samples/browseable/AdapterTransition/res/drawable-nodpi/p11.jpg
new file mode 100644
index 0000000..c5722b2
--- /dev/null
+++ b/samples/browseable/AdapterTransition/res/drawable-nodpi/p11.jpg
Binary files differ
diff --git a/samples/browseable/AdapterTransition/res/drawable-nodpi/p2.jpg b/samples/browseable/AdapterTransition/res/drawable-nodpi/p2.jpg
new file mode 100644
index 0000000..ca380ae
--- /dev/null
+++ b/samples/browseable/AdapterTransition/res/drawable-nodpi/p2.jpg
Binary files differ
diff --git a/samples/browseable/AdapterTransition/res/drawable-nodpi/p3.jpg b/samples/browseable/AdapterTransition/res/drawable-nodpi/p3.jpg
new file mode 100644
index 0000000..6fc71e7
--- /dev/null
+++ b/samples/browseable/AdapterTransition/res/drawable-nodpi/p3.jpg
Binary files differ
diff --git a/samples/browseable/AdapterTransition/res/drawable-nodpi/p4.jpg b/samples/browseable/AdapterTransition/res/drawable-nodpi/p4.jpg
new file mode 100644
index 0000000..153c1ff
--- /dev/null
+++ b/samples/browseable/AdapterTransition/res/drawable-nodpi/p4.jpg
Binary files differ
diff --git a/samples/browseable/AdapterTransition/res/drawable-nodpi/p5.jpg b/samples/browseable/AdapterTransition/res/drawable-nodpi/p5.jpg
new file mode 100644
index 0000000..46d6a13
--- /dev/null
+++ b/samples/browseable/AdapterTransition/res/drawable-nodpi/p5.jpg
Binary files differ
diff --git a/samples/browseable/AdapterTransition/res/drawable-nodpi/p6.jpg b/samples/browseable/AdapterTransition/res/drawable-nodpi/p6.jpg
new file mode 100644
index 0000000..89ccb83
--- /dev/null
+++ b/samples/browseable/AdapterTransition/res/drawable-nodpi/p6.jpg
Binary files differ
diff --git a/samples/browseable/AdapterTransition/res/drawable-nodpi/p7.jpg b/samples/browseable/AdapterTransition/res/drawable-nodpi/p7.jpg
new file mode 100644
index 0000000..7e9546d
--- /dev/null
+++ b/samples/browseable/AdapterTransition/res/drawable-nodpi/p7.jpg
Binary files differ
diff --git a/samples/browseable/AdapterTransition/res/drawable-nodpi/p8.jpg b/samples/browseable/AdapterTransition/res/drawable-nodpi/p8.jpg
new file mode 100644
index 0000000..21e25ba
--- /dev/null
+++ b/samples/browseable/AdapterTransition/res/drawable-nodpi/p8.jpg
Binary files differ
diff --git a/samples/browseable/AdapterTransition/res/drawable-nodpi/p9.jpg b/samples/browseable/AdapterTransition/res/drawable-nodpi/p9.jpg
new file mode 100644
index 0000000..79854cb
--- /dev/null
+++ b/samples/browseable/AdapterTransition/res/drawable-nodpi/p9.jpg
Binary files differ
diff --git a/samples/browseable/AdapterTransition/res/drawable-xhdpi/ic_action_grid.png b/samples/browseable/AdapterTransition/res/drawable-xhdpi/ic_action_grid.png
new file mode 100644
index 0000000..ecd39b5
--- /dev/null
+++ b/samples/browseable/AdapterTransition/res/drawable-xhdpi/ic_action_grid.png
Binary files differ
diff --git a/samples/browseable/AdapterTransition/res/drawable-xhdpi/ic_action_list.png b/samples/browseable/AdapterTransition/res/drawable-xhdpi/ic_action_list.png
new file mode 100644
index 0000000..e7e510d
--- /dev/null
+++ b/samples/browseable/AdapterTransition/res/drawable-xhdpi/ic_action_list.png
Binary files differ
diff --git a/samples/browseable/AdapterTransition/res/drawable-xhdpi/ic_launcher.png b/samples/browseable/AdapterTransition/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..11b9928
--- /dev/null
+++ b/samples/browseable/AdapterTransition/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/AdapterTransition/res/drawable-xxhdpi/ic_action_grid.png b/samples/browseable/AdapterTransition/res/drawable-xxhdpi/ic_action_grid.png
new file mode 100644
index 0000000..3ba98fc
--- /dev/null
+++ b/samples/browseable/AdapterTransition/res/drawable-xxhdpi/ic_action_grid.png
Binary files differ
diff --git a/samples/browseable/AdapterTransition/res/drawable-xxhdpi/ic_action_list.png b/samples/browseable/AdapterTransition/res/drawable-xxhdpi/ic_action_list.png
new file mode 100644
index 0000000..d187732
--- /dev/null
+++ b/samples/browseable/AdapterTransition/res/drawable-xxhdpi/ic_action_list.png
Binary files differ
diff --git a/samples/browseable/AdapterTransition/res/drawable-xxhdpi/ic_launcher.png b/samples/browseable/AdapterTransition/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..f136c9f
--- /dev/null
+++ b/samples/browseable/AdapterTransition/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/AdapterTransition/res/layout-w720dp/activity_main.xml b/samples/browseable/AdapterTransition/res/layout-w720dp/activity_main.xml
new file mode 100755
index 0000000..c9a52f6
--- /dev/null
+++ b/samples/browseable/AdapterTransition/res/layout-w720dp/activity_main.xml
@@ -0,0 +1,73 @@
+<!--
+  Copyright 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"
+      android:orientation="horizontal"
+      android:layout_width="match_parent"
+      android:layout_height="match_parent"
+      android:id="@+id/sample_main_layout">
+
+    <LinearLayout
+          android:id="@+id/sample_output"
+          android:layout_width="0px"
+          android:layout_height="match_parent"
+          android:layout_weight="1"
+          android:orientation="vertical">
+
+        <FrameLayout
+              style="@style/Widget.SampleMessageTile"
+              android:layout_width="match_parent"
+              android:layout_height="wrap_content">
+
+            <TextView
+                  style="@style/Widget.SampleMessage"
+                  android:layout_width="match_parent"
+                  android:layout_height="wrap_content"
+                  android:paddingLeft="@dimen/margin_medium"
+                  android:paddingRight="@dimen/margin_medium"
+                  android:paddingTop="@dimen/margin_large"
+                  android:paddingBottom="@dimen/margin_large"
+                  android:text="@string/intro_message" />
+        </FrameLayout>
+
+        <View
+              android:layout_width="match_parent"
+              android:layout_height="1dp"
+              android:background="@android:color/darker_gray" />
+
+        <fragment
+              android:name="com.example.android.common.logger.LogFragment"
+              android:id="@+id/log_fragment"
+              android:layout_width="match_parent"
+              android:layout_height="0px"
+              android:layout_weight="1" />
+
+    </LinearLayout>
+
+    <View
+          android:layout_width="1dp"
+          android:layout_height="match_parent"
+          android:background="@android:color/darker_gray" />
+
+    <FrameLayout
+          android:id="@+id/sample_content_fragment"
+          android:layout_weight="2"
+          android:layout_width="0px"
+          android:layout_height="match_parent" />
+
+</LinearLayout>
+
+
diff --git a/samples/browseable/AdapterTransition/res/layout/activity_main.xml b/samples/browseable/AdapterTransition/res/layout/activity_main.xml
new file mode 100755
index 0000000..1ae4f98
--- /dev/null
+++ b/samples/browseable/AdapterTransition/res/layout/activity_main.xml
@@ -0,0 +1,65 @@
+<!--
+  Copyright 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"
+      android:orientation="vertical"
+      android:layout_width="match_parent"
+      android:layout_height="match_parent"
+      android:id="@+id/sample_main_layout">
+
+    <ViewAnimator
+          android:id="@+id/sample_output"
+          android:layout_width="match_parent"
+          android:layout_height="0px"
+          android:layout_weight="1">
+
+        <ScrollView
+              style="@style/Widget.SampleMessageTile"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent">
+
+            <TextView
+                  style="@style/Widget.SampleMessage"
+                  android:layout_width="match_parent"
+                  android:layout_height="wrap_content"
+                  android:paddingLeft="@dimen/horizontal_page_margin"
+                  android:paddingRight="@dimen/horizontal_page_margin"
+                  android:paddingTop="@dimen/vertical_page_margin"
+                  android:paddingBottom="@dimen/vertical_page_margin"
+                  android:text="@string/intro_message" />
+        </ScrollView>
+
+        <fragment
+              android:name="com.example.android.common.logger.LogFragment"
+              android:id="@+id/log_fragment"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent" />
+
+    </ViewAnimator>
+
+    <View
+          android:layout_width="match_parent"
+          android:layout_height="1dp"
+          android:background="@android:color/darker_gray" />
+
+    <FrameLayout
+          android:id="@+id/sample_content_fragment"
+          android:layout_weight="2"
+          android:layout_width="match_parent"
+          android:layout_height="0px" />
+
+</LinearLayout>
+
diff --git a/samples/browseable/AdapterTransition/res/layout/fragment_adapter_transition.xml b/samples/browseable/AdapterTransition/res/layout/fragment_adapter_transition.xml
new file mode 100644
index 0000000..22ec090
--- /dev/null
+++ b/samples/browseable/AdapterTransition/res/layout/fragment_adapter_transition.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright 2014 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+<FrameLayout 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="com.example.android.adaptertransition.AdapterTransitionFragment">
+
+    <FrameLayout
+        android:id="@+id/content"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"/>
+
+    <FrameLayout
+        android:id="@+id/cover"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:background="#f3f3f3"
+        android:visibility="invisible"/>
+
+</FrameLayout>
diff --git a/samples/browseable/AdapterTransition/res/layout/fragment_meat_grid.xml b/samples/browseable/AdapterTransition/res/layout/fragment_meat_grid.xml
new file mode 100644
index 0000000..9a4f7a1
--- /dev/null
+++ b/samples/browseable/AdapterTransition/res/layout/fragment_meat_grid.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright 2014 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+<GridView
+    android:id="@+id/abs_list_view"
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:clipToPadding="false"
+    android:columnWidth="150dp"
+    android:horizontalSpacing="1dp"
+    android:numColumns="auto_fit"
+    android:padding="1dp"
+    android:scrollbars="none"
+    android:stretchMode="columnWidth"
+    android:verticalSpacing="1dp"/>
diff --git a/samples/browseable/AdapterTransition/res/layout/fragment_meat_list.xml b/samples/browseable/AdapterTransition/res/layout/fragment_meat_list.xml
new file mode 100644
index 0000000..4523b26
--- /dev/null
+++ b/samples/browseable/AdapterTransition/res/layout/fragment_meat_list.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright 2014 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+<ListView
+    android:id="@+id/abs_list_view"
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"/>
diff --git a/samples/browseable/AdapterTransition/res/layout/item_meat_grid.xml b/samples/browseable/AdapterTransition/res/layout/item_meat_grid.xml
new file mode 100644
index 0000000..d7fb77a
--- /dev/null
+++ b/samples/browseable/AdapterTransition/res/layout/item_meat_grid.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright 2014 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+<RelativeLayout
+    android:id="@+id/meat_container"
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="150dp">
+
+    <ImageView
+        android:id="@+id/meat_image"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:scaleType="centerCrop"
+        tools:src="@drawable/p1"/>
+
+    <TextView
+        android:id="@+id/meat_title"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignParentBottom="true"
+        android:layout_alignParentEnd="true"
+        android:layout_gravity="bottom|end"
+        android:layout_marginEnd="16dp"
+        android:layout_marginStart="16dp"
+        android:gravity="center_horizontal"
+        android:shadowColor="#000000"
+        android:shadowDx="0"
+        android:shadowDy="0"
+        android:shadowRadius="10"
+        android:textColor="#ffffff"
+        android:textSize="24sp"
+        android:textStyle="bold"
+        tools:text="Hello"/>
+
+</RelativeLayout>
\ No newline at end of file
diff --git a/samples/browseable/AdapterTransition/res/layout/item_meat_list.xml b/samples/browseable/AdapterTransition/res/layout/item_meat_list.xml
new file mode 100644
index 0000000..8d75b90
--- /dev/null
+++ b/samples/browseable/AdapterTransition/res/layout/item_meat_list.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright 2014 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+<RelativeLayout
+    android:id="@+id/meat_container"
+    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="horizontal"
+    android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
+    android:paddingStart="?android:attr/listPreferredItemPaddingStart">
+
+    <ImageView
+        android:id="@+id/meat_image"
+        android:layout_width="64dp"
+        android:layout_height="64dp"
+        android:scaleType="centerCrop"
+        tools:src="@drawable/p1"/>
+
+    <TextView
+        android:id="@+id/meat_title"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_centerVertical="true"
+        android:layout_marginStart="?android:attr/listPreferredItemPaddingStart"
+        android:layout_toEndOf="@id/meat_image"
+        android:layout_centerInParent="true"
+        android:gravity="center_vertical"
+        android:textSize="24sp"
+        tools:text="Title"/>
+
+</RelativeLayout>
\ No newline at end of file
diff --git a/samples/browseable/AdapterTransition/res/menu/fragment_adapter_transition.xml b/samples/browseable/AdapterTransition/res/menu/fragment_adapter_transition.xml
new file mode 100644
index 0000000..2a51b11
--- /dev/null
+++ b/samples/browseable/AdapterTransition/res/menu/fragment_adapter_transition.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright 2014 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+    <item
+        android:id="@+id/action_toggle"
+        android:icon="@drawable/ic_action_grid"
+        android:showAsAction="always"
+        android:title="Toggle view"/>
+</menu>
diff --git a/samples/training/bitmapfun/BitmapFun/src/main/res/values/colors.xml b/samples/browseable/AdapterTransition/res/menu/main.xml
similarity index 60%
copy from samples/training/bitmapfun/BitmapFun/src/main/res/values/colors.xml
copy to samples/browseable/AdapterTransition/res/menu/main.xml
index 7e4a4fe..b49c2c5 100644
--- a/samples/training/bitmapfun/BitmapFun/src/main/res/values/colors.xml
+++ b/samples/browseable/AdapterTransition/res/menu/main.xml
@@ -1,23 +1,21 @@
-<?xml version="1.0" encoding="utf-8"?>
 <!--
-  Copyright (C) 2012 The Android Open Source Project
+  Copyright 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
+      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>
-
-    <color name="grid_state_pressed">#BB7dbcd3</color>
-    <color name="grid_state_focused">#777dbcd3</color>
-
-</resources>
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:id="@+id/menu_toggle_log"
+          android:showAsAction="always"
+          android:title="@string/sample_show_log" />
+</menu>
diff --git a/samples/browseable/ActivityInstrumentation/res/values-sw600dp/dimens.xml b/samples/browseable/AdapterTransition/res/values-sw600dp/template-dimens.xml
similarity index 100%
copy from samples/browseable/ActivityInstrumentation/res/values-sw600dp/dimens.xml
copy to samples/browseable/AdapterTransition/res/values-sw600dp/template-dimens.xml
diff --git a/samples/browseable/ActivityInstrumentation/res/values-sw600dp/styles.xml b/samples/browseable/AdapterTransition/res/values-sw600dp/template-styles.xml
similarity index 100%
copy from samples/browseable/ActivityInstrumentation/res/values-sw600dp/styles.xml
copy to samples/browseable/AdapterTransition/res/values-sw600dp/template-styles.xml
diff --git a/samples/browseable/AdapterTransition/res/values-w820dp/dimens.xml b/samples/browseable/AdapterTransition/res/values-w820dp/dimens.xml
new file mode 100644
index 0000000..63fc816
--- /dev/null
+++ b/samples/browseable/AdapterTransition/res/values-w820dp/dimens.xml
@@ -0,0 +1,6 @@
+<resources>
+    <!-- Example customization of dimensions originally defined in res/values/dimens.xml
+         (such as screen margins) for screens with more than 820dp of available width. This
+         would include 7" and 10" devices in landscape (~960dp and ~1280dp respectively). -->
+    <dimen name="activity_horizontal_margin">64dp</dimen>
+</resources>
diff --git a/samples/browseable/repeatingAlarm/res/values/base-strings.xml b/samples/browseable/AdapterTransition/res/values/base-strings.xml
similarity index 79%
copy from samples/browseable/repeatingAlarm/res/values/base-strings.xml
copy to samples/browseable/AdapterTransition/res/values/base-strings.xml
index c11b89b..353c67e 100644
--- a/samples/browseable/repeatingAlarm/res/values/base-strings.xml
+++ b/samples/browseable/AdapterTransition/res/values/base-strings.xml
@@ -18,13 +18,12 @@
 
 
 <resources>
-    <string name="app_name">repeatingAlarm</string>
+    <string name="app_name">AdapterTransition</string>
     <string name="intro_message">
         <![CDATA[
         
             
-                Introductory text that explains what the sample is intended to demonstrate. Edit
-                in template-params.xml.
+	    Transition cannot be directly applied to AdapterViews. In this sample, we demonstrate how to create a overlay layout and run a Transition on it.
             
         
         ]]>
diff --git a/samples/browseable/AdapterTransition/res/values/dimens.xml b/samples/browseable/AdapterTransition/res/values/dimens.xml
new file mode 100644
index 0000000..a0171a7
--- /dev/null
+++ b/samples/browseable/AdapterTransition/res/values/dimens.xml
@@ -0,0 +1,6 @@
+<resources>
+    <!-- Default screen margins, per the Android Design guidelines. -->
+    <dimen name="activity_horizontal_margin">16dp</dimen>
+    <dimen name="activity_vertical_margin">16dp</dimen>
+
+    </resources>
diff --git a/samples/training/bitmapfun/BitmapFun/src/main/res/values/colors.xml b/samples/browseable/AdapterTransition/res/values/strings.xml
old mode 100644
new mode 100755
similarity index 67%
copy from samples/training/bitmapfun/BitmapFun/src/main/res/values/colors.xml
copy to samples/browseable/AdapterTransition/res/values/strings.xml
index 7e4a4fe..7b9d9ec
--- a/samples/training/bitmapfun/BitmapFun/src/main/res/values/colors.xml
+++ b/samples/browseable/AdapterTransition/res/values/strings.xml
@@ -1,12 +1,11 @@
-<?xml version="1.0" encoding="utf-8"?>
 <!--
-  Copyright (C) 2012 The Android Open Source Project
+  Copyright 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
+      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,
@@ -14,10 +13,7 @@
   See the License for the specific language governing permissions and
   limitations under the License.
 -->
-
 <resources>
-
-    <color name="grid_state_pressed">#BB7dbcd3</color>
-    <color name="grid_state_focused">#777dbcd3</color>
-
+    <string name="sample_show_log">Show Log</string>
+    <string name="sample_hide_log">Hide Log</string>
 </resources>
diff --git a/samples/browseable/AppRestrictions/res/values/dimens.xml b/samples/browseable/AdapterTransition/res/values/template-dimens.xml
similarity index 100%
copy from samples/browseable/AppRestrictions/res/values/dimens.xml
copy to samples/browseable/AdapterTransition/res/values/template-dimens.xml
diff --git a/samples/browseable/ActivityInstrumentation/res/values/styles.xml b/samples/browseable/AdapterTransition/res/values/template-styles.xml
similarity index 100%
copy from samples/browseable/ActivityInstrumentation/res/values/styles.xml
copy to samples/browseable/AdapterTransition/res/values/template-styles.xml
diff --git a/samples/browseable/AdapterTransition/src/com.example.android.adaptertransition/AdapterTransitionFragment.java b/samples/browseable/AdapterTransition/src/com.example.android.adaptertransition/AdapterTransitionFragment.java
new file mode 100644
index 0000000..525ed40
--- /dev/null
+++ b/samples/browseable/AdapterTransition/src/com.example.android.adaptertransition/AdapterTransitionFragment.java
@@ -0,0 +1,244 @@
+/*
+ * Copyright 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.adaptertransition;
+
+import android.os.Bundle;
+import android.support.v4.app.ActivityCompat;
+import android.support.v4.app.Fragment;
+import android.transition.AutoTransition;
+import android.transition.Scene;
+import android.transition.Transition;
+import android.transition.TransitionManager;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AbsListView;
+import android.widget.FrameLayout;
+import android.widget.GridView;
+import android.widget.ListView;
+
+/**
+ * Main screen for AdapterTransition sample.
+ */
+public class AdapterTransitionFragment extends Fragment implements Transition.TransitionListener {
+
+    /**
+     * Since the transition framework requires all relevant views in a view hierarchy to be marked
+     * with IDs, we use this ID to mark the root view.
+     */
+    private static final int ROOT_ID = 1;
+
+    /**
+     * This is where we place our AdapterView (ListView / GridView).
+     */
+    private FrameLayout mContent;
+
+    /**
+     * This is where we carry out the transition.
+     */
+    private FrameLayout mCover;
+
+    /**
+     * This list shows our contents. It can be ListView or GridView, and we toggle between them
+     * using the transition framework.
+     */
+    private AbsListView mAbsListView;
+
+    /**
+     * This is our contents.
+     */
+    private MeatAdapter mAdapter;
+
+    public static AdapterTransitionFragment newInstance() {
+        return new AdapterTransitionFragment();
+    }
+
+    public AdapterTransitionFragment() {
+    }
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setHasOptionsMenu(true);
+    }
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+        // We use a ListView at first
+        mAbsListView = (AbsListView) inflater.inflate(R.layout.fragment_meat_list, container, false);
+        mAdapter = new MeatAdapter(inflater, R.layout.item_meat_list);
+        return inflater.inflate(R.layout.fragment_adapter_transition, container, false);
+    }
+
+    @Override
+    public void onViewCreated(View view, Bundle savedInstanceState) {
+        // Retaining references for FrameLayouts that we use later.
+        mContent = (FrameLayout) view.findViewById(R.id.content);
+        mCover = (FrameLayout) view.findViewById(R.id.cover);
+        // We are attaching the list to the screen here.
+        mAbsListView.setAdapter(mAdapter);
+        mContent.addView(mAbsListView);
+    }
+
+    @Override
+    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+        inflater.inflate(R.menu.fragment_adapter_transition, menu);
+    }
+
+    @Override
+    public void onPrepareOptionsMenu(Menu menu) {
+        // We change the look of the icon every time the user toggles between list and grid.
+        MenuItem item = menu.findItem(R.id.action_toggle);
+        if (null != item) {
+            if (mAbsListView instanceof ListView) {
+                item.setIcon(R.drawable.ic_action_grid);
+            } else {
+                item.setIcon(R.drawable.ic_action_list);
+            }
+        }
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        switch (item.getItemId()) {
+            case R.id.action_toggle: {
+                toggle();
+                return true;
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public void onTransitionStart(Transition transition) {
+    }
+
+    // BEGIN_INCLUDE(on_transition_end)
+    @Override
+    public void onTransitionEnd(Transition transition) {
+        // When the transition ends, we remove all the views from the overlay and hide it.
+        mCover.removeAllViews();
+        mCover.setVisibility(View.INVISIBLE);
+    }
+    // END_INCLUDE(on_transition_end)
+
+    @Override
+    public void onTransitionCancel(Transition transition) {
+    }
+
+    @Override
+    public void onTransitionPause(Transition transition) {
+    }
+
+    @Override
+    public void onTransitionResume(Transition transition) {
+    }
+
+    /**
+     * Toggle the UI between ListView and GridView.
+     */
+    private void toggle() {
+        // We use mCover as the overlay on which we carry out the transition.
+        mCover.setVisibility(View.VISIBLE);
+        // This FrameLayout holds all the visible views in the current list or grid. We use this as
+        // the starting Scene of the Transition later.
+        FrameLayout before = copyVisibleViews();
+        FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
+                FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT);
+        mCover.addView(before, params);
+        // Swap the actual list.
+        swapAbsListView();
+        // We also swap the icon for the toggle button.
+        ActivityCompat.invalidateOptionsMenu(getActivity());
+        // It is now ready to start the transition.
+        mAbsListView.post(new Runnable() {
+            @Override
+            public void run() {
+                // BEGIN_INCLUDE(transition_with_listener)
+                Scene scene = new Scene(mCover, copyVisibleViews());
+                Transition transition = new AutoTransition();
+                transition.addListener(AdapterTransitionFragment.this);
+                TransitionManager.go(scene, transition);
+                // END_INCLUDE(transition_with_listener)
+            }
+        });
+    }
+
+    /**
+     * Swap ListView with GridView, or GridView with ListView.
+     */
+    private void swapAbsListView() {
+        // We save the current scrolling position before removing the current list.
+        int first = mAbsListView.getFirstVisiblePosition();
+        // If the current list is a GridView, we replace it with a ListView. If it is a ListView,
+        // a GridView.
+        LayoutInflater inflater = LayoutInflater.from(getActivity());
+        if (mAbsListView instanceof GridView) {
+            mAbsListView = (AbsListView) inflater.inflate(
+                    R.layout.fragment_meat_list, (ViewGroup) mAbsListView.getParent(), false);
+            mAdapter = new MeatAdapter(inflater, R.layout.item_meat_list);
+        } else {
+            mAbsListView = (AbsListView) inflater.inflate(
+                    R.layout.fragment_meat_grid, (ViewGroup) mAbsListView.getParent(), false);
+            mAdapter = new MeatAdapter(inflater, R.layout.item_meat_grid);
+        }
+        mAbsListView.setAdapter(mAdapter);
+        // We restore the scrolling position here.
+        mAbsListView.setSelection(first);
+        // The new list is ready, and we replace the existing one with it.
+        mContent.removeAllViews();
+        mContent.addView(mAbsListView);
+    }
+
+    /**
+     * Copy all the visible views in the mAbsListView into a new FrameLayout and return it.
+     *
+     * @return a FrameLayout with all the visible views inside.
+     */
+    private FrameLayout copyVisibleViews() {
+        // This is the FrameLayout we return afterwards.
+        FrameLayout layout = new FrameLayout(getActivity());
+        // The transition framework requires to set ID for all views to be animated.
+        layout.setId(ROOT_ID);
+        // We only copy visible views.
+        int first = mAbsListView.getFirstVisiblePosition();
+        int index = 0;
+        while (true) {
+            // This is one of the views that we copy. Note that the argument for getChildAt is a
+            // zero-oriented index, and it doesn't usually match with its position in the list.
+            View source = mAbsListView.getChildAt(index);
+            if (null == source) {
+                break;
+            }
+            // This is the copy of the original view.
+            View destination = mAdapter.getView(first + index, null, layout);
+            assert destination != null;
+            destination.setId(ROOT_ID + first + index);
+            FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
+                    source.getWidth(), source.getHeight());
+            params.leftMargin = (int) source.getX();
+            params.topMargin = (int) source.getY();
+            layout.addView(destination, params);
+            ++index;
+        }
+        return layout;
+    }
+
+}
diff --git a/samples/browseable/AdapterTransition/src/com.example.android.adaptertransition/MainActivity.java b/samples/browseable/AdapterTransition/src/com.example.android.adaptertransition/MainActivity.java
new file mode 100644
index 0000000..a45632c
--- /dev/null
+++ b/samples/browseable/AdapterTransition/src/com.example.android.adaptertransition/MainActivity.java
@@ -0,0 +1,110 @@
+/*
+* Copyright 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.adaptertransition;
+
+import android.os.Bundle;
+import android.support.v4.app.FragmentTransaction;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.widget.ViewAnimator;
+
+import com.example.android.common.activities.SampleActivityBase;
+import com.example.android.common.logger.Log;
+import com.example.android.common.logger.LogFragment;
+import com.example.android.common.logger.LogWrapper;
+import com.example.android.common.logger.MessageOnlyLogFilter;
+
+/**
+ * A simple launcher activity containing a summary sample description, sample log and a custom
+ * {@link android.support.v4.app.Fragment} which can display a view.
+ * <p>
+ * For devices with displays with a width of 720dp or greater, the sample log is always visible,
+ * on other devices it's visibility is controlled by an item on the Action Bar.
+ */
+public class MainActivity extends SampleActivityBase {
+
+    public static final String TAG = "MainActivity";
+
+    // Whether the Log Fragment is currently shown
+    private boolean mLogShown;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_main);
+
+        FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
+        AdapterTransitionFragment fragment = new AdapterTransitionFragment();
+        transaction.replace(R.id.sample_content_fragment, fragment);
+        transaction.commit();
+    }
+
+    @Override
+    public boolean onCreateOptionsMenu(Menu menu) {
+        getMenuInflater().inflate(R.menu.main, menu);
+        return true;
+    }
+
+    @Override
+    public boolean onPrepareOptionsMenu(Menu menu) {
+        MenuItem logToggle = menu.findItem(R.id.menu_toggle_log);
+        logToggle.setVisible(findViewById(R.id.sample_output) instanceof ViewAnimator);
+        logToggle.setTitle(mLogShown ? R.string.sample_hide_log : R.string.sample_show_log);
+
+        return super.onPrepareOptionsMenu(menu);
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        switch(item.getItemId()) {
+            case R.id.menu_toggle_log:
+                mLogShown = !mLogShown;
+                ViewAnimator output = (ViewAnimator) findViewById(R.id.sample_output);
+                if (mLogShown) {
+                    output.setDisplayedChild(1);
+                } else {
+                    output.setDisplayedChild(0);
+                }
+                supportInvalidateOptionsMenu();
+                return true;
+        }
+        return super.onOptionsItemSelected(item);
+    }
+
+    /** Create a chain of targets that will receive log data */
+    @Override
+    public void initializeLogging() {
+        // Wraps Android's native log framework.
+        LogWrapper logWrapper = new LogWrapper();
+        // Using Log, front-end to the logging chain, emulates android.util.log method signatures.
+        Log.setLogNode(logWrapper);
+
+        // Filter strips out everything except the message text.
+        MessageOnlyLogFilter msgFilter = new MessageOnlyLogFilter();
+        logWrapper.setNext(msgFilter);
+
+        // On screen logging via a fragment with a TextView.
+        LogFragment logFragment = (LogFragment) getSupportFragmentManager()
+                .findFragmentById(R.id.log_fragment);
+        msgFilter.setNext(logFragment.getLogView());
+
+        Log.i(TAG, "Ready");
+    }
+}
diff --git a/samples/browseable/AdapterTransition/src/com.example.android.adaptertransition/Meat.java b/samples/browseable/AdapterTransition/src/com.example.android.adaptertransition/Meat.java
new file mode 100644
index 0000000..bca1c5f
--- /dev/null
+++ b/samples/browseable/AdapterTransition/src/com.example.android.adaptertransition/Meat.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.adaptertransition;
+
+/**
+ * Sample data.
+ */
+public class Meat {
+
+    public int resourceId;
+    public String title;
+
+    public Meat(int resourceId, String title) {
+        this.resourceId = resourceId;
+        this.title = title;
+    }
+
+    public static final Meat[] MEATS = {
+            new Meat(R.drawable.p1, "First"),
+            new Meat(R.drawable.p2, "Second"),
+            new Meat(R.drawable.p3, "Third"),
+            new Meat(R.drawable.p4, "Fourth"),
+            new Meat(R.drawable.p5, "Fifth"),
+            new Meat(R.drawable.p6, "Sixth"),
+            new Meat(R.drawable.p7, "Seventh"),
+            new Meat(R.drawable.p8, "Eighth"),
+            new Meat(R.drawable.p9, "Ninth"),
+            new Meat(R.drawable.p10, "Tenth"),
+            new Meat(R.drawable.p11, "Eleventh"),
+    };
+
+}
diff --git a/samples/browseable/AdapterTransition/src/com.example.android.adaptertransition/MeatAdapter.java b/samples/browseable/AdapterTransition/src/com.example.android.adaptertransition/MeatAdapter.java
new file mode 100644
index 0000000..c7630ce
--- /dev/null
+++ b/samples/browseable/AdapterTransition/src/com.example.android.adaptertransition/MeatAdapter.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.adaptertransition;
+
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.BaseAdapter;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+/**
+ * This class provides data as Views. It is designed to support both ListView and GridView by
+ * changing a layout resource file to inflate.
+ */
+public class MeatAdapter extends BaseAdapter {
+
+    private final LayoutInflater mLayoutInflater;
+    private final int mResourceId;
+
+    /**
+     * Create a new instance of {@link MeatAdapter}.
+     *
+     * @param inflater   The layout inflater.
+     * @param resourceId The resource ID for the layout to be used. The layout should contain an
+     *                   ImageView with ID of "meat_image" and a TextView with ID of "meat_title".
+     */
+    public MeatAdapter(LayoutInflater inflater, int resourceId) {
+        mLayoutInflater = inflater;
+        mResourceId = resourceId;
+    }
+
+    @Override
+    public int getCount() {
+        return Meat.MEATS.length;
+    }
+
+    @Override
+    public Meat getItem(int position) {
+        return Meat.MEATS[position];
+    }
+
+    @Override
+    public long getItemId(int position) {
+        return Meat.MEATS[position].resourceId;
+    }
+
+    @Override
+    public View getView(int position, View convertView, ViewGroup parent) {
+        final View view;
+        final ViewHolder holder;
+        if (null == convertView) {
+            view = mLayoutInflater.inflate(mResourceId, parent, false);
+            holder = new ViewHolder();
+            assert view != null;
+            holder.image = (ImageView) view.findViewById(R.id.meat_image);
+            holder.title = (TextView) view.findViewById(R.id.meat_title);
+            view.setTag(holder);
+        } else {
+            view = convertView;
+            holder = (ViewHolder) view.getTag();
+        }
+        Meat meat = getItem(position);
+        holder.image.setImageResource(meat.resourceId);
+        holder.title.setText(meat.title);
+        return view;
+    }
+
+    private static class ViewHolder {
+        public ImageView image;
+        public TextView title;
+    }
+
+}
diff --git a/samples/browseable/repeatingAlarm/src/com.example.android.common/activities/SampleActivityBase.java b/samples/browseable/AdapterTransition/src/com.example.android.common/activities/SampleActivityBase.java
similarity index 100%
copy from samples/browseable/repeatingAlarm/src/com.example.android.common/activities/SampleActivityBase.java
copy to samples/browseable/AdapterTransition/src/com.example.android.common/activities/SampleActivityBase.java
diff --git a/samples/browseable/repeatingAlarm/src/com.example.android.common/logger/Log.java b/samples/browseable/AdapterTransition/src/com.example.android.common/logger/Log.java
similarity index 100%
copy from samples/browseable/repeatingAlarm/src/com.example.android.common/logger/Log.java
copy to samples/browseable/AdapterTransition/src/com.example.android.common/logger/Log.java
diff --git a/samples/browseable/repeatingAlarm/src/com.example.android.common/logger/LogFragment.java b/samples/browseable/AdapterTransition/src/com.example.android.common/logger/LogFragment.java
similarity index 100%
copy from samples/browseable/repeatingAlarm/src/com.example.android.common/logger/LogFragment.java
copy to samples/browseable/AdapterTransition/src/com.example.android.common/logger/LogFragment.java
diff --git a/samples/browseable/repeatingAlarm/src/com.example.android.common/logger/LogNode.java b/samples/browseable/AdapterTransition/src/com.example.android.common/logger/LogNode.java
similarity index 100%
copy from samples/browseable/repeatingAlarm/src/com.example.android.common/logger/LogNode.java
copy to samples/browseable/AdapterTransition/src/com.example.android.common/logger/LogNode.java
diff --git a/samples/browseable/repeatingAlarm/src/com.example.android.common/logger/LogView.java b/samples/browseable/AdapterTransition/src/com.example.android.common/logger/LogView.java
similarity index 100%
copy from samples/browseable/repeatingAlarm/src/com.example.android.common/logger/LogView.java
copy to samples/browseable/AdapterTransition/src/com.example.android.common/logger/LogView.java
diff --git a/samples/browseable/repeatingAlarm/src/com.example.android.common/logger/LogWrapper.java b/samples/browseable/AdapterTransition/src/com.example.android.common/logger/LogWrapper.java
similarity index 100%
copy from samples/browseable/repeatingAlarm/src/com.example.android.common/logger/LogWrapper.java
copy to samples/browseable/AdapterTransition/src/com.example.android.common/logger/LogWrapper.java
diff --git a/samples/browseable/repeatingAlarm/src/com.example.android.common/logger/MessageOnlyLogFilter.java b/samples/browseable/AdapterTransition/src/com.example.android.common/logger/MessageOnlyLogFilter.java
similarity index 100%
copy from samples/browseable/repeatingAlarm/src/com.example.android.common/logger/MessageOnlyLogFilter.java
copy to samples/browseable/AdapterTransition/src/com.example.android.common/logger/MessageOnlyLogFilter.java
diff --git a/samples/browseable/AdapterTransition/src/com.example.android.common/view/SlidingTabLayout.java b/samples/browseable/AdapterTransition/src/com.example.android.common/view/SlidingTabLayout.java
new file mode 100644
index 0000000..20049e3
--- /dev/null
+++ b/samples/browseable/AdapterTransition/src/com.example.android.common/view/SlidingTabLayout.java
@@ -0,0 +1,314 @@
+/*
+ * 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.common.view;
+
+import android.content.Context;
+import android.graphics.Typeface;
+import android.os.Build;
+import android.support.v4.view.PagerAdapter;
+import android.support.v4.view.ViewPager;
+import android.util.AttributeSet;
+import android.util.TypedValue;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.HorizontalScrollView;
+import android.widget.TextView;
+
+/**
+ * To be used with ViewPager to provide a tab indicator component which give constant feedback as to
+ * the user's scroll progress.
+ * <p>
+ * To use the component, simply add it to your view hierarchy. Then in your
+ * {@link android.app.Activity} or {@link android.support.v4.app.Fragment} call
+ * {@link #setViewPager(ViewPager)} providing it the ViewPager this layout is being used for.
+ * <p>
+ * The colors can be customized in two ways. The first and simplest is to provide an array of colors
+ * via {@link #setSelectedIndicatorColors(int...)} and {@link #setDividerColors(int...)}. The
+ * alternative is via the {@link TabColorizer} interface which provides you complete control over
+ * which color is used for any individual position.
+ * <p>
+ * The views used as tabs can be customized by calling {@link #setCustomTabView(int, int)},
+ * providing the layout ID of your custom layout.
+ */
+public class SlidingTabLayout extends HorizontalScrollView {
+
+    /**
+     * Allows complete control over the colors drawn in the tab layout. Set with
+     * {@link #setCustomTabColorizer(TabColorizer)}.
+     */
+    public interface TabColorizer {
+
+        /**
+         * @return return the color of the indicator used when {@code position} is selected.
+         */
+        int getIndicatorColor(int position);
+
+        /**
+         * @return return the color of the divider drawn to the right of {@code position}.
+         */
+        int getDividerColor(int position);
+
+    }
+
+    private static final int TITLE_OFFSET_DIPS = 24;
+    private static final int TAB_VIEW_PADDING_DIPS = 16;
+    private static final int TAB_VIEW_TEXT_SIZE_SP = 12;
+
+    private int mTitleOffset;
+
+    private int mTabViewLayoutId;
+    private int mTabViewTextViewId;
+
+    private ViewPager mViewPager;
+    private ViewPager.OnPageChangeListener mViewPagerPageChangeListener;
+
+    private final SlidingTabStrip mTabStrip;
+
+    public SlidingTabLayout(Context context) {
+        this(context, null);
+    }
+
+    public SlidingTabLayout(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public SlidingTabLayout(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+
+        // Disable the Scroll Bar
+        setHorizontalScrollBarEnabled(false);
+        // Make sure that the Tab Strips fills this View
+        setFillViewport(true);
+
+        mTitleOffset = (int) (TITLE_OFFSET_DIPS * getResources().getDisplayMetrics().density);
+
+        mTabStrip = new SlidingTabStrip(context);
+        addView(mTabStrip, LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
+    }
+
+    /**
+     * Set the custom {@link TabColorizer} to be used.
+     *
+     * If you only require simple custmisation then you can use
+     * {@link #setSelectedIndicatorColors(int...)} and {@link #setDividerColors(int...)} to achieve
+     * similar effects.
+     */
+    public void setCustomTabColorizer(TabColorizer tabColorizer) {
+        mTabStrip.setCustomTabColorizer(tabColorizer);
+    }
+
+    /**
+     * Sets the colors to be used for indicating the selected tab. These colors are treated as a
+     * circular array. Providing one color will mean that all tabs are indicated with the same color.
+     */
+    public void setSelectedIndicatorColors(int... colors) {
+        mTabStrip.setSelectedIndicatorColors(colors);
+    }
+
+    /**
+     * Sets the colors to be used for tab dividers. These colors are treated as a circular array.
+     * Providing one color will mean that all tabs are indicated with the same color.
+     */
+    public void setDividerColors(int... colors) {
+        mTabStrip.setDividerColors(colors);
+    }
+
+    /**
+     * Set the {@link ViewPager.OnPageChangeListener}. When using {@link SlidingTabLayout} you are
+     * required to set any {@link ViewPager.OnPageChangeListener} through this method. This is so
+     * that the layout can update it's scroll position correctly.
+     *
+     * @see ViewPager#setOnPageChangeListener(ViewPager.OnPageChangeListener)
+     */
+    public void setOnPageChangeListener(ViewPager.OnPageChangeListener listener) {
+        mViewPagerPageChangeListener = listener;
+    }
+
+    /**
+     * Set the custom layout to be inflated for the tab views.
+     *
+     * @param layoutResId Layout id to be inflated
+     * @param textViewId id of the {@link TextView} in the inflated view
+     */
+    public void setCustomTabView(int layoutResId, int textViewId) {
+        mTabViewLayoutId = layoutResId;
+        mTabViewTextViewId = textViewId;
+    }
+
+    /**
+     * Sets the associated view pager. Note that the assumption here is that the pager content
+     * (number of tabs and tab titles) does not change after this call has been made.
+     */
+    public void setViewPager(ViewPager viewPager) {
+        mTabStrip.removeAllViews();
+
+        mViewPager = viewPager;
+        if (viewPager != null) {
+            viewPager.setOnPageChangeListener(new InternalViewPagerListener());
+            populateTabStrip();
+        }
+    }
+
+    /**
+     * Create a default view to be used for tabs. This is called if a custom tab view is not set via
+     * {@link #setCustomTabView(int, int)}.
+     */
+    protected TextView createDefaultTabView(Context context) {
+        TextView textView = new TextView(context);
+        textView.setGravity(Gravity.CENTER);
+        textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, TAB_VIEW_TEXT_SIZE_SP);
+        textView.setTypeface(Typeface.DEFAULT_BOLD);
+
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
+            // If we're running on Honeycomb or newer, then we can use the Theme's
+            // selectableItemBackground to ensure that the View has a pressed state
+            TypedValue outValue = new TypedValue();
+            getContext().getTheme().resolveAttribute(android.R.attr.selectableItemBackground,
+                    outValue, true);
+            textView.setBackgroundResource(outValue.resourceId);
+        }
+
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
+            // If we're running on ICS or newer, enable all-caps to match the Action Bar tab style
+            textView.setAllCaps(true);
+        }
+
+        int padding = (int) (TAB_VIEW_PADDING_DIPS * getResources().getDisplayMetrics().density);
+        textView.setPadding(padding, padding, padding, padding);
+
+        return textView;
+    }
+
+    private void populateTabStrip() {
+        final PagerAdapter adapter = mViewPager.getAdapter();
+        final View.OnClickListener tabClickListener = new TabClickListener();
+
+        for (int i = 0; i < adapter.getCount(); i++) {
+            View tabView = null;
+            TextView tabTitleView = null;
+
+            if (mTabViewLayoutId != 0) {
+                // If there is a custom tab view layout id set, try and inflate it
+                tabView = LayoutInflater.from(getContext()).inflate(mTabViewLayoutId, mTabStrip,
+                        false);
+                tabTitleView = (TextView) tabView.findViewById(mTabViewTextViewId);
+            }
+
+            if (tabView == null) {
+                tabView = createDefaultTabView(getContext());
+            }
+
+            if (tabTitleView == null && TextView.class.isInstance(tabView)) {
+                tabTitleView = (TextView) tabView;
+            }
+
+            tabTitleView.setText(adapter.getPageTitle(i));
+            tabView.setOnClickListener(tabClickListener);
+
+            mTabStrip.addView(tabView);
+        }
+    }
+
+    @Override
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+
+        if (mViewPager != null) {
+            scrollToTab(mViewPager.getCurrentItem(), 0);
+        }
+    }
+
+    private void scrollToTab(int tabIndex, int positionOffset) {
+        final int tabStripChildCount = mTabStrip.getChildCount();
+        if (tabStripChildCount == 0 || tabIndex < 0 || tabIndex >= tabStripChildCount) {
+            return;
+        }
+
+        View selectedChild = mTabStrip.getChildAt(tabIndex);
+        if (selectedChild != null) {
+            int targetScrollX = selectedChild.getLeft() + positionOffset;
+
+            if (tabIndex > 0 || positionOffset > 0) {
+                // If we're not at the first child and are mid-scroll, make sure we obey the offset
+                targetScrollX -= mTitleOffset;
+            }
+
+            scrollTo(targetScrollX, 0);
+        }
+    }
+
+    private class InternalViewPagerListener implements ViewPager.OnPageChangeListener {
+        private int mScrollState;
+
+        @Override
+        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
+            int tabStripChildCount = mTabStrip.getChildCount();
+            if ((tabStripChildCount == 0) || (position < 0) || (position >= tabStripChildCount)) {
+                return;
+            }
+
+            mTabStrip.onViewPagerPageChanged(position, positionOffset);
+
+            View selectedTitle = mTabStrip.getChildAt(position);
+            int extraOffset = (selectedTitle != null)
+                    ? (int) (positionOffset * selectedTitle.getWidth())
+                    : 0;
+            scrollToTab(position, extraOffset);
+
+            if (mViewPagerPageChangeListener != null) {
+                mViewPagerPageChangeListener.onPageScrolled(position, positionOffset,
+                        positionOffsetPixels);
+            }
+        }
+
+        @Override
+        public void onPageScrollStateChanged(int state) {
+            mScrollState = state;
+
+            if (mViewPagerPageChangeListener != null) {
+                mViewPagerPageChangeListener.onPageScrollStateChanged(state);
+            }
+        }
+
+        @Override
+        public void onPageSelected(int position) {
+            if (mScrollState == ViewPager.SCROLL_STATE_IDLE) {
+                mTabStrip.onViewPagerPageChanged(position, 0f);
+                scrollToTab(position, 0);
+            }
+
+            if (mViewPagerPageChangeListener != null) {
+                mViewPagerPageChangeListener.onPageSelected(position);
+            }
+        }
+
+    }
+
+    private class TabClickListener implements View.OnClickListener {
+        @Override
+        public void onClick(View v) {
+            for (int i = 0; i < mTabStrip.getChildCount(); i++) {
+                if (v == mTabStrip.getChildAt(i)) {
+                    mViewPager.setCurrentItem(i);
+                    return;
+                }
+            }
+        }
+    }
+
+}
diff --git a/samples/browseable/AdapterTransition/src/com.example.android.common/view/SlidingTabStrip.java b/samples/browseable/AdapterTransition/src/com.example.android.common/view/SlidingTabStrip.java
new file mode 100644
index 0000000..d5bbbae
--- /dev/null
+++ b/samples/browseable/AdapterTransition/src/com.example.android.common/view/SlidingTabStrip.java
@@ -0,0 +1,208 @@
+/*
+ * 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.common.view;
+
+import android.R;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.util.AttributeSet;
+import android.util.TypedValue;
+import android.view.View;
+import android.widget.LinearLayout;
+
+class SlidingTabStrip extends LinearLayout {
+
+    private static final int DEFAULT_BOTTOM_BORDER_THICKNESS_DIPS = 2;
+    private static final byte DEFAULT_BOTTOM_BORDER_COLOR_ALPHA = 0x26;
+    private static final int SELECTED_INDICATOR_THICKNESS_DIPS = 8;
+    private static final int DEFAULT_SELECTED_INDICATOR_COLOR = 0xFF33B5E5;
+
+    private static final int DEFAULT_DIVIDER_THICKNESS_DIPS = 1;
+    private static final byte DEFAULT_DIVIDER_COLOR_ALPHA = 0x20;
+    private static final float DEFAULT_DIVIDER_HEIGHT = 0.5f;
+
+    private final int mBottomBorderThickness;
+    private final Paint mBottomBorderPaint;
+
+    private final int mSelectedIndicatorThickness;
+    private final Paint mSelectedIndicatorPaint;
+
+    private final int mDefaultBottomBorderColor;
+
+    private final Paint mDividerPaint;
+    private final float mDividerHeight;
+
+    private int mSelectedPosition;
+    private float mSelectionOffset;
+
+    private SlidingTabLayout.TabColorizer mCustomTabColorizer;
+    private final SimpleTabColorizer mDefaultTabColorizer;
+
+    SlidingTabStrip(Context context) {
+        this(context, null);
+    }
+
+    SlidingTabStrip(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        setWillNotDraw(false);
+
+        final float density = getResources().getDisplayMetrics().density;
+
+        TypedValue outValue = new TypedValue();
+        context.getTheme().resolveAttribute(R.attr.colorForeground, outValue, true);
+        final int themeForegroundColor =  outValue.data;
+
+        mDefaultBottomBorderColor = setColorAlpha(themeForegroundColor,
+                DEFAULT_BOTTOM_BORDER_COLOR_ALPHA);
+
+        mDefaultTabColorizer = new SimpleTabColorizer();
+        mDefaultTabColorizer.setIndicatorColors(DEFAULT_SELECTED_INDICATOR_COLOR);
+        mDefaultTabColorizer.setDividerColors(setColorAlpha(themeForegroundColor,
+                DEFAULT_DIVIDER_COLOR_ALPHA));
+
+        mBottomBorderThickness = (int) (DEFAULT_BOTTOM_BORDER_THICKNESS_DIPS * density);
+        mBottomBorderPaint = new Paint();
+        mBottomBorderPaint.setColor(mDefaultBottomBorderColor);
+
+        mSelectedIndicatorThickness = (int) (SELECTED_INDICATOR_THICKNESS_DIPS * density);
+        mSelectedIndicatorPaint = new Paint();
+
+        mDividerHeight = DEFAULT_DIVIDER_HEIGHT;
+        mDividerPaint = new Paint();
+        mDividerPaint.setStrokeWidth((int) (DEFAULT_DIVIDER_THICKNESS_DIPS * density));
+    }
+
+    void setCustomTabColorizer(SlidingTabLayout.TabColorizer customTabColorizer) {
+        mCustomTabColorizer = customTabColorizer;
+        invalidate();
+    }
+
+    void setSelectedIndicatorColors(int... colors) {
+        // Make sure that the custom colorizer is removed
+        mCustomTabColorizer = null;
+        mDefaultTabColorizer.setIndicatorColors(colors);
+        invalidate();
+    }
+
+    void setDividerColors(int... colors) {
+        // Make sure that the custom colorizer is removed
+        mCustomTabColorizer = null;
+        mDefaultTabColorizer.setDividerColors(colors);
+        invalidate();
+    }
+
+    void onViewPagerPageChanged(int position, float positionOffset) {
+        mSelectedPosition = position;
+        mSelectionOffset = positionOffset;
+        invalidate();
+    }
+
+    @Override
+    protected void onDraw(Canvas canvas) {
+        final int height = getHeight();
+        final int childCount = getChildCount();
+        final int dividerHeightPx = (int) (Math.min(Math.max(0f, mDividerHeight), 1f) * height);
+        final SlidingTabLayout.TabColorizer tabColorizer = mCustomTabColorizer != null
+                ? mCustomTabColorizer
+                : mDefaultTabColorizer;
+
+        // Thick colored underline below the current selection
+        if (childCount > 0) {
+            View selectedTitle = getChildAt(mSelectedPosition);
+            int left = selectedTitle.getLeft();
+            int right = selectedTitle.getRight();
+            int color = tabColorizer.getIndicatorColor(mSelectedPosition);
+
+            if (mSelectionOffset > 0f && mSelectedPosition < (getChildCount() - 1)) {
+                int nextColor = tabColorizer.getIndicatorColor(mSelectedPosition + 1);
+                if (color != nextColor) {
+                    color = blendColors(nextColor, color, mSelectionOffset);
+                }
+
+                // Draw the selection partway between the tabs
+                View nextTitle = getChildAt(mSelectedPosition + 1);
+                left = (int) (mSelectionOffset * nextTitle.getLeft() +
+                        (1.0f - mSelectionOffset) * left);
+                right = (int) (mSelectionOffset * nextTitle.getRight() +
+                        (1.0f - mSelectionOffset) * right);
+            }
+
+            mSelectedIndicatorPaint.setColor(color);
+
+            canvas.drawRect(left, height - mSelectedIndicatorThickness, right,
+                    height, mSelectedIndicatorPaint);
+        }
+
+        // Thin underline along the entire bottom edge
+        canvas.drawRect(0, height - mBottomBorderThickness, getWidth(), height, mBottomBorderPaint);
+
+        // Vertical separators between the titles
+        int separatorTop = (height - dividerHeightPx) / 2;
+        for (int i = 0; i < childCount - 1; i++) {
+            View child = getChildAt(i);
+            mDividerPaint.setColor(tabColorizer.getDividerColor(i));
+            canvas.drawLine(child.getRight(), separatorTop, child.getRight(),
+                    separatorTop + dividerHeightPx, mDividerPaint);
+        }
+    }
+
+    /**
+     * Set the alpha value of the {@code color} to be the given {@code alpha} value.
+     */
+    private static int setColorAlpha(int color, byte alpha) {
+        return Color.argb(alpha, Color.red(color), Color.green(color), Color.blue(color));
+    }
+
+    /**
+     * Blend {@code color1} and {@code color2} using the given ratio.
+     *
+     * @param ratio of which to blend. 1.0 will return {@code color1}, 0.5 will give an even blend,
+     *              0.0 will return {@code color2}.
+     */
+    private static int blendColors(int color1, int color2, float ratio) {
+        final float inverseRation = 1f - ratio;
+        float r = (Color.red(color1) * ratio) + (Color.red(color2) * inverseRation);
+        float g = (Color.green(color1) * ratio) + (Color.green(color2) * inverseRation);
+        float b = (Color.blue(color1) * ratio) + (Color.blue(color2) * inverseRation);
+        return Color.rgb((int) r, (int) g, (int) b);
+    }
+
+    private static class SimpleTabColorizer implements SlidingTabLayout.TabColorizer {
+        private int[] mIndicatorColors;
+        private int[] mDividerColors;
+
+        @Override
+        public final int getIndicatorColor(int position) {
+            return mIndicatorColors[position % mIndicatorColors.length];
+        }
+
+        @Override
+        public final int getDividerColor(int position) {
+            return mDividerColors[position % mDividerColors.length];
+        }
+
+        void setIndicatorColors(int... colors) {
+            mIndicatorColors = colors;
+        }
+
+        void setDividerColors(int... colors) {
+            mDividerColors = colors;
+        }
+    }
+}
\ No newline at end of file
diff --git a/samples/browseable/AdvancedImmersiveMode/_index.jd b/samples/browseable/AdvancedImmersiveMode/_index.jd
index 2b19c9c..7048fe8 100644
--- a/samples/browseable/AdvancedImmersiveMode/_index.jd
+++ b/samples/browseable/AdvancedImmersiveMode/_index.jd
@@ -5,10 +5,15 @@
 sample.group=UI
 @jd:body
 
-<p>Android 4.4 introduces a way for you to provide a more immersive screen
-experience in your app, by letting users show or hide the status bar and
-navigation bar with a swipe.</p>
-<p>This sample demonstrates how this features interacts with some of the other
+<p>
+Android 4.4 introduces a way for you to provide a more immersive screen
+experience in your app by letting users show or hide the status bar and
+the navigation bar with a swipe.
+</p>
+
+<p>
+This sample demonstrates how this feature interacts with some of the other
 UI flags related to full-screen apps. The sample also shows how to implement a
 "sticky" mode, which re-hides the bars a few seconds after the user swipes
-them back in.</p>
+them back in.
+</p>
\ No newline at end of file
diff --git a/samples/browseable/AdvancedImmersiveMode/res/drawable-hdpi/ic_launcher.png b/samples/browseable/AdvancedImmersiveMode/res/drawable-hdpi/ic_launcher.png
index b1efaf4..b96e6a5 100644
--- a/samples/browseable/AdvancedImmersiveMode/res/drawable-hdpi/ic_launcher.png
+++ b/samples/browseable/AdvancedImmersiveMode/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/AdvancedImmersiveMode/res/drawable-mdpi/ic_launcher.png b/samples/browseable/AdvancedImmersiveMode/res/drawable-mdpi/ic_launcher.png
index f5f9244..1294d5b 100644
--- a/samples/browseable/AdvancedImmersiveMode/res/drawable-mdpi/ic_launcher.png
+++ b/samples/browseable/AdvancedImmersiveMode/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/AdvancedImmersiveMode/res/drawable-xhdpi/ic_launcher.png b/samples/browseable/AdvancedImmersiveMode/res/drawable-xhdpi/ic_launcher.png
index 5d07b3f..9f101ff 100644
--- a/samples/browseable/AdvancedImmersiveMode/res/drawable-xhdpi/ic_launcher.png
+++ b/samples/browseable/AdvancedImmersiveMode/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/AdvancedImmersiveMode/res/drawable-xxhdpi/ic_launcher.png b/samples/browseable/AdvancedImmersiveMode/res/drawable-xxhdpi/ic_launcher.png
index 6ef21e1..7a195a1 100644
--- a/samples/browseable/AdvancedImmersiveMode/res/drawable-xxhdpi/ic_launcher.png
+++ b/samples/browseable/AdvancedImmersiveMode/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/AdvancedImmersiveMode/res/layout-w720dp/activity_main.xml b/samples/browseable/AdvancedImmersiveMode/res/layout-w720dp/activity_main.xml
new file mode 100755
index 0000000..c9a52f6
--- /dev/null
+++ b/samples/browseable/AdvancedImmersiveMode/res/layout-w720dp/activity_main.xml
@@ -0,0 +1,73 @@
+<!--
+  Copyright 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"
+      android:orientation="horizontal"
+      android:layout_width="match_parent"
+      android:layout_height="match_parent"
+      android:id="@+id/sample_main_layout">
+
+    <LinearLayout
+          android:id="@+id/sample_output"
+          android:layout_width="0px"
+          android:layout_height="match_parent"
+          android:layout_weight="1"
+          android:orientation="vertical">
+
+        <FrameLayout
+              style="@style/Widget.SampleMessageTile"
+              android:layout_width="match_parent"
+              android:layout_height="wrap_content">
+
+            <TextView
+                  style="@style/Widget.SampleMessage"
+                  android:layout_width="match_parent"
+                  android:layout_height="wrap_content"
+                  android:paddingLeft="@dimen/margin_medium"
+                  android:paddingRight="@dimen/margin_medium"
+                  android:paddingTop="@dimen/margin_large"
+                  android:paddingBottom="@dimen/margin_large"
+                  android:text="@string/intro_message" />
+        </FrameLayout>
+
+        <View
+              android:layout_width="match_parent"
+              android:layout_height="1dp"
+              android:background="@android:color/darker_gray" />
+
+        <fragment
+              android:name="com.example.android.common.logger.LogFragment"
+              android:id="@+id/log_fragment"
+              android:layout_width="match_parent"
+              android:layout_height="0px"
+              android:layout_weight="1" />
+
+    </LinearLayout>
+
+    <View
+          android:layout_width="1dp"
+          android:layout_height="match_parent"
+          android:background="@android:color/darker_gray" />
+
+    <FrameLayout
+          android:id="@+id/sample_content_fragment"
+          android:layout_weight="2"
+          android:layout_width="0px"
+          android:layout_height="match_parent" />
+
+</LinearLayout>
+
+
diff --git a/samples/browseable/AdvancedImmersiveMode/res/layout/activity_main.xml b/samples/browseable/AdvancedImmersiveMode/res/layout/activity_main.xml
index bc5a575..1ae4f98 100755
--- a/samples/browseable/AdvancedImmersiveMode/res/layout/activity_main.xml
+++ b/samples/browseable/AdvancedImmersiveMode/res/layout/activity_main.xml
@@ -14,25 +14,52 @@
   limitations under the License.
   -->
 <LinearLayout
-        xmlns:android="http://schemas.android.com/apk/res/android"
-        android:orientation="vertical"
-        android:layout_width="fill_parent"
-        android:layout_height="fill_parent"
-        android:id="@+id/sample_main_layout">
-    <TextView android:id="@+id/sample_output"
-              style="@style/Widget.SampleMessage"
-              android:layout_weight="1"
+      xmlns:android="http://schemas.android.com/apk/res/android"
+      android:orientation="vertical"
+      android:layout_width="match_parent"
+      android:layout_height="match_parent"
+      android:id="@+id/sample_main_layout">
+
+    <ViewAnimator
+          android:id="@+id/sample_output"
+          android:layout_width="match_parent"
+          android:layout_height="0px"
+          android:layout_weight="1">
+
+        <ScrollView
+              style="@style/Widget.SampleMessageTile"
               android:layout_width="match_parent"
-              android:layout_height="match_parent"
-              android:text="@string/intro_message" />
+              android:layout_height="match_parent">
+
+            <TextView
+                  style="@style/Widget.SampleMessage"
+                  android:layout_width="match_parent"
+                  android:layout_height="wrap_content"
+                  android:paddingLeft="@dimen/horizontal_page_margin"
+                  android:paddingRight="@dimen/horizontal_page_margin"
+                  android:paddingTop="@dimen/vertical_page_margin"
+                  android:paddingBottom="@dimen/vertical_page_margin"
+                  android:text="@string/intro_message" />
+        </ScrollView>
+
+        <fragment
+              android:name="com.example.android.common.logger.LogFragment"
+              android:id="@+id/log_fragment"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent" />
+
+    </ViewAnimator>
+
     <View
-            android:layout_width="fill_parent"
-            android:layout_height="1dp"
-            android:background="@android:color/darker_gray"/>
-    <fragment
-            android:name="com.example.android.common.logger.LogFragment"
-            android:id="@+id/log_fragment"
-            android:layout_weight="1"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent" />
+          android:layout_width="match_parent"
+          android:layout_height="1dp"
+          android:background="@android:color/darker_gray" />
+
+    <FrameLayout
+          android:id="@+id/sample_content_fragment"
+          android:layout_weight="2"
+          android:layout_width="match_parent"
+          android:layout_height="0px" />
+
 </LinearLayout>
+
diff --git a/samples/browseable/AdvancedImmersiveMode/res/layout/fragment_flags.xml b/samples/browseable/AdvancedImmersiveMode/res/layout/fragment_flags.xml
new file mode 100644
index 0000000..2c74e83
--- /dev/null
+++ b/samples/browseable/AdvancedImmersiveMode/res/layout/fragment_flags.xml
@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="vertical" android:layout_width="match_parent"
+    android:layout_height="wrap_content">
+
+    <CheckBox
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:id="@+id/flag_enable_lowprof"
+        android:text="Enable Low Profile Mode" />
+
+    <CheckBox
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:id="@+id/flag_hide_navbar"
+        android:text="Hide Navigation bar" />
+
+    <CheckBox
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:id="@+id/flag_hide_statbar"
+        android:text="Hide Status Bar" />
+
+    <CheckBox
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:id="@+id/flag_enable_immersive"
+        android:text="Enable Immersive Mode" />
+
+    <CheckBox
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:id="@+id/flag_enable_immersive_sticky"
+        android:text="Enable Immersive Mode (Sticky)" />
+
+    <Button
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="Do things!"
+        android:id="@+id/btn_changeFlags" />
+
+
+    <TextView
+        android:layout_marginTop="@dimen/margin_large"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="Common flag presets"/>
+    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+        android:orientation="horizontal" android:layout_width="match_parent"
+        android:layout_height="wrap_content">
+
+        <Button
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="Immersive Mode"
+            android:id="@+id/btn_immersive" />
+
+        <Button
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="Leanback Mode"
+            android:id="@+id/btn_leanback" />
+
+    </LinearLayout>
+
+
+
+</LinearLayout>
\ No newline at end of file
diff --git a/samples/browseable/AdvancedImmersiveMode/res/menu/main.xml b/samples/browseable/AdvancedImmersiveMode/res/menu/main.xml
index 2c3515d..b49c2c5 100644
--- a/samples/browseable/AdvancedImmersiveMode/res/menu/main.xml
+++ b/samples/browseable/AdvancedImmersiveMode/res/menu/main.xml
@@ -15,7 +15,7 @@
   -->
 
 <menu xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:id="@+id/sample_action"
-          android:showAsAction="ifRoom|withText"
-          android:title="@string/sample_action" />
+    <item android:id="@+id/menu_toggle_log"
+          android:showAsAction="always"
+          android:title="@string/sample_show_log" />
 </menu>
diff --git a/samples/browseable/AdvancedImmersiveMode/res/values-sw600dp/dimens.xml b/samples/browseable/AdvancedImmersiveMode/res/values-sw600dp/template-dimens.xml
similarity index 100%
rename from samples/browseable/AdvancedImmersiveMode/res/values-sw600dp/dimens.xml
rename to samples/browseable/AdvancedImmersiveMode/res/values-sw600dp/template-dimens.xml
diff --git a/samples/browseable/AdvancedImmersiveMode/res/values-sw600dp/styles.xml b/samples/browseable/AdvancedImmersiveMode/res/values-sw600dp/template-styles.xml
similarity index 100%
rename from samples/browseable/AdvancedImmersiveMode/res/values-sw600dp/styles.xml
rename to samples/browseable/AdvancedImmersiveMode/res/values-sw600dp/template-styles.xml
diff --git a/samples/browseable/AdvancedImmersiveMode/res/values/base-strings.xml b/samples/browseable/AdvancedImmersiveMode/res/values/base-strings.xml
index 305e12a..8e4c710 100644
--- a/samples/browseable/AdvancedImmersiveMode/res/values/base-strings.xml
+++ b/samples/browseable/AdvancedImmersiveMode/res/values/base-strings.xml
@@ -23,13 +23,10 @@
         <![CDATA[
         
             
-            \"Immersive Mode\" is a new UI mode which improves \"hide full screen\" and
+            \n\n\n\"Immersive Mode\", added in Android 4.4, improves the \"hide full screen\" and
             \"hide nav bar\" modes, by letting users swipe the bars in and out.  This sample
-            lets the user experiment with immersive mode by enabling it and seeing how it interacts
+            lets the user experiment with immersive mode by seeing how it interacts
             with some of the other UI flags related to full-screen apps.
-            \n\nThis sample also lets the user choose between normal immersive mode and "sticky"
-            immersive mode, which removes the status bar and nav bar
-            a few seconds after the user has swiped them back in.
             
         
         ]]>
diff --git a/samples/browseable/AdvancedImmersiveMode/res/values/strings.xml b/samples/browseable/AdvancedImmersiveMode/res/values/strings.xml
old mode 100644
new mode 100755
index a65b891..7b9d9ec
--- a/samples/browseable/AdvancedImmersiveMode/res/values/strings.xml
+++ b/samples/browseable/AdvancedImmersiveMode/res/values/strings.xml
@@ -1,22 +1,19 @@
-<?xml version="1.0" encoding="UTF-8"?>
 <!--
- Copyright 2013 The Android Open Source Project
+  Copyright 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
+  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
+      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.
+  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="sample_action">Try these settings!</string>
+    <string name="sample_show_log">Show Log</string>
+    <string name="sample_hide_log">Hide Log</string>
 </resources>
diff --git a/samples/browseable/AdvancedImmersiveMode/res/values/dimens.xml b/samples/browseable/AdvancedImmersiveMode/res/values/template-dimens.xml
similarity index 100%
rename from samples/browseable/AdvancedImmersiveMode/res/values/dimens.xml
rename to samples/browseable/AdvancedImmersiveMode/res/values/template-dimens.xml
diff --git a/samples/browseable/AppRestrictions/res/values/styles.xml b/samples/browseable/AdvancedImmersiveMode/res/values/template-styles.xml
similarity index 100%
copy from samples/browseable/AppRestrictions/res/values/styles.xml
copy to samples/browseable/AdvancedImmersiveMode/res/values/template-styles.xml
diff --git a/samples/browseable/AdvancedImmersiveMode/src/com.example.android.advancedimmersivemode/AdvancedImmersiveModeFragment.java b/samples/browseable/AdvancedImmersiveMode/src/com.example.android.advancedimmersivemode/AdvancedImmersiveModeFragment.java
index fe11ecb..d8fb0d4 100644
--- a/samples/browseable/AdvancedImmersiveMode/src/com.example.android.advancedimmersivemode/AdvancedImmersiveModeFragment.java
+++ b/samples/browseable/AdvancedImmersiveMode/src/com.example.android.advancedimmersivemode/AdvancedImmersiveModeFragment.java
@@ -17,9 +17,10 @@
 
 import android.os.Bundle;
 import android.support.v4.app.Fragment;
-import android.view.MenuItem;
+import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
+import android.widget.Button;
 import android.widget.CheckBox;
 
 import com.example.android.common.logger.Log;
@@ -46,49 +47,136 @@
     }
 
     @Override
-    public void onActivityCreated(Bundle savedInstanceState) {
-        super.onActivityCreated(savedInstanceState);
+    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle state) {
+        final View flagsView = inflater.inflate(R.layout.fragment_flags, container, false);
+        mLowProfileCheckBox = (CheckBox) flagsView.findViewById(R.id.flag_enable_lowprof);
+        mHideNavCheckbox = (CheckBox) flagsView.findViewById(R.id.flag_hide_navbar);
+        mHideStatusBarCheckBox = (CheckBox) flagsView.findViewById(R.id.flag_hide_statbar);
+        mImmersiveModeCheckBox = (CheckBox) flagsView.findViewById(R.id.flag_enable_immersive);
+        mImmersiveModeStickyCheckBox =
+                (CheckBox) flagsView.findViewById(R.id.flag_enable_immersive_sticky);
 
-        final View decorView = getActivity().getWindow().getDecorView();
-        ViewGroup parentView = (ViewGroup) getActivity().getWindow().getDecorView()
-                .findViewById(R.id.sample_main_layout);
+        Button toggleFlagsButton = (Button) flagsView.findViewById(R.id.btn_changeFlags);
+        toggleFlagsButton.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View view) {
+                toggleUiFlags();
+            }
+        });
 
-        mLowProfileCheckBox = new CheckBox(getActivity());
-        mLowProfileCheckBox.setText("Enable Low Profile mode.");
-        parentView.addView(mLowProfileCheckBox);
+        Button presetsImmersiveModeButton = (Button) flagsView.findViewById(R.id.btn_immersive);
+        presetsImmersiveModeButton.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View view) {
 
-        mHideNavCheckbox = new CheckBox(getActivity());
-        mHideNavCheckbox.setChecked(true);
-        mHideNavCheckbox.setText("Hide Navigation bar");
-        parentView.addView(mHideNavCheckbox);
+                // BEGIN_INCLUDE(immersive_presets)
+                // For immersive mode, the FULLSCREEN, HIDE_HAVIGATION and IMMERSIVE
+                // flags should be set (you can use IMMERSIVE_STICKY instead of IMMERSIVE
+                // as appropriate for your app).  The LOW_PROFILE flag should be cleared.
 
-        mHideStatusBarCheckBox = new CheckBox(getActivity());
-        mHideStatusBarCheckBox.setChecked(true);
-        mHideStatusBarCheckBox.setText("Hide Status Bar");
-        parentView.addView(mHideStatusBarCheckBox);
+                // Immersive mode is primarily for situations where the user will be
+                // interacting with the screen, like games or reading books.
+                int uiOptions = flagsView.getSystemUiVisibility();
+                uiOptions &= ~View.SYSTEM_UI_FLAG_LOW_PROFILE;
+                uiOptions |= View.SYSTEM_UI_FLAG_FULLSCREEN;
+                uiOptions |= View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
+                uiOptions |= View.SYSTEM_UI_FLAG_IMMERSIVE;
+                uiOptions &= ~View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
+                flagsView.setSystemUiVisibility(uiOptions);
+                // END_INCLUDE(immersive_presets)
 
-        mImmersiveModeCheckBox = new CheckBox(getActivity());
-        mImmersiveModeCheckBox.setText("Enable Immersive Mode.");
-        parentView.addView(mImmersiveModeCheckBox);
+                dumpFlagStateToLog(uiOptions);
 
-        mImmersiveModeStickyCheckBox = new CheckBox(getActivity());
-        mImmersiveModeStickyCheckBox.setText("Enable Immersive Mode (Sticky)");
-        parentView.addView(mImmersiveModeStickyCheckBox);
+                // The below code just updates the checkboxes to reflect which flags have been set.
+                mLowProfileCheckBox.setChecked(false);
+                mHideNavCheckbox.setChecked(true);
+                mHideStatusBarCheckBox.setChecked(true);
+                mImmersiveModeCheckBox.setChecked(true);
+                mImmersiveModeStickyCheckBox.setChecked(false);
+            }
+        });
 
+
+        Button presetsLeanbackModeButton = (Button) flagsView.findViewById(R.id.btn_leanback);
+        presetsLeanbackModeButton.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View view) {
+                // BEGIN_INCLUDE(leanback_presets)
+                // For leanback mode, only the HIDE_NAVE and HIDE_STATUSBAR flags
+                // should be checked.  In this case IMMERSIVE should *not* be set,
+                // since this mode is left as soon as the user touches the screen.
+                int uiOptions = flagsView.getSystemUiVisibility();
+                uiOptions &= ~View.SYSTEM_UI_FLAG_LOW_PROFILE;
+                uiOptions |= View.SYSTEM_UI_FLAG_FULLSCREEN;
+                uiOptions |= View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
+                uiOptions &= ~View.SYSTEM_UI_FLAG_IMMERSIVE;
+                uiOptions &= ~View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
+                flagsView.setSystemUiVisibility(uiOptions);
+                // END_INCLUDE(leanback_presets)
+
+                dumpFlagStateToLog(uiOptions);
+
+                // The below code just updates the checkboxes to reflect which flags have been set.
+                mLowProfileCheckBox.setChecked(false);
+                mHideNavCheckbox.setChecked(true);
+                mHideStatusBarCheckBox.setChecked(true);
+                mImmersiveModeCheckBox.setChecked(false);
+                mImmersiveModeStickyCheckBox.setChecked(false);
+            }
+        });
+
+        // Setting these flags makes the content appear under the navigation
+        // bars, so that showing/hiding the nav bars doesn't resize the content
+        // window, which can be jarring.
+        int uiOptions = flagsView.getSystemUiVisibility();
+        uiOptions |= View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
+        uiOptions |= View.SYSTEM_UI_FLAG_LAYOUT_STABLE;
+        uiOptions |= View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
+        flagsView.setSystemUiVisibility(uiOptions);
+
+        return flagsView;
     }
 
-    @Override
-    public boolean onOptionsItemSelected(MenuItem item) {
-        if (item.getItemId() == R.id.sample_action) {
-            toggleImmersiveMode();
+    /**
+     * Helper method to dump flag state to the log.
+     * @param uiFlags Set of UI flags to inspect
+     */
+    public void dumpFlagStateToLog(int uiFlags) {
+        if ((uiFlags & View.SYSTEM_UI_FLAG_LOW_PROFILE) != 0) {
+            Log.i(TAG, "SYSTEM_UI_FLAG_LOW_PROFILE is set");
+        } else {
+            Log.i(TAG, "SYSTEM_UI_FLAG_LOW_PROFILE is unset");
         }
-        return true;
+
+        if ((uiFlags & View.SYSTEM_UI_FLAG_FULLSCREEN) != 0) {
+            Log.i(TAG, "SYSTEM_UI_FLAG_FULLSCREEN is set");
+        } else {
+            Log.i(TAG, "SYSTEM_UI_FLAG_FULLSCREEN is unset");
+        }
+
+        if ((uiFlags & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0) {
+            Log.i(TAG, "SYSTEM_UI_FLAG_HIDE_NAVIGATION is set");
+        } else {
+            Log.i(TAG, "SYSTEM_UI_FLAG_HIDE_NAVIGATION is unset");
+        }
+
+        if ((uiFlags & View.SYSTEM_UI_FLAG_IMMERSIVE) != 0) {
+            Log.i(TAG, "SYSTEM_UI_FLAG_IMMERSIVE is set");
+        } else {
+            Log.i(TAG, "SYSTEM_UI_FLAG_IMMERSIVE is unset");
+        }
+
+        if ((uiFlags & View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY) != 0) {
+            Log.i(TAG, "SYSTEM_UI_FLAG_IMMERSIVE_STICKY is set");
+        } else {
+            Log.i(TAG, "SYSTEM_UI_FLAG_IMMERSIVE_STICKY is unset");
+        }
     }
 
     /**
      * Detects and toggles immersive mode (also known as "hidey bar" mode).
      */
-    public void toggleImmersiveMode() {
+    public void toggleUiFlags() {
 
         // BEGIN_INCLUDE (get_current_ui_flags)
         // The "Decor View" is the parent view of the Activity.  It's also conveniently the easiest
@@ -168,7 +256,8 @@
         // BEGIN_INCLUDE (set_ui_flags)
         //Set the new UI flags.
         decorView.setSystemUiVisibility(newUiOptions);
-        Log.i(TAG, "Current height: " + decorView.getHeight() + ", width: " + decorView.getWidth());
         // END_INCLUDE (set_ui_flags)
+
+        dumpFlagStateToLog(uiOptions);
     }
 }
diff --git a/samples/browseable/AdvancedImmersiveMode/src/com.example.android.advancedimmersivemode/MainActivity.java b/samples/browseable/AdvancedImmersiveMode/src/com.example.android.advancedimmersivemode/MainActivity.java
index 0ebe878..e323557 100644
--- a/samples/browseable/AdvancedImmersiveMode/src/com.example.android.advancedimmersivemode/MainActivity.java
+++ b/samples/browseable/AdvancedImmersiveMode/src/com.example.android.advancedimmersivemode/MainActivity.java
@@ -22,6 +22,8 @@
 import android.os.Bundle;
 import android.support.v4.app.FragmentTransaction;
 import android.view.Menu;
+import android.view.MenuItem;
+import android.widget.ViewAnimator;
 
 import com.example.android.common.activities.SampleActivityBase;
 import com.example.android.common.logger.Log;
@@ -30,26 +32,28 @@
 import com.example.android.common.logger.MessageOnlyLogFilter;
 
 /**
- * A simple launcher activity containing a summary sample description
- * and a few action bar buttons.
+ * A simple launcher activity containing a summary sample description, sample log and a custom
+ * {@link android.support.v4.app.Fragment} which can display a view.
+ * <p>
+ * For devices with displays with a width of 720dp or greater, the sample log is always visible,
+ * on other devices it's visibility is controlled by an item on the Action Bar.
  */
 public class MainActivity extends SampleActivityBase {
 
     public static final String TAG = "MainActivity";
 
-    public static final String FRAGTAG = "AdvancedImmersiveModeFragment";
+    // Whether the Log Fragment is currently shown
+    private boolean mLogShown;
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         setContentView(R.layout.activity_main);
 
-        if (getSupportFragmentManager().findFragmentByTag(FRAGTAG) == null ) {
-            FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
-            AdvancedImmersiveModeFragment fragment = new AdvancedImmersiveModeFragment();
-            transaction.add(fragment, FRAGTAG);
-            transaction.commit();
-        }
+        FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
+        AdvancedImmersiveModeFragment fragment = new AdvancedImmersiveModeFragment();
+        transaction.replace(R.id.sample_content_fragment, fragment);
+        transaction.commit();
     }
 
     @Override
@@ -58,6 +62,32 @@
         return true;
     }
 
+    @Override
+    public boolean onPrepareOptionsMenu(Menu menu) {
+        MenuItem logToggle = menu.findItem(R.id.menu_toggle_log);
+        logToggle.setVisible(findViewById(R.id.sample_output) instanceof ViewAnimator);
+        logToggle.setTitle(mLogShown ? R.string.sample_hide_log : R.string.sample_show_log);
+
+        return super.onPrepareOptionsMenu(menu);
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        switch(item.getItemId()) {
+            case R.id.menu_toggle_log:
+                mLogShown = !mLogShown;
+                ViewAnimator output = (ViewAnimator) findViewById(R.id.sample_output);
+                if (mLogShown) {
+                    output.setDisplayedChild(1);
+                } else {
+                    output.setDisplayedChild(0);
+                }
+                supportInvalidateOptionsMenu();
+                return true;
+        }
+        return super.onOptionsItemSelected(item);
+    }
+
     /** Create a chain of targets that will receive log data */
     @Override
     public void initializeLogging() {
diff --git a/samples/browseable/AppRestrictions/res/values-sw600dp/dimens.xml b/samples/browseable/AppRestrictions/res/values-sw600dp/template-dimens.xml
similarity index 100%
rename from samples/browseable/AppRestrictions/res/values-sw600dp/dimens.xml
rename to samples/browseable/AppRestrictions/res/values-sw600dp/template-dimens.xml
diff --git a/samples/browseable/AppRestrictions/res/values-sw600dp/styles.xml b/samples/browseable/AppRestrictions/res/values-sw600dp/template-styles.xml
similarity index 100%
rename from samples/browseable/AppRestrictions/res/values-sw600dp/styles.xml
rename to samples/browseable/AppRestrictions/res/values-sw600dp/template-styles.xml
diff --git a/samples/browseable/AppRestrictions/res/values/dimens.xml b/samples/browseable/AppRestrictions/res/values/template-dimens.xml
similarity index 100%
rename from samples/browseable/AppRestrictions/res/values/dimens.xml
rename to samples/browseable/AppRestrictions/res/values/template-dimens.xml
diff --git a/samples/browseable/AppRestrictions/res/values/styles.xml b/samples/browseable/AppRestrictions/res/values/template-styles.xml
similarity index 100%
rename from samples/browseable/AppRestrictions/res/values/styles.xml
rename to samples/browseable/AppRestrictions/res/values/template-styles.xml
diff --git a/samples/browseable/BasicAccessibility/res/values-sw600dp/dimens.xml b/samples/browseable/BasicAccessibility/res/values-sw600dp/template-dimens.xml
similarity index 100%
rename from samples/browseable/BasicAccessibility/res/values-sw600dp/dimens.xml
rename to samples/browseable/BasicAccessibility/res/values-sw600dp/template-dimens.xml
diff --git a/samples/browseable/BasicAccessibility/res/values-sw600dp/styles.xml b/samples/browseable/BasicAccessibility/res/values-sw600dp/template-styles.xml
similarity index 100%
rename from samples/browseable/BasicAccessibility/res/values-sw600dp/styles.xml
rename to samples/browseable/BasicAccessibility/res/values-sw600dp/template-styles.xml
diff --git a/samples/browseable/BasicAccessibility/res/values/dimens.xml b/samples/browseable/BasicAccessibility/res/values/dimens.xml
index 39e710b..a5e4ebe 100644
--- a/samples/browseable/BasicAccessibility/res/values/dimens.xml
+++ b/samples/browseable/BasicAccessibility/res/values/dimens.xml
@@ -1,32 +1,20 @@
 <!--
-  Copyright 2013 The Android Open Source Project
+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
+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
+     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.
-  -->
-
+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>
-
-    <!-- Define standard dimensions to comply with Holo-style grids and rhythm. -->
-
-    <dimen name="margin_tiny">4dp</dimen>
-    <dimen name="margin_small">8dp</dimen>
-    <dimen name="margin_medium">16dp</dimen>
-    <dimen name="margin_large">32dp</dimen>
-    <dimen name="margin_huge">64dp</dimen>
-
-    <!-- Semantic definitions -->
-
-    <dimen name="horizontal_page_margin">@dimen/margin_medium</dimen>
-    <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
-
+    <!-- Default screen margins, per the Android Design guidelines. -->
+    <dimen name="activity_horizontal_margin">16dp</dimen>
+    <dimen name="activity_vertical_margin">16dp</dimen>
 </resources>
diff --git a/samples/browseable/Basic/res/values/dimens.xml b/samples/browseable/BasicAccessibility/res/values/template-dimens.xml
similarity index 100%
copy from samples/browseable/Basic/res/values/dimens.xml
copy to samples/browseable/BasicAccessibility/res/values/template-dimens.xml
diff --git a/samples/browseable/BasicAccessibility/res/values/styles.xml b/samples/browseable/BasicAccessibility/res/values/template-styles.xml
similarity index 100%
rename from samples/browseable/BasicAccessibility/res/values/styles.xml
rename to samples/browseable/BasicAccessibility/res/values/template-styles.xml
diff --git a/samples/browseable/BasicAndroidKeyStore/res/layout-sw600dp-land/activity_main.xml b/samples/browseable/BasicAndroidKeyStore/res/layout-sw600dp-land/activity_main.xml
new file mode 100644
index 0000000..653454b
--- /dev/null
+++ b/samples/browseable/BasicAndroidKeyStore/res/layout-sw600dp-land/activity_main.xml
@@ -0,0 +1,37 @@
+<!--
+  Copyright 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"
+        android:orientation="horizontal"
+        android:layout_width="fill_parent"
+        android:layout_height="fill_parent"
+        android:id="@+id/sample_main_layout">
+    <TextView android:id="@+id/sample_output"
+              style="@style/Widget.SampleMessage"
+              android:background="@android:color/white"
+              android:layout_weight="1"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent"
+              android:text="@string/intro_message"
+              android:layout_margin="16dp" />
+    <fragment
+            android:name="com.example.android.common.logger.LogFragment"
+            android:id="@+id/log_fragment"
+            android:layout_weight="1"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:layout_margin="16dp" />
+</LinearLayout>
diff --git a/samples/browseable/BasicAndroidKeyStore/res/layout-sw600dp/activity_main.xml b/samples/browseable/BasicAndroidKeyStore/res/layout-sw600dp/activity_main.xml
new file mode 100644
index 0000000..11cd71b
--- /dev/null
+++ b/samples/browseable/BasicAndroidKeyStore/res/layout-sw600dp/activity_main.xml
@@ -0,0 +1,36 @@
+<!--
+  Copyright 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"
+        android:orientation="vertical"
+        android:layout_width="fill_parent"
+        android:layout_height="fill_parent"
+        android:id="@+id/sample_main_layout">
+    <TextView android:id="@+id/sample_output"
+              style="@style/Widget.SampleMessage"
+              android:background="@android:color/white"
+              android:layout_width="match_parent"
+              android:layout_height="wrap_content"
+              android:text="@string/intro_message"
+              android:padding="16dp"
+              android:layout_margin="16dp"/>
+    <fragment
+            android:name="com.example.android.common.logger.LogFragment"
+            android:id="@+id/log_fragment"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:layout_margin="16dp" />
+</LinearLayout>
diff --git a/samples/browseable/BasicAndroidKeyStore/res/layout/activity_main.xml b/samples/browseable/BasicAndroidKeyStore/res/layout/activity_main.xml
index bc5a575..6f41369 100644
--- a/samples/browseable/BasicAndroidKeyStore/res/layout/activity_main.xml
+++ b/samples/browseable/BasicAndroidKeyStore/res/layout/activity_main.xml
@@ -24,7 +24,8 @@
               android:layout_weight="1"
               android:layout_width="match_parent"
               android:layout_height="match_parent"
-              android:text="@string/intro_message" />
+              android:text="@string/intro_message"
+              android:padding="16dp" />
     <View
             android:layout_width="fill_parent"
             android:layout_height="1dp"
diff --git a/samples/browseable/BasicAndroidKeyStore/res/values-sw600dp/dimens.xml b/samples/browseable/BasicAndroidKeyStore/res/values-sw600dp/template-dimens.xml
similarity index 100%
rename from samples/browseable/BasicAndroidKeyStore/res/values-sw600dp/dimens.xml
rename to samples/browseable/BasicAndroidKeyStore/res/values-sw600dp/template-dimens.xml
diff --git a/samples/browseable/BasicAndroidKeyStore/res/values-sw600dp/styles.xml b/samples/browseable/BasicAndroidKeyStore/res/values-sw600dp/template-styles.xml
similarity index 100%
rename from samples/browseable/BasicAndroidKeyStore/res/values-sw600dp/styles.xml
rename to samples/browseable/BasicAndroidKeyStore/res/values-sw600dp/template-styles.xml
diff --git a/samples/browseable/BasicAndroidKeyStore/res/values/styles.xml b/samples/browseable/BasicAndroidKeyStore/res/values/styles.xml
deleted file mode 100644
index d3f82ff..0000000
--- a/samples/browseable/BasicAndroidKeyStore/res/values/styles.xml
+++ /dev/null
@@ -1,51 +0,0 @@
-<!--
-  Copyright 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>
-
-    <!-- Activity themes -->
-
-    <style name="Theme.Base" parent="android:Theme.Holo.Light" />
-
-    <style name="AppTheme" parent="Theme.Base" />
-    <!-- Widget styling -->
-
-    <style name="Widget" />
-
-    <style name="Widget.SampleMessage">
-        <item name="android:textAppearance">?android:textAppearanceMedium</item>
-        <item name="android:lineSpacingMultiplier">1.1</item>
-    </style>
-
-    <style name="Widget.SampleMessageTile">
-        <item name="android:background">@drawable/tile</item>
-        <item name="android:shadowColor">#7F000000</item>
-        <item name="android:shadowDy">-3.5</item>
-        <item name="android:shadowRadius">2</item>
-    </style>
-
-
-    <style name="Widget.SampleOutput">
-        <item name="android:padding">@dimen/margin_medium</item>
-        <item name="android:textAppearance">?android:textAppearanceMedium</item>
-        <item name="android:lineSpacingMultiplier">1.1</item>
-    </style>
-
-    <style name="Log" parent="Widget.SampleOutput">
-        <item name="android:typeface">monospace</item>
-    </style>
-
-</resources>
diff --git a/samples/browseable/BasicAndroidKeyStore/res/values/dimens.xml b/samples/browseable/BasicAndroidKeyStore/res/values/template-dimens.xml
similarity index 100%
rename from samples/browseable/BasicAndroidKeyStore/res/values/dimens.xml
rename to samples/browseable/BasicAndroidKeyStore/res/values/template-dimens.xml
diff --git a/samples/browseable/AdvancedImmersiveMode/res/values/styles.xml b/samples/browseable/BasicAndroidKeyStore/res/values/template-styles.xml
similarity index 90%
rename from samples/browseable/AdvancedImmersiveMode/res/values/styles.xml
rename to samples/browseable/BasicAndroidKeyStore/res/values/template-styles.xml
index d3f82ff..cfffcbd 100644
--- a/samples/browseable/AdvancedImmersiveMode/res/values/styles.xml
+++ b/samples/browseable/BasicAndroidKeyStore/res/values/template-styles.xml
@@ -26,8 +26,11 @@
     <style name="Widget" />
 
     <style name="Widget.SampleMessage">
+        <item name="android:padding">@dimen/margin_medium</item>
         <item name="android:textAppearance">?android:textAppearanceMedium</item>
         <item name="android:lineSpacingMultiplier">1.1</item>
+        <item name="android:layout_margin">16dp</item>
+        <item name="android:shadowDy">-6.5</item>
     </style>
 
     <style name="Widget.SampleMessageTile">
diff --git a/samples/browseable/BasicAndroidKeyStore/src/com.example.android.basicandroidkeystore/MainActivity.java b/samples/browseable/BasicAndroidKeyStore/src/com.example.android.basicandroidkeystore/MainActivity.java
index 9f16565..7711f35 100644
--- a/samples/browseable/BasicAndroidKeyStore/src/com.example.android.basicandroidkeystore/MainActivity.java
+++ b/samples/browseable/BasicAndroidKeyStore/src/com.example.android.basicandroidkeystore/MainActivity.java
@@ -19,6 +19,7 @@
 
 package com.example.android.basicandroidkeystore;
 
+import android.graphics.Color;
 import android.os.Bundle;
 import android.support.v4.app.FragmentTransaction;
 import android.view.Menu;
@@ -72,6 +73,8 @@
         LogFragment logFragment = (LogFragment) getSupportFragmentManager()
                 .findFragmentById(R.id.log_fragment);
         msgFilter.setNext(logFragment.getLogView());
+        logFragment.getLogView().setTextAppearance(this, R.style.Log);
+        logFragment.getLogView().setBackgroundColor(Color.WHITE);
 
         Log.i(TAG, "Ready");
     }
diff --git a/samples/browseable/BasicContactables/res/values-sw600dp/dimens.xml b/samples/browseable/BasicContactables/res/values-sw600dp/template-dimens.xml
similarity index 100%
rename from samples/browseable/BasicContactables/res/values-sw600dp/dimens.xml
rename to samples/browseable/BasicContactables/res/values-sw600dp/template-dimens.xml
diff --git a/samples/browseable/BasicContactables/res/values-sw600dp/styles.xml b/samples/browseable/BasicContactables/res/values-sw600dp/template-styles.xml
similarity index 100%
rename from samples/browseable/BasicContactables/res/values-sw600dp/styles.xml
rename to samples/browseable/BasicContactables/res/values-sw600dp/template-styles.xml
diff --git a/samples/browseable/BasicContactables/res/values/styles.xml b/samples/browseable/BasicContactables/res/values/styles.xml
index 404623e..c3a400d 100644
--- a/samples/browseable/BasicContactables/res/values/styles.xml
+++ b/samples/browseable/BasicContactables/res/values/styles.xml
@@ -1,3 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
 <!--
   Copyright 2013 The Android Open Source Project
 
@@ -15,28 +16,12 @@
   -->
 
 <resources>
-
-    <!-- Activity themes -->
-
-    <style name="Theme.Base" parent="android:Theme.Holo.Light" />
-
-    <style name="Theme.Sample" parent="Theme.Base" />
-
-    <style name="AppTheme" parent="Theme.Sample" />
     <!-- Widget styling -->
 
-    <style name="Widget" />
-
-    <style name="Widget.SampleMessage">
+    <style name="Widget.SampleOutput">
+        <item name="android:padding">@dimen/margin_medium</item>
         <item name="android:textAppearance">?android:textAppearanceMedium</item>
         <item name="android:lineSpacingMultiplier">1.1</item>
     </style>
 
-    <style name="Widget.SampleMessageTile">
-        <item name="android:background">@drawable/tile</item>
-        <item name="android:shadowColor">#7F000000</item>
-        <item name="android:shadowDy">-3.5</item>
-        <item name="android:shadowRadius">2</item>
-    </style>
-
 </resources>
diff --git a/samples/browseable/BasicContactables/res/values/dimens.xml b/samples/browseable/BasicContactables/res/values/template-dimens.xml
similarity index 100%
rename from samples/browseable/BasicContactables/res/values/dimens.xml
rename to samples/browseable/BasicContactables/res/values/template-dimens.xml
diff --git a/samples/browseable/Basic/res/values/styles.xml b/samples/browseable/BasicContactables/res/values/template-styles.xml
similarity index 100%
copy from samples/browseable/Basic/res/values/styles.xml
copy to samples/browseable/BasicContactables/res/values/template-styles.xml
diff --git a/samples/browseable/BasicGestureDetect/res/values-sw600dp/dimens.xml b/samples/browseable/BasicGestureDetect/res/values-sw600dp/template-dimens.xml
similarity index 100%
rename from samples/browseable/BasicGestureDetect/res/values-sw600dp/dimens.xml
rename to samples/browseable/BasicGestureDetect/res/values-sw600dp/template-dimens.xml
diff --git a/samples/browseable/BasicGestureDetect/res/values-sw600dp/styles.xml b/samples/browseable/BasicGestureDetect/res/values-sw600dp/template-styles.xml
similarity index 100%
rename from samples/browseable/BasicGestureDetect/res/values-sw600dp/styles.xml
rename to samples/browseable/BasicGestureDetect/res/values-sw600dp/template-styles.xml
diff --git a/samples/browseable/BasicGestureDetect/res/values/dimens.xml b/samples/browseable/BasicGestureDetect/res/values/template-dimens.xml
similarity index 100%
rename from samples/browseable/BasicGestureDetect/res/values/dimens.xml
rename to samples/browseable/BasicGestureDetect/res/values/template-dimens.xml
diff --git a/samples/browseable/BasicGestureDetect/res/values/styles.xml b/samples/browseable/BasicGestureDetect/res/values/template-styles.xml
similarity index 100%
rename from samples/browseable/BasicGestureDetect/res/values/styles.xml
rename to samples/browseable/BasicGestureDetect/res/values/template-styles.xml
diff --git a/samples/browseable/BasicGestureDetect/src/com.example.android.basicgesturedetect/GestureListener.java b/samples/browseable/BasicGestureDetect/src/com.example.android.basicgesturedetect/GestureListener.java
index c2d2b6f..2e2921d 100644
--- a/samples/browseable/BasicGestureDetect/src/com.example.android.basicgesturedetect/GestureListener.java
+++ b/samples/browseable/BasicGestureDetect/src/com.example.android.basicgesturedetect/GestureListener.java
@@ -42,7 +42,7 @@
 
     @Override
     public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,
-                            float distanceY) {
+    float distanceY) {
         // User attempted to scroll
         Log.i(TAG, "Scroll");
         return false;
@@ -50,7 +50,7 @@
 
     @Override
     public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
-                           float velocityY) {
+    float velocityY) {
         // Fling event occurred.  Notification of this one happens after an "up" event.
         Log.i(TAG, "Fling");
         return false;
diff --git a/samples/browseable/BasicImmersiveMode/res/values-sw600dp/dimens.xml b/samples/browseable/BasicImmersiveMode/res/values-sw600dp/template-dimens.xml
similarity index 100%
rename from samples/browseable/BasicImmersiveMode/res/values-sw600dp/dimens.xml
rename to samples/browseable/BasicImmersiveMode/res/values-sw600dp/template-dimens.xml
diff --git a/samples/browseable/BasicImmersiveMode/res/values-sw600dp/styles.xml b/samples/browseable/BasicImmersiveMode/res/values-sw600dp/template-styles.xml
similarity index 100%
rename from samples/browseable/BasicImmersiveMode/res/values-sw600dp/styles.xml
rename to samples/browseable/BasicImmersiveMode/res/values-sw600dp/template-styles.xml
diff --git a/samples/browseable/BasicImmersiveMode/res/values/dimens.xml b/samples/browseable/BasicImmersiveMode/res/values/template-dimens.xml
similarity index 100%
rename from samples/browseable/BasicImmersiveMode/res/values/dimens.xml
rename to samples/browseable/BasicImmersiveMode/res/values/template-dimens.xml
diff --git a/samples/browseable/BasicImmersiveMode/res/values/styles.xml b/samples/browseable/BasicImmersiveMode/res/values/template-styles.xml
similarity index 100%
rename from samples/browseable/BasicImmersiveMode/res/values/styles.xml
rename to samples/browseable/BasicImmersiveMode/res/values/template-styles.xml
diff --git a/samples/browseable/BasicMediaDecoder/res/values-sw600dp/dimens.xml b/samples/browseable/BasicMediaDecoder/res/values-sw600dp/template-dimens.xml
similarity index 100%
rename from samples/browseable/BasicMediaDecoder/res/values-sw600dp/dimens.xml
rename to samples/browseable/BasicMediaDecoder/res/values-sw600dp/template-dimens.xml
diff --git a/samples/browseable/BasicMediaDecoder/res/values-sw600dp/styles.xml b/samples/browseable/BasicMediaDecoder/res/values-sw600dp/template-styles.xml
similarity index 100%
rename from samples/browseable/BasicMediaDecoder/res/values-sw600dp/styles.xml
rename to samples/browseable/BasicMediaDecoder/res/values-sw600dp/template-styles.xml
diff --git a/samples/browseable/BasicMediaDecoder/res/values/dimens.xml b/samples/browseable/BasicMediaDecoder/res/values/template-dimens.xml
similarity index 100%
rename from samples/browseable/BasicMediaDecoder/res/values/dimens.xml
rename to samples/browseable/BasicMediaDecoder/res/values/template-dimens.xml
diff --git a/samples/browseable/BasicMediaDecoder/res/values/styles.xml b/samples/browseable/BasicMediaDecoder/res/values/template-styles.xml
similarity index 100%
rename from samples/browseable/BasicMediaDecoder/res/values/styles.xml
rename to samples/browseable/BasicMediaDecoder/res/values/template-styles.xml
diff --git a/samples/browseable/BasicMediaRouter/res/values-sw600dp/dimens.xml b/samples/browseable/BasicMediaRouter/res/values-sw600dp/template-dimens.xml
similarity index 100%
rename from samples/browseable/BasicMediaRouter/res/values-sw600dp/dimens.xml
rename to samples/browseable/BasicMediaRouter/res/values-sw600dp/template-dimens.xml
diff --git a/samples/browseable/BasicMediaRouter/res/values-sw600dp/styles.xml b/samples/browseable/BasicMediaRouter/res/values-sw600dp/template-styles.xml
similarity index 100%
rename from samples/browseable/BasicMediaRouter/res/values-sw600dp/styles.xml
rename to samples/browseable/BasicMediaRouter/res/values-sw600dp/template-styles.xml
diff --git a/samples/browseable/BasicMediaRouter/res/values/styles.xml b/samples/browseable/BasicMediaRouter/res/values/styles.xml
index 404623e..4f64054 100644
--- a/samples/browseable/BasicMediaRouter/res/values/styles.xml
+++ b/samples/browseable/BasicMediaRouter/res/values/styles.xml
@@ -1,42 +1,22 @@
-<!--
-  Copyright 2013 The Android Open Source Project
+<resources xmlns:android="http://schemas.android.com/apk/res/android">
 
-  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>
-
-    <!-- Activity themes -->
-
-    <style name="Theme.Base" parent="android:Theme.Holo.Light" />
-
-    <style name="Theme.Sample" parent="Theme.Base" />
-
-    <style name="AppTheme" parent="Theme.Sample" />
-    <!-- Widget styling -->
-
-    <style name="Widget" />
-
-    <style name="Widget.SampleMessage">
-        <item name="android:textAppearance">?android:textAppearanceMedium</item>
-        <item name="android:lineSpacingMultiplier">1.1</item>
+    <!--
+        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>
 
-    <style name="Widget.SampleMessageTile">
-        <item name="android:background">@drawable/tile</item>
-        <item name="android:shadowColor">#7F000000</item>
-        <item name="android:shadowDy">-3.5</item>
-        <item name="android:shadowRadius">2</item>
+
+    <style name="DisplayLargeText">
+        <item name="android:textSize">30sp</item>
+        <item name="android:textStyle">bold</item>
+        <item name="android:textColor">#FFFFFF</item>
     </style>
 
-</resources>
+</resources>
\ No newline at end of file
diff --git a/samples/browseable/BasicMediaRouter/res/values/dimens.xml b/samples/browseable/BasicMediaRouter/res/values/template-dimens.xml
similarity index 100%
rename from samples/browseable/BasicMediaRouter/res/values/dimens.xml
rename to samples/browseable/BasicMediaRouter/res/values/template-dimens.xml
diff --git a/samples/browseable/BasicMediaDecoder/res/values/styles.xml b/samples/browseable/BasicMediaRouter/res/values/template-styles.xml
similarity index 100%
copy from samples/browseable/BasicMediaDecoder/res/values/styles.xml
copy to samples/browseable/BasicMediaRouter/res/values/template-styles.xml
diff --git a/samples/browseable/BasicMultitouch/res/values-sw600dp/dimens.xml b/samples/browseable/BasicMultitouch/res/values-sw600dp/template-dimens.xml
similarity index 100%
rename from samples/browseable/BasicMultitouch/res/values-sw600dp/dimens.xml
rename to samples/browseable/BasicMultitouch/res/values-sw600dp/template-dimens.xml
diff --git a/samples/browseable/BasicMultitouch/res/values-sw600dp/styles.xml b/samples/browseable/BasicMultitouch/res/values-sw600dp/template-styles.xml
similarity index 100%
rename from samples/browseable/BasicMultitouch/res/values-sw600dp/styles.xml
rename to samples/browseable/BasicMultitouch/res/values-sw600dp/template-styles.xml
diff --git a/samples/browseable/BasicMultitouch/res/values/styles.xml b/samples/browseable/BasicMultitouch/res/values/styles.xml
index 404623e..e56d4f8 100644
--- a/samples/browseable/BasicMultitouch/res/values/styles.xml
+++ b/samples/browseable/BasicMultitouch/res/values/styles.xml
@@ -13,30 +13,18 @@
   See the License for the specific language governing permissions and
   limitations under the License.
   -->
-
 <resources>
 
-    <!-- Activity themes -->
-
-    <style name="Theme.Base" parent="android:Theme.Holo.Light" />
-
-    <style name="Theme.Sample" parent="Theme.Base" />
-
-    <style name="AppTheme" parent="Theme.Sample" />
-    <!-- Widget styling -->
-
-    <style name="Widget" />
-
-    <style name="Widget.SampleMessage">
-        <item name="android:textAppearance">?android:textAppearanceMedium</item>
-        <item name="android:lineSpacingMultiplier">1.1</item>
+    <!--
+        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.NoTitleBar">
+        <!--
+            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>
 
-    <style name="Widget.SampleMessageTile">
-        <item name="android:background">@drawable/tile</item>
-        <item name="android:shadowColor">#7F000000</item>
-        <item name="android:shadowDy">-3.5</item>
-        <item name="android:shadowRadius">2</item>
-    </style>
-
-</resources>
+</resources>
\ No newline at end of file
diff --git a/samples/browseable/BasicMultitouch/res/values/dimens.xml b/samples/browseable/BasicMultitouch/res/values/template-dimens.xml
similarity index 100%
rename from samples/browseable/BasicMultitouch/res/values/dimens.xml
rename to samples/browseable/BasicMultitouch/res/values/template-dimens.xml
diff --git a/samples/browseable/Basic/res/values/styles.xml b/samples/browseable/BasicMultitouch/res/values/template-styles.xml
similarity index 100%
rename from samples/browseable/Basic/res/values/styles.xml
rename to samples/browseable/BasicMultitouch/res/values/template-styles.xml
diff --git a/samples/browseable/BasicNetworking/res/values-sw600dp/dimens.xml b/samples/browseable/BasicNetworking/res/values-sw600dp/template-dimens.xml
similarity index 100%
rename from samples/browseable/BasicNetworking/res/values-sw600dp/dimens.xml
rename to samples/browseable/BasicNetworking/res/values-sw600dp/template-dimens.xml
diff --git a/samples/browseable/BasicNetworking/res/values-sw600dp/styles.xml b/samples/browseable/BasicNetworking/res/values-sw600dp/template-styles.xml
similarity index 100%
rename from samples/browseable/BasicNetworking/res/values-sw600dp/styles.xml
rename to samples/browseable/BasicNetworking/res/values-sw600dp/template-styles.xml
diff --git a/samples/browseable/BasicNetworking/res/values/styles.xml b/samples/browseable/BasicNetworking/res/values/styles.xml
index 404623e..3450a54 100644
--- a/samples/browseable/BasicNetworking/res/values/styles.xml
+++ b/samples/browseable/BasicNetworking/res/values/styles.xml
@@ -8,7 +8,7 @@
       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,
+  distributed under thegi 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.
@@ -16,27 +16,17 @@
 
 <resources>
 
-    <!-- Activity themes -->
-
-    <style name="Theme.Base" parent="android:Theme.Holo.Light" />
-
-    <style name="Theme.Sample" parent="Theme.Base" />
-
-    <style name="AppTheme" parent="Theme.Sample" />
     <!-- Widget styling -->
 
-    <style name="Widget" />
-
-    <style name="Widget.SampleMessage">
+    <style name="Widget.SampleOutput">
+        <item name="android:padding">@dimen/margin_medium</item>
         <item name="android:textAppearance">?android:textAppearanceMedium</item>
         <item name="android:lineSpacingMultiplier">1.1</item>
     </style>
 
-    <style name="Widget.SampleMessageTile">
-        <item name="android:background">@drawable/tile</item>
-        <item name="android:shadowColor">#7F000000</item>
-        <item name="android:shadowDy">-3.5</item>
-        <item name="android:shadowRadius">2</item>
+    <style name="Log" parent="Widget.SampleOutput">
+        <item name="android:typeface">monospace</item>
     </style>
 
+
 </resources>
diff --git a/samples/browseable/BasicNetworking/res/values/dimens.xml b/samples/browseable/BasicNetworking/res/values/template-dimens.xml
similarity index 100%
rename from samples/browseable/BasicNetworking/res/values/dimens.xml
rename to samples/browseable/BasicNetworking/res/values/template-dimens.xml
diff --git a/samples/browseable/Basic/res/values/styles.xml b/samples/browseable/BasicNetworking/res/values/template-styles.xml
similarity index 100%
copy from samples/browseable/Basic/res/values/styles.xml
copy to samples/browseable/BasicNetworking/res/values/template-styles.xml
diff --git a/samples/browseable/BasicNotifications/res/values-sw600dp/dimens.xml b/samples/browseable/BasicNotifications/res/values-sw600dp/template-dimens.xml
similarity index 100%
rename from samples/browseable/BasicNotifications/res/values-sw600dp/dimens.xml
rename to samples/browseable/BasicNotifications/res/values-sw600dp/template-dimens.xml
diff --git a/samples/browseable/BasicNotifications/res/values-sw600dp/styles.xml b/samples/browseable/BasicNotifications/res/values-sw600dp/template-styles.xml
similarity index 100%
rename from samples/browseable/BasicNotifications/res/values-sw600dp/styles.xml
rename to samples/browseable/BasicNotifications/res/values-sw600dp/template-styles.xml
diff --git a/samples/browseable/BasicNotifications/res/values/dimens.xml b/samples/browseable/BasicNotifications/res/values/template-dimens.xml
similarity index 100%
rename from samples/browseable/BasicNotifications/res/values/dimens.xml
rename to samples/browseable/BasicNotifications/res/values/template-dimens.xml
diff --git a/samples/browseable/BasicNotifications/res/values/styles.xml b/samples/browseable/BasicNotifications/res/values/template-styles.xml
similarity index 100%
rename from samples/browseable/BasicNotifications/res/values/styles.xml
rename to samples/browseable/BasicNotifications/res/values/template-styles.xml
diff --git a/samples/browseable/BasicRenderScript/AndroidManifest.xml b/samples/browseable/BasicRenderScript/AndroidManifest.xml
new file mode 100644
index 0000000..e1e2dfc
--- /dev/null
+++ b/samples/browseable/BasicRenderScript/AndroidManifest.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="UTF-8"?><!--
+ Copyright 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.example.android.basicrenderscript"
+    android:versionCode="1"
+    android:versionName="1.0">
+
+    <uses-sdk
+        android:minSdkVersion="8"
+        android:targetSdkVersion="19" />
+
+    <application
+        android:allowBackup="true"
+        android:label="@string/app_name"
+        android:icon="@drawable/ic_launcher"
+        android:theme="@style/AppTheme">
+
+        <activity
+            android:name=".MainActivity"
+            android:label="@string/app_name"
+            android:theme="@style/FullscreenTheme">
+            <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/browseable/BasicRenderScript/_index.jd b/samples/browseable/BasicRenderScript/_index.jd
new file mode 100644
index 0000000..a40a264
--- /dev/null
+++ b/samples/browseable/BasicRenderScript/_index.jd
@@ -0,0 +1,13 @@
+
+
+
+page.tags="BasicRenderScript"
+sample.group=RenderScript
+@jd:body
+
+<p>
+  This sample demonstrates the basic steps for using RenderScript. In this
+  example, the app uses <a href=
+  "{@docRoot}guide/topics/renderscript/compute.html">RenderScript</a> to
+  perform graphical filter operations on a image.
+</p>
diff --git a/samples/training/bitmapfun/BitmapFun/src/main/res/drawable-hdpi/ic_launcher.png b/samples/browseable/BasicRenderScript/res/drawable-hdpi/ic_launcher.png
old mode 100644
new mode 100755
similarity index 100%
rename from samples/training/bitmapfun/BitmapFun/src/main/res/drawable-hdpi/ic_launcher.png
rename to samples/browseable/BasicRenderScript/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/Basic/res/drawable-hdpi/tile.9.png b/samples/browseable/BasicRenderScript/res/drawable-hdpi/tile.9.png
similarity index 100%
copy from samples/browseable/Basic/res/drawable-hdpi/tile.9.png
copy to samples/browseable/BasicRenderScript/res/drawable-hdpi/tile.9.png
Binary files differ
diff --git a/samples/browseable/BasicRenderScript/res/drawable-mdpi/ic_launcher.png b/samples/browseable/BasicRenderScript/res/drawable-mdpi/ic_launcher.png
new file mode 100755
index 0000000..4ccd98e
--- /dev/null
+++ b/samples/browseable/BasicRenderScript/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/BasicRenderScript/res/drawable-nodpi/data.jpg b/samples/browseable/BasicRenderScript/res/drawable-nodpi/data.jpg
new file mode 100644
index 0000000..81a87b1
--- /dev/null
+++ b/samples/browseable/BasicRenderScript/res/drawable-nodpi/data.jpg
Binary files differ
diff --git a/samples/training/bitmapfun/BitmapFun/src/main/res/drawable-xhdpi/ic_launcher.png b/samples/browseable/BasicRenderScript/res/drawable-xhdpi/ic_launcher.png
old mode 100644
new mode 100755
similarity index 100%
rename from samples/training/bitmapfun/BitmapFun/src/main/res/drawable-xhdpi/ic_launcher.png
rename to samples/browseable/BasicRenderScript/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/BasicRenderScript/res/drawable-xxhdpi/ic_launcher.png b/samples/browseable/BasicRenderScript/res/drawable-xxhdpi/ic_launcher.png
new file mode 100755
index 0000000..3c45f51
--- /dev/null
+++ b/samples/browseable/BasicRenderScript/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/Basic/res/layout/activity_main.xml b/samples/browseable/BasicRenderScript/res/layout/activity_main.xml
similarity index 100%
rename from samples/browseable/Basic/res/layout/activity_main.xml
rename to samples/browseable/BasicRenderScript/res/layout/activity_main.xml
diff --git a/samples/browseable/BasicRenderScript/res/layout/main_layout.xml b/samples/browseable/BasicRenderScript/res/layout/main_layout.xml
new file mode 100644
index 0000000..69695f0
--- /dev/null
+++ b/samples/browseable/BasicRenderScript/res/layout/main_layout.xml
@@ -0,0 +1,22 @@
+<FrameLayout 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:background="#0099cc"
+    tools:context=".MainActivity">
+
+    <ImageView
+        android:id="@+id/imageView"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:scaleType="fitCenter"
+        android:src="@drawable/data" />
+
+    <SeekBar
+        android:id="@+id/seekBar1"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_gravity="bottom"
+        android:layout_marginBottom="16dp" />
+
+</FrameLayout>
diff --git a/samples/browseable/Basic/res/values-sw600dp/dimens.xml b/samples/browseable/BasicRenderScript/res/values-sw600dp/template-dimens.xml
similarity index 100%
copy from samples/browseable/Basic/res/values-sw600dp/dimens.xml
copy to samples/browseable/BasicRenderScript/res/values-sw600dp/template-dimens.xml
diff --git a/samples/browseable/Basic/res/values-sw600dp/styles.xml b/samples/browseable/BasicRenderScript/res/values-sw600dp/template-styles.xml
similarity index 100%
copy from samples/browseable/Basic/res/values-sw600dp/styles.xml
copy to samples/browseable/BasicRenderScript/res/values-sw600dp/template-styles.xml
diff --git a/samples/browseable/BasicRenderScript/res/values-v11/styles.xml b/samples/browseable/BasicRenderScript/res/values-v11/styles.xml
new file mode 100644
index 0000000..f3a90c6
--- /dev/null
+++ b/samples/browseable/BasicRenderScript/res/values-v11/styles.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<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>
+
+    <style name="FullscreenTheme" parent="android:Theme.Holo">
+        <item name="android:actionBarStyle">@style/FullscreenActionBarStyle</item>
+        <item name="android:windowActionBarOverlay">true</item>
+        <item name="android:windowBackground">@null</item>
+        <item name="buttonBarStyle">?android:attr/buttonBarStyle</item>
+        <item name="buttonBarButtonStyle">?android:attr/buttonBarButtonStyle</item>
+    </style>
+
+    <style name="FullscreenActionBarStyle" parent="android:Widget.Holo.ActionBar">
+        <item name="android:background">@color/black_overlay</item>
+    </style>
+
+</resources>
diff --git a/samples/browseable/BasicRenderScript/res/values-v14/styles.xml b/samples/browseable/BasicRenderScript/res/values-v14/styles.xml
new file mode 100644
index 0000000..a91fd03
--- /dev/null
+++ b/samples/browseable/BasicRenderScript/res/values-v14/styles.xml
@@ -0,0 +1,12 @@
+<resources>
+
+    <!--
+        Base application theme for API 14+. This theme completely replaces
+        AppBaseTheme from BOTH res/values/styles.xml and
+        res/values-v11/styles.xml on API 14+ devices.
+    -->
+    <style name="AppBaseTheme" parent="android:Theme.Holo.Light.DarkActionBar">
+        <!-- API 14 theme customizations can go here. -->
+    </style>
+
+</resources>
diff --git a/samples/browseable/BasicRenderScript/res/values/attrs.xml b/samples/browseable/BasicRenderScript/res/values/attrs.xml
new file mode 100644
index 0000000..e67df0a
--- /dev/null
+++ b/samples/browseable/BasicRenderScript/res/values/attrs.xml
@@ -0,0 +1,14 @@
+<resources>
+
+    <!--
+         Declare custom theme attributes that allow changing which styles are
+         used for button bars depending on the API level.
+         ?android:attr/buttonBarStyle is new as of API 11 so this is
+         necessary to support previous API levels.
+    -->
+    <declare-styleable name="ButtonBarContainerTheme">
+        <attr name="buttonBarStyle" format="reference" />
+        <attr name="buttonBarButtonStyle" format="reference" />
+    </declare-styleable>
+
+</resources>
diff --git a/samples/browseable/repeatingAlarm/res/values/base-strings.xml b/samples/browseable/BasicRenderScript/res/values/base-strings.xml
similarity index 77%
copy from samples/browseable/repeatingAlarm/res/values/base-strings.xml
copy to samples/browseable/BasicRenderScript/res/values/base-strings.xml
index c11b89b..a35b320 100644
--- a/samples/browseable/repeatingAlarm/res/values/base-strings.xml
+++ b/samples/browseable/BasicRenderScript/res/values/base-strings.xml
@@ -18,13 +18,13 @@
 
 
 <resources>
-    <string name="app_name">repeatingAlarm</string>
+    <string name="app_name">BasicRenderScript</string>
     <string name="intro_message">
         <![CDATA[
         
             
-                Introductory text that explains what the sample is intended to demonstrate. Edit
-                in template-params.xml.
+            BasicRenderScript sample demonstrates basic steps how to use renderScript.
+			In the sample, it performs graphical filter operation on a image with renderScript.
             
         
         ]]>
diff --git a/samples/browseable/BasicRenderScript/res/values/colors.xml b/samples/browseable/BasicRenderScript/res/values/colors.xml
new file mode 100644
index 0000000..327c060
--- /dev/null
+++ b/samples/browseable/BasicRenderScript/res/values/colors.xml
@@ -0,0 +1,5 @@
+<resources>
+
+    <color name="black_overlay">#66000000</color>
+
+</resources>
diff --git a/samples/browseable/BasicRenderScript/res/values/styles.xml b/samples/browseable/BasicRenderScript/res/values/styles.xml
new file mode 100644
index 0000000..49299b9
--- /dev/null
+++ b/samples/browseable/BasicRenderScript/res/values/styles.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+
+    <style name="FullscreenTheme" parent="android:Theme.NoTitleBar">
+        <item name="android:windowContentOverlay">@null</item>
+        <item name="android:windowBackground">@null</item>
+        <item name="buttonBarStyle">@style/ButtonBar</item>
+        <item name="buttonBarButtonStyle">@style/ButtonBarButton</item>
+    </style>
+
+    <style name="ButtonBar">
+        <item name="android:paddingLeft">2dp</item>
+        <item name="android:paddingTop">5dp</item>
+        <item name="android:paddingRight">2dp</item>
+        <item name="android:paddingBottom">0dp</item>
+        <item name="android:background">@android:drawable/bottom_bar</item>
+    </style>
+
+    <style name="ButtonBarButton" />
+
+</resources>
diff --git a/samples/browseable/Basic/res/values/dimens.xml b/samples/browseable/BasicRenderScript/res/values/template-dimens.xml
similarity index 100%
copy from samples/browseable/Basic/res/values/dimens.xml
copy to samples/browseable/BasicRenderScript/res/values/template-dimens.xml
diff --git a/samples/browseable/Basic/res/values/styles.xml b/samples/browseable/BasicRenderScript/res/values/template-styles.xml
similarity index 100%
copy from samples/browseable/Basic/res/values/styles.xml
copy to samples/browseable/BasicRenderScript/res/values/template-styles.xml
diff --git a/samples/browseable/BasicRenderScript/src/com.example.android.basicrenderscript/MainActivity.java b/samples/browseable/BasicRenderScript/src/com.example.android.basicrenderscript/MainActivity.java
new file mode 100644
index 0000000..ed6d5ad
--- /dev/null
+++ b/samples/browseable/BasicRenderScript/src/com.example.android.basicrenderscript/MainActivity.java
@@ -0,0 +1,190 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.basicrenderscript;
+
+import android.app.Activity;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.widget.ImageView;
+import android.widget.SeekBar;
+import android.widget.SeekBar.OnSeekBarChangeListener;
+import android.support.v8.renderscript.*;
+
+public class MainActivity extends Activity {
+    /* Number of bitmaps that is used for renderScript thread and UI thread synchronization.
+       Ideally, this can be reduced to 2, however in some devices, 2 buffers still showing tierings on UI.
+       Investigating a root cause.
+     */
+    private final int NUM_BITMAPS = 3;
+    private int mCurrentBitmap = 0;
+    private Bitmap mBitmapIn;
+    private Bitmap[] mBitmapsOut;
+    private ImageView mImageView;
+
+    private RenderScript mRS;
+    private Allocation mInAllocation;
+    private Allocation[] mOutAllocations;
+    private ScriptC_saturation mScript;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        setContentView(R.layout.main_layout);
+
+        /*
+         * Initialize UI
+         */
+        mBitmapIn = loadBitmap(R.drawable.data);
+        mBitmapsOut = new Bitmap[NUM_BITMAPS];
+        for (int i = 0; i < NUM_BITMAPS; ++i) {
+            mBitmapsOut[i] = Bitmap.createBitmap(mBitmapIn.getWidth(),
+                    mBitmapIn.getHeight(), mBitmapIn.getConfig());
+        }
+
+        mImageView = (ImageView) findViewById(R.id.imageView);
+        mImageView.setImageBitmap(mBitmapsOut[mCurrentBitmap]);
+        mCurrentBitmap += (mCurrentBitmap + 1) % NUM_BITMAPS;
+
+        SeekBar seekbar = (SeekBar) findViewById(R.id.seekBar1);
+        seekbar.setProgress(50);
+        seekbar.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
+            public void onProgressChanged(SeekBar seekBar, int progress,
+                                          boolean fromUser) {
+                float max = 2.0f;
+                float min = 0.0f;
+                float f = (float) ((max - min) * (progress / 100.0) + min);
+                updateImage(f);
+            }
+
+            @Override
+            public void onStartTrackingTouch(SeekBar seekBar) {
+            }
+
+            @Override
+            public void onStopTrackingTouch(SeekBar seekBar) {
+            }
+        });
+
+        /*
+         * Create renderScript
+         */
+        createScript();
+
+        /*
+         * Invoke renderScript kernel and update imageView
+         */
+        updateImage(1.0f);
+    }
+
+    /*
+     * Initialize RenderScript
+     * In the sample, it creates RenderScript kernel that performs saturation manipulation.
+     */
+    private void createScript() {
+        //Initialize RS
+        mRS = RenderScript.create(this);
+
+        //Allocate buffers
+        mInAllocation = Allocation.createFromBitmap(mRS, mBitmapIn);
+        mOutAllocations = new Allocation[NUM_BITMAPS];
+        for (int i = 0; i < NUM_BITMAPS; ++i) {
+            mOutAllocations[i] = Allocation.createFromBitmap(mRS, mBitmapsOut[i]);
+        }
+
+        //Load script
+        mScript = new ScriptC_saturation(mRS);
+    }
+
+    /*
+     * In the AsyncTask, it invokes RenderScript intrinsics to do a filtering.
+     * After the filtering is done, an operation blocks at Allication.copyTo() in AsyncTask thread.
+     * Once all operation is finished at onPostExecute() in UI thread, it can invalidate and update ImageView UI.
+     */
+    private class RenderScriptTask extends AsyncTask<Float, Integer, Integer> {
+        Boolean issued = false;
+
+        protected Integer doInBackground(Float... values) {
+            int index = -1;
+            if (isCancelled() == false) {
+                issued = true;
+                index = mCurrentBitmap;
+
+                /*
+                 * Set global variable in RS
+                 */
+                mScript.set_saturationValue(values[0]);
+
+                /*
+                 * Invoke saturation filter kernel
+                 */
+                mScript.forEach_saturation(mInAllocation, mOutAllocations[index]);
+
+                /*
+                 * Copy to bitmap and invalidate image view
+                 */
+                mOutAllocations[index].copyTo(mBitmapsOut[index]);
+                mCurrentBitmap = (mCurrentBitmap + 1) % NUM_BITMAPS;
+            }
+            return index;
+        }
+
+        void updateView(Integer result) {
+            if (result != -1) {
+                // Request UI update
+                mImageView.setImageBitmap(mBitmapsOut[result]);
+                mImageView.invalidate();
+            }
+        }
+
+        protected void onPostExecute(Integer result) {
+            updateView(result);
+        }
+
+        protected void onCancelled(Integer result) {
+            if (issued) {
+                updateView(result);
+            }
+        }
+    }
+
+    RenderScriptTask currentTask = null;
+
+    /*
+    Invoke AsynchTask and cancel previous task.
+    When AsyncTasks are piled up (typically in slow device with heavy kernel),
+    Only the latest (and already started) task invokes RenderScript operation.
+     */
+    private void updateImage(final float f) {
+        if (currentTask != null)
+            currentTask.cancel(false);
+        currentTask = new RenderScriptTask();
+        currentTask.execute(f);
+    }
+
+    /*
+    Helper to load Bitmap from resource
+     */
+    private Bitmap loadBitmap(int resource) {
+        final BitmapFactory.Options options = new BitmapFactory.Options();
+        options.inPreferredConfig = Bitmap.Config.ARGB_8888;
+        return BitmapFactory.decodeResource(getResources(), resource, options);
+    }
+
+}
diff --git a/samples/browseable/BasicRenderScript/src/com.example.android.common.media/CameraHelper.java b/samples/browseable/BasicRenderScript/src/com.example.android.common.media/CameraHelper.java
new file mode 100644
index 0000000..1fa8416
--- /dev/null
+++ b/samples/browseable/BasicRenderScript/src/com.example.android.common.media/CameraHelper.java
@@ -0,0 +1,182 @@
+/*
+ * 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.common.media;
+
+import android.annotation.TargetApi;
+import android.hardware.Camera;
+import android.os.Build;
+import android.os.Environment;
+import android.util.Log;
+
+import java.io.File;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * Camera related utilities.
+ */
+public class CameraHelper {
+
+    public static final int MEDIA_TYPE_IMAGE = 1;
+    public static final int MEDIA_TYPE_VIDEO = 2;
+
+    /**
+     * Iterate over supported camera preview sizes to see which one best fits the
+     * dimensions of the given view while maintaining the aspect ratio. If none can,
+     * be lenient with the aspect ratio.
+     *
+     * @param sizes Supported camera preview sizes.
+     * @param w The width of the view.
+     * @param h The height of the view.
+     * @return Best match camera preview size to fit in the view.
+     */
+    public static  Camera.Size getOptimalPreviewSize(List<Camera.Size> sizes, int w, int h) {
+        // Use a very small tolerance because we want an exact match.
+        final double ASPECT_TOLERANCE = 0.1;
+        double targetRatio = (double) w / h;
+        if (sizes == null)
+            return null;
+
+        Camera.Size optimalSize = null;
+
+        // Start with max value and refine as we iterate over available preview sizes. This is the
+        // minimum difference between view and camera height.
+        double minDiff = Double.MAX_VALUE;
+
+        // Target view height
+        int targetHeight = h;
+
+        // Try to find a preview size that matches aspect ratio and the target view size.
+        // Iterate over all available sizes and pick the largest size that can fit in the view and
+        // still maintain the aspect ratio.
+        for (Camera.Size size : sizes) {
+            double ratio = (double) size.width / size.height;
+            if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE)
+                continue;
+            if (Math.abs(size.height - targetHeight) < minDiff) {
+                optimalSize = size;
+                minDiff = Math.abs(size.height - targetHeight);
+            }
+        }
+
+        // Cannot find preview size that matches the aspect ratio, ignore the requirement
+        if (optimalSize == null) {
+            minDiff = Double.MAX_VALUE;
+            for (Camera.Size size : sizes) {
+                if (Math.abs(size.height - targetHeight) < minDiff) {
+                    optimalSize = size;
+                    minDiff = Math.abs(size.height - targetHeight);
+                }
+            }
+        }
+        return optimalSize;
+    }
+
+    /**
+     * @return the default camera on the device. Return null if there is no camera on the device.
+     */
+    public static Camera getDefaultCameraInstance() {
+        return Camera.open();
+    }
+
+
+    /**
+     * @return the default rear/back facing camera on the device. Returns null if camera is not
+     * available.
+     */
+    public static Camera getDefaultBackFacingCameraInstance() {
+        return getDefaultCamera(Camera.CameraInfo.CAMERA_FACING_BACK);
+    }
+
+    /**
+     * @return the default front facing camera on the device. Returns null if camera is not
+     * available.
+     */
+    public static Camera getDefaultFrontFacingCameraInstance() {
+        return getDefaultCamera(Camera.CameraInfo.CAMERA_FACING_FRONT);
+    }
+
+
+    /**
+     *
+     * @param position Physical position of the camera i.e Camera.CameraInfo.CAMERA_FACING_FRONT
+     *                 or Camera.CameraInfo.CAMERA_FACING_BACK.
+     * @return the default camera on the device. Returns null if camera is not available.
+     */
+    @TargetApi(Build.VERSION_CODES.GINGERBREAD)
+    private static Camera getDefaultCamera(int position) {
+        // Find the total number of cameras available
+        int  mNumberOfCameras = Camera.getNumberOfCameras();
+
+        // Find the ID of the back-facing ("default") camera
+        Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
+        for (int i = 0; i < mNumberOfCameras; i++) {
+            Camera.getCameraInfo(i, cameraInfo);
+            if (cameraInfo.facing == position) {
+                return Camera.open(i);
+
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * Creates a media file in the {@code Environment.DIRECTORY_PICTURES} directory. The directory
+     * is persistent and available to other applications like gallery.
+     *
+     * @param type Media type. Can be video or image.
+     * @return A file object pointing to the newly created file.
+     */
+    public  static File getOutputMediaFile(int type){
+        // To be safe, you should check that the SDCard is mounted
+        // using Environment.getExternalStorageState() before doing this.
+        if (!Environment.getExternalStorageState().equalsIgnoreCase(Environment.MEDIA_MOUNTED)) {
+            return  null;
+        }
+
+        File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(
+                Environment.DIRECTORY_PICTURES), "CameraSample");
+        // This location works best if you want the created images to be shared
+        // between applications and persist after your app has been uninstalled.
+
+        // Create the storage directory if it does not exist
+        if (! mediaStorageDir.exists()){
+            if (! mediaStorageDir.mkdirs()) {
+                Log.d("CameraSample", "failed to create directory");
+                return null;
+            }
+        }
+
+        // Create a media file name
+        String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
+        File mediaFile;
+        if (type == MEDIA_TYPE_IMAGE){
+            mediaFile = new File(mediaStorageDir.getPath() + File.separator +
+                    "IMG_"+ timeStamp + ".jpg");
+        } else if(type == MEDIA_TYPE_VIDEO) {
+            mediaFile = new File(mediaStorageDir.getPath() + File.separator +
+                    "VID_"+ timeStamp + ".mp4");
+        } else {
+            return null;
+        }
+
+        return mediaFile;
+    }
+
+}
diff --git a/samples/browseable/BasicRenderScript/src/com.example.android.common.media/MediaCodecWrapper.java b/samples/browseable/BasicRenderScript/src/com.example.android.common.media/MediaCodecWrapper.java
new file mode 100644
index 0000000..a511221
--- /dev/null
+++ b/samples/browseable/BasicRenderScript/src/com.example.android.common.media/MediaCodecWrapper.java
@@ -0,0 +1,386 @@
+/*
+ * 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.common.media;
+
+import android.media.*;
+import android.os.Handler;
+import android.os.Looper;
+import android.view.Surface;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayDeque;
+import java.util.Queue;
+
+/**
+ * Simplifies the MediaCodec interface by wrapping around the buffer processing operations.
+ */
+public class MediaCodecWrapper {
+
+    // Handler to use for {@code OutputSampleListener} and {code OutputFormatChangedListener}
+    // callbacks
+    private Handler mHandler;
+
+
+    // Callback when media output format changes.
+    public interface OutputFormatChangedListener {
+        void outputFormatChanged(MediaCodecWrapper sender, MediaFormat newFormat);
+    }
+
+    private OutputFormatChangedListener mOutputFormatChangedListener = null;
+
+    /**
+     * Callback for decodes frames. Observers can register a listener for optional stream
+     * of decoded data
+     */
+    public interface OutputSampleListener {
+        void outputSample(MediaCodecWrapper sender, MediaCodec.BufferInfo info, ByteBuffer buffer);
+    }
+
+    /**
+     * The {@link MediaCodec} that is managed by this class.
+     */
+    private MediaCodec mDecoder;
+
+    // References to the internal buffers managed by the codec. The codec
+    // refers to these buffers by index, never by reference so it's up to us
+    // to keep track of which buffer is which.
+    private ByteBuffer[] mInputBuffers;
+    private ByteBuffer[] mOutputBuffers;
+
+    // Indices of the input buffers that are currently available for writing. We'll
+    // consume these in the order they were dequeued from the codec.
+    private Queue<Integer> mAvailableInputBuffers;
+
+    // Indices of the output buffers that currently hold valid data, in the order
+    // they were produced by the codec.
+    private Queue<Integer> mAvailableOutputBuffers;
+
+    // Information about each output buffer, by index. Each entry in this array
+    // is valid if and only if its index is currently contained in mAvailableOutputBuffers.
+    private MediaCodec.BufferInfo[] mOutputBufferInfo;
+
+    // An (optional) stream that will receive decoded data.
+    private OutputSampleListener mOutputSampleListener;
+
+    private MediaCodecWrapper(MediaCodec codec) {
+        mDecoder = codec;
+        codec.start();
+        mInputBuffers = codec.getInputBuffers();
+        mOutputBuffers = codec.getOutputBuffers();
+        mOutputBufferInfo = new MediaCodec.BufferInfo[mOutputBuffers.length];
+        mAvailableInputBuffers = new ArrayDeque<Integer>(mOutputBuffers.length);
+        mAvailableOutputBuffers = new ArrayDeque<Integer>(mInputBuffers.length);
+    }
+
+    /**
+     * Releases resources and ends the encoding/decoding session.
+     */
+    public void stopAndRelease() {
+        mDecoder.stop();
+        mDecoder.release();
+        mDecoder = null;
+        mHandler = null;
+    }
+
+    /**
+     * Getter for the registered {@link OutputFormatChangedListener}
+     */
+    public OutputFormatChangedListener getOutputFormatChangedListener() {
+        return mOutputFormatChangedListener;
+    }
+
+    /**
+     *
+     * @param outputFormatChangedListener the listener for callback.
+     * @param handler message handler for posting the callback.
+     */
+    public void setOutputFormatChangedListener(final OutputFormatChangedListener
+            outputFormatChangedListener, Handler handler) {
+        mOutputFormatChangedListener = outputFormatChangedListener;
+
+        // Making sure we don't block ourselves due to a bad implementation of the callback by
+        // using a handler provided by client.
+        Looper looper;
+        mHandler = handler;
+        if (outputFormatChangedListener != null && mHandler == null) {
+            if ((looper = Looper.myLooper()) != null) {
+                mHandler = new Handler();
+            } else {
+                throw new IllegalArgumentException(
+                        "Looper doesn't exist in the calling thread");
+            }
+        }
+    }
+
+    /**
+     * Constructs the {@link MediaCodecWrapper} wrapper object around the video codec.
+     * The codec is created using the encapsulated information in the
+     * {@link MediaFormat} object.
+     *
+     * @param trackFormat The format of the media object to be decoded.
+     * @param surface Surface to render the decoded frames.
+     * @return
+     */
+    public static MediaCodecWrapper fromVideoFormat(final MediaFormat trackFormat,
+            Surface surface) {
+        MediaCodecWrapper result = null;
+        MediaCodec videoCodec = null;
+
+        // BEGIN_INCLUDE(create_codec)
+        final String mimeType = trackFormat.getString(MediaFormat.KEY_MIME);
+
+        // Check to see if this is actually a video mime type. If it is, then create
+        // a codec that can decode this mime type.
+        if (mimeType.contains("video/")) {
+            videoCodec = MediaCodec.createDecoderByType(mimeType);
+            videoCodec.configure(trackFormat, surface, null,  0);
+
+        }
+
+        // If codec creation was successful, then create a wrapper object around the
+        // newly created codec.
+        if (videoCodec != null) {
+            result = new MediaCodecWrapper(videoCodec);
+        }
+        // END_INCLUDE(create_codec)
+
+        return result;
+    }
+
+
+    /**
+     * Write a media sample to the decoder.
+     *
+     * A "sample" here refers to a single atomic access unit in the media stream. The definition
+     * of "access unit" is dependent on the type of encoding used, but it typically refers to
+     * a single frame of video or a few seconds of audio. {@link android.media.MediaExtractor}
+     * extracts data from a stream one sample at a time.
+     *
+     * @param input A ByteBuffer containing the input data for one sample. The buffer must be set
+     * up for reading, with its position set to the beginning of the sample data and its limit
+     * set to the end of the sample data.
+     *
+     * @param presentationTimeUs  The time, relative to the beginning of the media stream,
+     * at which this buffer should be rendered.
+     *
+     * @param flags Flags to pass to the decoder. See {@link MediaCodec#queueInputBuffer(int,
+     * int, int, long, int)}
+     *
+     * @throws MediaCodec.CryptoException
+     */
+    public boolean writeSample(final ByteBuffer input,
+            final MediaCodec.CryptoInfo crypto,
+            final long presentationTimeUs,
+            final int flags) throws MediaCodec.CryptoException, WriteException {
+        boolean result = false;
+        int size = input.remaining();
+
+        // check if we have dequed input buffers available from the codec
+        if (size > 0 &&  !mAvailableInputBuffers.isEmpty()) {
+            int index = mAvailableInputBuffers.remove();
+            ByteBuffer buffer = mInputBuffers[index];
+
+            // we can't write our sample to a lesser capacity input buffer.
+            if (size > buffer.capacity()) {
+                throw new MediaCodecWrapper.WriteException(String.format(
+                        "Insufficient capacity in MediaCodec buffer: "
+                            + "tried to write %d, buffer capacity is %d.",
+                        input.remaining(),
+                        buffer.capacity()));
+            }
+
+            buffer.clear();
+            buffer.put(input);
+
+            // Submit the buffer to the codec for decoding. The presentationTimeUs
+            // indicates the position (play time) for the current sample.
+            if (crypto == null) {
+                mDecoder.queueInputBuffer(index, 0, size, presentationTimeUs, flags);
+            } else {
+                mDecoder.queueSecureInputBuffer(index, 0, crypto, presentationTimeUs, flags);
+            }
+            result = true;
+        }
+        return result;
+    }
+
+    static MediaCodec.CryptoInfo cryptoInfo= new MediaCodec.CryptoInfo();
+
+    /**
+     * Write a media sample to the decoder.
+     *
+     * A "sample" here refers to a single atomic access unit in the media stream. The definition
+     * of "access unit" is dependent on the type of encoding used, but it typically refers to
+     * a single frame of video or a few seconds of audio. {@link android.media.MediaExtractor}
+     * extracts data from a stream one sample at a time.
+     *
+     * @param extractor  Instance of {@link android.media.MediaExtractor} wrapping the media.
+     *
+     * @param presentationTimeUs The time, relative to the beginning of the media stream,
+     * at which this buffer should be rendered.
+     *
+     * @param flags  Flags to pass to the decoder. See {@link MediaCodec#queueInputBuffer(int,
+     * int, int, long, int)}
+     *
+     * @throws MediaCodec.CryptoException
+     */
+    public boolean writeSample(final MediaExtractor extractor,
+            final boolean isSecure,
+            final long presentationTimeUs,
+            int flags) {
+        boolean result = false;
+        boolean isEos = false;
+
+        if (!mAvailableInputBuffers.isEmpty()) {
+            int index = mAvailableInputBuffers.remove();
+            ByteBuffer buffer = mInputBuffers[index];
+
+            // reads the sample from the file using extractor into the buffer
+            int size = extractor.readSampleData(buffer, 0);
+            if (size <= 0) {
+                flags |= MediaCodec.BUFFER_FLAG_END_OF_STREAM;
+            }
+
+            // Submit the buffer to the codec for decoding. The presentationTimeUs
+            // indicates the position (play time) for the current sample.
+            if (!isSecure) {
+                mDecoder.queueInputBuffer(index, 0, size, presentationTimeUs, flags);
+            } else {
+                extractor.getSampleCryptoInfo(cryptoInfo);
+                mDecoder.queueSecureInputBuffer(index, 0, cryptoInfo, presentationTimeUs, flags);
+            }
+
+            result = true;
+        }
+        return result;
+    }
+
+    /**
+     * Performs a peek() operation in the queue to extract media info for the buffer ready to be
+     * released i.e. the head element of the queue.
+     *
+     * @param out_bufferInfo An output var to hold the buffer info.
+     *
+     * @return True, if the peek was successful.
+     */
+    public boolean peekSample(MediaCodec.BufferInfo out_bufferInfo) {
+        // dequeue available buffers and synchronize our data structures with the codec.
+        update();
+        boolean result = false;
+        if (!mAvailableOutputBuffers.isEmpty()) {
+            int index = mAvailableOutputBuffers.peek();
+            MediaCodec.BufferInfo info = mOutputBufferInfo[index];
+            // metadata of the sample
+            out_bufferInfo.set(
+                    info.offset,
+                    info.size,
+                    info.presentationTimeUs,
+                    info.flags);
+            result = true;
+        }
+        return result;
+    }
+
+    /**
+     * Processes, releases and optionally renders the output buffer available at the head of the
+     * queue. All observers are notified with a callback. See {@link
+     * OutputSampleListener#outputSample(MediaCodecWrapper, android.media.MediaCodec.BufferInfo,
+     * java.nio.ByteBuffer)}
+     *
+     * @param render True, if the buffer is to be rendered on the {@link Surface} configured
+     *
+     */
+    public void popSample(boolean render) {
+        // dequeue available buffers and synchronize our data structures with the codec.
+        update();
+        if (!mAvailableOutputBuffers.isEmpty()) {
+            int index = mAvailableOutputBuffers.remove();
+
+            if (render && mOutputSampleListener != null) {
+                ByteBuffer buffer = mOutputBuffers[index];
+                MediaCodec.BufferInfo info = mOutputBufferInfo[index];
+                mOutputSampleListener.outputSample(this, info, buffer);
+            }
+
+            // releases the buffer back to the codec
+            mDecoder.releaseOutputBuffer(index, render);
+        }
+    }
+
+    /**
+     * Synchronize this object's state with the internal state of the wrapped
+     * MediaCodec.
+     */
+    private void update() {
+        // BEGIN_INCLUDE(update_codec_state)
+        int index;
+
+        // Get valid input buffers from the codec to fill later in the same order they were
+        // made available by the codec.
+        while ((index = mDecoder.dequeueInputBuffer(0)) != MediaCodec.INFO_TRY_AGAIN_LATER) {
+            mAvailableInputBuffers.add(index);
+        }
+
+
+        // Likewise with output buffers. If the output buffers have changed, start using the
+        // new set of output buffers. If the output format has changed, notify listeners.
+        MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
+        while ((index = mDecoder.dequeueOutputBuffer(info, 0)) !=  MediaCodec.INFO_TRY_AGAIN_LATER) {
+            switch (index) {
+                case MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED:
+                    mOutputBuffers = mDecoder.getOutputBuffers();
+                    mOutputBufferInfo = new MediaCodec.BufferInfo[mOutputBuffers.length];
+                    mAvailableOutputBuffers.clear();
+                    break;
+                case MediaCodec.INFO_OUTPUT_FORMAT_CHANGED:
+                    if (mOutputFormatChangedListener != null) {
+                        mHandler.post(new Runnable() {
+                            @Override
+                            public void run() {
+                                mOutputFormatChangedListener
+                                        .outputFormatChanged(MediaCodecWrapper.this,
+                                                mDecoder.getOutputFormat());
+
+                            }
+                        });
+                    }
+                    break;
+                default:
+                    // Making sure the index is valid before adding to output buffers. We've already
+                    // handled INFO_TRY_AGAIN_LATER, INFO_OUTPUT_FORMAT_CHANGED &
+                    // INFO_OUTPUT_BUFFERS_CHANGED i.e all the other possible return codes but
+                    // asserting index value anyways for future-proofing the code.
+                    if(index >= 0) {
+                        mOutputBufferInfo[index] = info;
+                        mAvailableOutputBuffers.add(index);
+                    } else {
+                        throw new IllegalStateException("Unknown status from dequeueOutputBuffer");
+                    }
+                    break;
+            }
+
+        }
+        // END_INCLUDE(update_codec_state)
+
+    }
+
+    private class WriteException extends Throwable {
+        private WriteException(final String detailMessage) {
+            super(detailMessage);
+        }
+    }
+}
diff --git a/samples/browseable/BasicSyncAdapter/res/values-sw600dp/dimens.xml b/samples/browseable/BasicSyncAdapter/res/values-sw600dp/template-dimens.xml
similarity index 100%
rename from samples/browseable/BasicSyncAdapter/res/values-sw600dp/dimens.xml
rename to samples/browseable/BasicSyncAdapter/res/values-sw600dp/template-dimens.xml
diff --git a/samples/browseable/BasicSyncAdapter/res/values-sw600dp/styles.xml b/samples/browseable/BasicSyncAdapter/res/values-sw600dp/template-styles.xml
similarity index 100%
rename from samples/browseable/BasicSyncAdapter/res/values-sw600dp/styles.xml
rename to samples/browseable/BasicSyncAdapter/res/values-sw600dp/template-styles.xml
diff --git a/samples/browseable/BasicSyncAdapter/res/values/dimens.xml b/samples/browseable/BasicSyncAdapter/res/values/template-dimens.xml
similarity index 100%
rename from samples/browseable/BasicSyncAdapter/res/values/dimens.xml
rename to samples/browseable/BasicSyncAdapter/res/values/template-dimens.xml
diff --git a/samples/browseable/BasicSyncAdapter/res/values/styles.xml b/samples/browseable/BasicSyncAdapter/res/values/template-styles.xml
similarity index 100%
rename from samples/browseable/BasicSyncAdapter/res/values/styles.xml
rename to samples/browseable/BasicSyncAdapter/res/values/template-styles.xml
diff --git a/samples/browseable/BasicTransition/AndroidManifest.xml b/samples/browseable/BasicTransition/AndroidManifest.xml
new file mode 100644
index 0000000..b4698d6
--- /dev/null
+++ b/samples/browseable/BasicTransition/AndroidManifest.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.example.android.basictransition"
+    android:versionCode="1"
+    android:versionName="1.0">
+
+    <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="19" />
+
+    <application
+        android:allowBackup="true"
+        android:icon="@drawable/ic_launcher"
+        android:label="@string/app_name"
+        android:theme="@style/AppTheme" >
+        <activity
+            android:name=".MainActivity"
+            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/browseable/BasicTransition/_index.jd b/samples/browseable/BasicTransition/_index.jd
new file mode 100644
index 0000000..af2a6e7
--- /dev/null
+++ b/samples/browseable/BasicTransition/_index.jd
@@ -0,0 +1,12 @@
+
+
+
+page.tags="BasicTransition"
+sample.group=UI
+@jd:body
+
+<p>
+This sample demonstrates the basic use of the transition framework introduced in KitKat.
+Select each of the radio buttons to switch between the 
+{@link android.transition.Scene Scene}s.
+</p>
diff --git a/samples/browseable/BasicTransition/res/drawable-hdpi/ic_launcher.png b/samples/browseable/BasicTransition/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..0f5d360
--- /dev/null
+++ b/samples/browseable/BasicTransition/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/Basic/res/drawable-hdpi/tile.9.png b/samples/browseable/BasicTransition/res/drawable-hdpi/tile.9.png
similarity index 100%
rename from samples/browseable/Basic/res/drawable-hdpi/tile.9.png
rename to samples/browseable/BasicTransition/res/drawable-hdpi/tile.9.png
Binary files differ
diff --git a/samples/browseable/BasicTransition/res/drawable-mdpi/ic_launcher.png b/samples/browseable/BasicTransition/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..72d85c9
--- /dev/null
+++ b/samples/browseable/BasicTransition/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/BasicTransition/res/drawable-xhdpi/ic_launcher.png b/samples/browseable/BasicTransition/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..cf93e69
--- /dev/null
+++ b/samples/browseable/BasicTransition/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/BasicTransition/res/drawable-xxhdpi/ic_launcher.png b/samples/browseable/BasicTransition/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..149a984
--- /dev/null
+++ b/samples/browseable/BasicTransition/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/BasicTransition/res/drawable/oval.xml b/samples/browseable/BasicTransition/res/drawable/oval.xml
new file mode 100644
index 0000000..07f3abd
--- /dev/null
+++ b/samples/browseable/BasicTransition/res/drawable/oval.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="oval">
+    <solid android:color="#0000ff"/>
+</shape>
diff --git a/samples/browseable/BasicTransition/res/layout-w720dp/activity_main.xml b/samples/browseable/BasicTransition/res/layout-w720dp/activity_main.xml
new file mode 100755
index 0000000..c9a52f6
--- /dev/null
+++ b/samples/browseable/BasicTransition/res/layout-w720dp/activity_main.xml
@@ -0,0 +1,73 @@
+<!--
+  Copyright 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"
+      android:orientation="horizontal"
+      android:layout_width="match_parent"
+      android:layout_height="match_parent"
+      android:id="@+id/sample_main_layout">
+
+    <LinearLayout
+          android:id="@+id/sample_output"
+          android:layout_width="0px"
+          android:layout_height="match_parent"
+          android:layout_weight="1"
+          android:orientation="vertical">
+
+        <FrameLayout
+              style="@style/Widget.SampleMessageTile"
+              android:layout_width="match_parent"
+              android:layout_height="wrap_content">
+
+            <TextView
+                  style="@style/Widget.SampleMessage"
+                  android:layout_width="match_parent"
+                  android:layout_height="wrap_content"
+                  android:paddingLeft="@dimen/margin_medium"
+                  android:paddingRight="@dimen/margin_medium"
+                  android:paddingTop="@dimen/margin_large"
+                  android:paddingBottom="@dimen/margin_large"
+                  android:text="@string/intro_message" />
+        </FrameLayout>
+
+        <View
+              android:layout_width="match_parent"
+              android:layout_height="1dp"
+              android:background="@android:color/darker_gray" />
+
+        <fragment
+              android:name="com.example.android.common.logger.LogFragment"
+              android:id="@+id/log_fragment"
+              android:layout_width="match_parent"
+              android:layout_height="0px"
+              android:layout_weight="1" />
+
+    </LinearLayout>
+
+    <View
+          android:layout_width="1dp"
+          android:layout_height="match_parent"
+          android:background="@android:color/darker_gray" />
+
+    <FrameLayout
+          android:id="@+id/sample_content_fragment"
+          android:layout_weight="2"
+          android:layout_width="0px"
+          android:layout_height="match_parent" />
+
+</LinearLayout>
+
+
diff --git a/samples/browseable/BasicTransition/res/layout/activity_basic_transition.xml b/samples/browseable/BasicTransition/res/layout/activity_basic_transition.xml
new file mode 100644
index 0000000..f9a4cd2
--- /dev/null
+++ b/samples/browseable/BasicTransition/res/layout/activity_basic_transition.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:id="@+id/container"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    tools:context="com.example.android.basictransition.BasicTransitionActivity"/>
diff --git a/samples/browseable/BasicTransition/res/layout/activity_main.xml b/samples/browseable/BasicTransition/res/layout/activity_main.xml
new file mode 100755
index 0000000..1ae4f98
--- /dev/null
+++ b/samples/browseable/BasicTransition/res/layout/activity_main.xml
@@ -0,0 +1,65 @@
+<!--
+  Copyright 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"
+      android:orientation="vertical"
+      android:layout_width="match_parent"
+      android:layout_height="match_parent"
+      android:id="@+id/sample_main_layout">
+
+    <ViewAnimator
+          android:id="@+id/sample_output"
+          android:layout_width="match_parent"
+          android:layout_height="0px"
+          android:layout_weight="1">
+
+        <ScrollView
+              style="@style/Widget.SampleMessageTile"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent">
+
+            <TextView
+                  style="@style/Widget.SampleMessage"
+                  android:layout_width="match_parent"
+                  android:layout_height="wrap_content"
+                  android:paddingLeft="@dimen/horizontal_page_margin"
+                  android:paddingRight="@dimen/horizontal_page_margin"
+                  android:paddingTop="@dimen/vertical_page_margin"
+                  android:paddingBottom="@dimen/vertical_page_margin"
+                  android:text="@string/intro_message" />
+        </ScrollView>
+
+        <fragment
+              android:name="com.example.android.common.logger.LogFragment"
+              android:id="@+id/log_fragment"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent" />
+
+    </ViewAnimator>
+
+    <View
+          android:layout_width="match_parent"
+          android:layout_height="1dp"
+          android:background="@android:color/darker_gray" />
+
+    <FrameLayout
+          android:id="@+id/sample_content_fragment"
+          android:layout_weight="2"
+          android:layout_width="match_parent"
+          android:layout_height="0px" />
+
+</LinearLayout>
+
diff --git a/samples/browseable/BasicTransition/res/layout/fragment_basic_transition.xml b/samples/browseable/BasicTransition/res/layout/fragment_basic_transition.xml
new file mode 100644
index 0000000..98999c8
--- /dev/null
+++ b/samples/browseable/BasicTransition/res/layout/fragment_basic_transition.xml
@@ -0,0 +1,82 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<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"
+    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="com.example.android.basictransition.BasicTransitionFragment">
+
+    <RadioGroup
+        android:id="@+id/select_scene"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center_horizontal"
+        android:orientation="horizontal">
+
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_weight="1"
+            android:text="@string/scene"/>
+
+        <RadioButton
+            android:id="@+id/select_scene_1"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_weight="1"
+            android:checked="true"
+            android:text="@string/scene_1"/>
+
+        <RadioButton
+            android:id="@+id/select_scene_2"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_weight="1"
+            android:text="@string/scene_2"/>
+
+        <RadioButton
+            android:id="@+id/select_scene_3"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_weight="1"
+            android:text="@string/scene_3"/>
+
+        <RadioButton
+            android:id="@+id/select_scene_4"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_weight="1"
+            android:text="@string/scene_4"/>
+
+    </RadioGroup>
+
+    <FrameLayout
+        android:id="@+id/scene_root"
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        android:layout_weight="1">
+
+        <include layout="@layout/scene1"/>
+
+    </FrameLayout>
+
+</LinearLayout>
\ No newline at end of file
diff --git a/samples/browseable/BasicTransition/res/layout/scene1.xml b/samples/browseable/BasicTransition/res/layout/scene1.xml
new file mode 100644
index 0000000..005bf3b
--- /dev/null
+++ b/samples/browseable/BasicTransition/res/layout/scene1.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<RelativeLayout
+    android:id="@+id/container"
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <View
+        android:id="@+id/transition_square"
+        android:layout_width="@dimen/square_size_normal"
+        android:layout_height="@dimen/square_size_normal"
+        android:background="#990000"
+        android:gravity="center"/>
+
+    <ImageView
+        android:id="@+id/transition_image"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_below="@id/transition_square"
+        android:src="@drawable/ic_launcher"/>
+
+    <ImageView
+        android:id="@+id/transition_oval"
+        android:layout_width="32dp"
+        android:layout_height="32dp"
+        android:layout_below="@id/transition_image"
+        android:src="@drawable/oval"/>
+
+</RelativeLayout>
\ No newline at end of file
diff --git a/samples/browseable/BasicTransition/res/layout/scene2.xml b/samples/browseable/BasicTransition/res/layout/scene2.xml
new file mode 100644
index 0000000..38a809a
--- /dev/null
+++ b/samples/browseable/BasicTransition/res/layout/scene2.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<RelativeLayout
+    android:id="@+id/container"
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <View
+        android:id="@+id/transition_square"
+        android:layout_width="@dimen/square_size_normal"
+        android:layout_height="@dimen/square_size_normal"
+        android:layout_alignParentBottom="true"
+        android:background="#990000"
+        android:gravity="center"/>
+
+    <ImageView
+        android:id="@+id/transition_image"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignParentBottom="true"
+        android:layout_alignParentRight="true"
+        android:src="@drawable/ic_launcher"/>
+
+    <ImageView
+        android:id="@+id/transition_oval"
+        android:layout_width="32dp"
+        android:layout_height="32dp"
+        android:layout_centerHorizontal="true"
+        android:src="@drawable/oval"/>
+
+</RelativeLayout>
\ No newline at end of file
diff --git a/samples/browseable/BasicTransition/res/layout/scene3.xml b/samples/browseable/BasicTransition/res/layout/scene3.xml
new file mode 100644
index 0000000..06246da
--- /dev/null
+++ b/samples/browseable/BasicTransition/res/layout/scene3.xml
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<RelativeLayout
+    android:id="@+id/container"
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <View
+        android:id="@+id/transition_square"
+        android:layout_width="@dimen/square_size_normal"
+        android:layout_height="@dimen/square_size_normal"
+        android:layout_centerHorizontal="true"
+        android:background="#990000"
+        android:gravity="center"/>
+
+    <ImageView
+        android:id="@+id/transition_image"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignParentBottom="true"
+        android:src="@drawable/ic_launcher"/>
+
+    <ImageView
+        android:id="@+id/transition_oval"
+        android:layout_width="32dp"
+        android:layout_height="32dp"
+        android:layout_alignParentBottom="true"
+        android:layout_alignParentRight="true"
+        android:src="@drawable/oval"/>
+
+    <TextView
+        android:id="@+id/transition_title"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_centerInParent="true"
+        android:text="@string/this_is_scene_3"
+        android:textAppearance="?android:attr/textAppearanceLarge"/>
+
+</RelativeLayout>
\ No newline at end of file
diff --git a/samples/training/bitmapfun/BitmapFun/src/main/res/values/colors.xml b/samples/browseable/BasicTransition/res/menu/main.xml
similarity index 60%
copy from samples/training/bitmapfun/BitmapFun/src/main/res/values/colors.xml
copy to samples/browseable/BasicTransition/res/menu/main.xml
index 7e4a4fe..b49c2c5 100644
--- a/samples/training/bitmapfun/BitmapFun/src/main/res/values/colors.xml
+++ b/samples/browseable/BasicTransition/res/menu/main.xml
@@ -1,23 +1,21 @@
-<?xml version="1.0" encoding="utf-8"?>
 <!--
-  Copyright (C) 2012 The Android Open Source Project
+  Copyright 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
+      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>
-
-    <color name="grid_state_pressed">#BB7dbcd3</color>
-    <color name="grid_state_focused">#777dbcd3</color>
-
-</resources>
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:id="@+id/menu_toggle_log"
+          android:showAsAction="always"
+          android:title="@string/sample_show_log" />
+</menu>
diff --git a/samples/browseable/BasicTransition/res/transition/changebounds_fadein_together.xml b/samples/browseable/BasicTransition/res/transition/changebounds_fadein_together.xml
new file mode 100644
index 0000000..062e012
--- /dev/null
+++ b/samples/browseable/BasicTransition/res/transition/changebounds_fadein_together.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<transitionSet xmlns:android="http://schemas.android.com/apk/res/android">
+    <changeBounds/>
+    <fade android:fadingMode="fade_in">
+        <targets>
+            <target android:targetId="@id/transition_title" />
+        </targets>
+    </fade>
+</transitionSet>
diff --git a/samples/browseable/BasicTransition/res/transition/scene3_transition_manager.xml b/samples/browseable/BasicTransition/res/transition/scene3_transition_manager.xml
new file mode 100644
index 0000000..6189d61
--- /dev/null
+++ b/samples/browseable/BasicTransition/res/transition/scene3_transition_manager.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<transitionManager xmlns:android="http://schemas.android.com/apk/res/android">
+    <transition
+        android:toScene="@layout/scene3"
+        android:transition="@transition/changebounds_fadein_together"/>
+</transitionManager>
diff --git a/samples/browseable/Basic/res/values-sw600dp/dimens.xml b/samples/browseable/BasicTransition/res/values-sw600dp/template-dimens.xml
similarity index 100%
rename from samples/browseable/Basic/res/values-sw600dp/dimens.xml
rename to samples/browseable/BasicTransition/res/values-sw600dp/template-dimens.xml
diff --git a/samples/browseable/Basic/res/values-sw600dp/styles.xml b/samples/browseable/BasicTransition/res/values-sw600dp/template-styles.xml
similarity index 100%
rename from samples/browseable/Basic/res/values-sw600dp/styles.xml
rename to samples/browseable/BasicTransition/res/values-sw600dp/template-styles.xml
diff --git a/samples/browseable/BasicTransition/res/values-w820dp/dimens.xml b/samples/browseable/BasicTransition/res/values-w820dp/dimens.xml
new file mode 100644
index 0000000..21e2968
--- /dev/null
+++ b/samples/browseable/BasicTransition/res/values-w820dp/dimens.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<resources>
+    <!-- Example customization of dimensions originally defined in res/values/dimens.xml
+         (such as screen margins) for screens with more than 820dp of available width. This
+         would include 7" and 10" devices in landscape (~960dp and ~1280dp respectively). -->
+    <dimen name="activity_horizontal_margin">64dp</dimen>
+</resources>
diff --git a/samples/browseable/repeatingAlarm/res/values/base-strings.xml b/samples/browseable/BasicTransition/res/values/base-strings.xml
similarity index 78%
copy from samples/browseable/repeatingAlarm/res/values/base-strings.xml
copy to samples/browseable/BasicTransition/res/values/base-strings.xml
index c11b89b..466e590 100644
--- a/samples/browseable/repeatingAlarm/res/values/base-strings.xml
+++ b/samples/browseable/BasicTransition/res/values/base-strings.xml
@@ -18,13 +18,13 @@
 
 
 <resources>
-    <string name="app_name">repeatingAlarm</string>
+    <string name="app_name">BasicTransition</string>
     <string name="intro_message">
         <![CDATA[
         
             
-                Introductory text that explains what the sample is intended to demonstrate. Edit
-                in template-params.xml.
+	    This sample demonstrates the basic use of the transition framework introduced in KitKat.
+	    Select each of the RadioButtons to switch between the Scenes.
             
         
         ]]>
diff --git a/samples/browseable/BasicTransition/res/values/dimens.xml b/samples/browseable/BasicTransition/res/values/dimens.xml
new file mode 100644
index 0000000..45ccdbc
--- /dev/null
+++ b/samples/browseable/BasicTransition/res/values/dimens.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<resources>
+    <dimen name="activity_horizontal_margin">16dp</dimen>
+    <dimen name="activity_vertical_margin">16dp</dimen>
+    <dimen name="square_size_normal">50dp</dimen>
+    <dimen name="square_size_expanded">100dp</dimen>
+</resources>
diff --git a/samples/training/bitmapfun/BitmapFun/src/main/res/values/colors.xml b/samples/browseable/BasicTransition/res/values/strings.xml
old mode 100644
new mode 100755
similarity index 67%
copy from samples/training/bitmapfun/BitmapFun/src/main/res/values/colors.xml
copy to samples/browseable/BasicTransition/res/values/strings.xml
index 7e4a4fe..7b9d9ec
--- a/samples/training/bitmapfun/BitmapFun/src/main/res/values/colors.xml
+++ b/samples/browseable/BasicTransition/res/values/strings.xml
@@ -1,12 +1,11 @@
-<?xml version="1.0" encoding="utf-8"?>
 <!--
-  Copyright (C) 2012 The Android Open Source Project
+  Copyright 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
+      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,
@@ -14,10 +13,7 @@
   See the License for the specific language governing permissions and
   limitations under the License.
 -->
-
 <resources>
-
-    <color name="grid_state_pressed">#BB7dbcd3</color>
-    <color name="grid_state_focused">#777dbcd3</color>
-
+    <string name="sample_show_log">Show Log</string>
+    <string name="sample_hide_log">Hide Log</string>
 </resources>
diff --git a/samples/browseable/Basic/res/values/dimens.xml b/samples/browseable/BasicTransition/res/values/template-dimens.xml
similarity index 100%
rename from samples/browseable/Basic/res/values/dimens.xml
rename to samples/browseable/BasicTransition/res/values/template-dimens.xml
diff --git a/samples/browseable/Basic/res/values/styles.xml b/samples/browseable/BasicTransition/res/values/template-styles.xml
similarity index 100%
copy from samples/browseable/Basic/res/values/styles.xml
copy to samples/browseable/BasicTransition/res/values/template-styles.xml
diff --git a/samples/browseable/BasicTransition/src/com.example.android.basictransition/BasicTransitionFragment.java b/samples/browseable/BasicTransition/src/com.example.android.basictransition/BasicTransitionFragment.java
new file mode 100644
index 0000000..e67603d
--- /dev/null
+++ b/samples/browseable/BasicTransition/src/com.example.android.basictransition/BasicTransitionFragment.java
@@ -0,0 +1,121 @@
+/*
+ * 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.basictransition;
+
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.transition.Scene;
+import android.transition.TransitionInflater;
+import android.transition.TransitionManager;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.RadioGroup;
+
+public class BasicTransitionFragment extends Fragment
+        implements RadioGroup.OnCheckedChangeListener {
+
+    // We transition between these Scenes
+    private Scene mScene1;
+    private Scene mScene2;
+    private Scene mScene3;
+
+    /** A custom TransitionManager */
+    private TransitionManager mTransitionManagerForScene3;
+
+    /** Transitions take place in this ViewGroup. We retain this for the dynamic transition on scene 4. */
+    private ViewGroup mSceneRoot;
+
+    public static BasicTransitionFragment newInstance() {
+        return new BasicTransitionFragment();
+    }
+
+    public BasicTransitionFragment() {
+    }
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+                             Bundle savedInstanceState) {
+        View view = inflater.inflate(R.layout.fragment_basic_transition, container, false);
+        assert view != null;
+        RadioGroup radioGroup = (RadioGroup) view.findViewById(R.id.select_scene);
+        radioGroup.setOnCheckedChangeListener(this);
+        mSceneRoot = (ViewGroup) view.findViewById(R.id.scene_root);
+
+        // BEGIN_INCLUDE(instantiation_from_view)
+        // A Scene can be instantiated from a live view hierarchy.
+        mScene1 = new Scene(mSceneRoot, (ViewGroup) mSceneRoot.findViewById(R.id.container));
+        // END_INCLUDE(instantiation_from_view)
+
+        // BEGIN_INCLUDE(instantiation_from_resource)
+        // You can also inflate a generate a Scene from a layout resource file.
+        mScene2 = Scene.getSceneForLayout(mSceneRoot, R.layout.scene2, getActivity());
+        // END_INCLUDE(instantiation_from_resource)
+
+        // Another scene from a layout resource file.
+        mScene3 = Scene.getSceneForLayout(mSceneRoot, R.layout.scene3, getActivity());
+
+        // BEGIN_INCLUDE(custom_transition_manager)
+        // We create a custom TransitionManager for Scene 3, in which ChangeBounds and Fade
+        // take place at the same time.
+        mTransitionManagerForScene3 = TransitionInflater.from(getActivity())
+                .inflateTransitionManager(R.transition.scene3_transition_manager, mSceneRoot);
+        // END_INCLUDE(custom_transition_manager)
+
+        return view;
+    }
+
+    @Override
+    public void onCheckedChanged(RadioGroup group, int checkedId) {
+        switch (checkedId) {
+            case R.id.select_scene_1: {
+                // BEGIN_INCLUDE(transition_simple)
+                // You can start an automatic transition with TransitionManager.go().
+                TransitionManager.go(mScene1);
+                // END_INCLUDE(transition_simple)
+                break;
+            }
+            case R.id.select_scene_2: {
+                TransitionManager.go(mScene2);
+                break;
+            }
+            case R.id.select_scene_3: {
+                // BEGIN_INCLUDE(transition_custom)
+                // You can also start a transition with a custom TransitionManager.
+                mTransitionManagerForScene3.transitionTo(mScene3);
+                // END_INCLUDE(transition_custom)
+                break;
+            }
+            case R.id.select_scene_4: {
+                // BEGIN_INCLUDE(transition_dynamic)
+                // Alternatively, transition can be invoked dynamically without a Scene.
+                // For this, we first call TransitionManager.beginDelayedTransition().
+                TransitionManager.beginDelayedTransition(mSceneRoot);
+                // Then, we can just change view properties as usual.
+                View square = mSceneRoot.findViewById(R.id.transition_square);
+                ViewGroup.LayoutParams params = square.getLayoutParams();
+                int newSize = getResources().getDimensionPixelSize(R.dimen.square_size_expanded);
+                params.width = newSize;
+                params.height = newSize;
+                square.setLayoutParams(params);
+                // END_INCLUDE(transition_dynamic)
+                break;
+            }
+        }
+    }
+
+}
diff --git a/samples/browseable/BasicTransition/src/com.example.android.basictransition/MainActivity.java b/samples/browseable/BasicTransition/src/com.example.android.basictransition/MainActivity.java
new file mode 100644
index 0000000..1e7c301
--- /dev/null
+++ b/samples/browseable/BasicTransition/src/com.example.android.basictransition/MainActivity.java
@@ -0,0 +1,110 @@
+/*
+* Copyright 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.basictransition;
+
+import android.os.Bundle;
+import android.support.v4.app.FragmentTransaction;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.widget.ViewAnimator;
+
+import com.example.android.common.activities.SampleActivityBase;
+import com.example.android.common.logger.Log;
+import com.example.android.common.logger.LogFragment;
+import com.example.android.common.logger.LogWrapper;
+import com.example.android.common.logger.MessageOnlyLogFilter;
+
+/**
+ * A simple launcher activity containing a summary sample description, sample log and a custom
+ * {@link android.support.v4.app.Fragment} which can display a view.
+ * <p>
+ * For devices with displays with a width of 720dp or greater, the sample log is always visible,
+ * on other devices it's visibility is controlled by an item on the Action Bar.
+ */
+public class MainActivity extends SampleActivityBase {
+
+    public static final String TAG = "MainActivity";
+
+    // Whether the Log Fragment is currently shown
+    private boolean mLogShown;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_main);
+
+        FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
+        BasicTransitionFragment fragment = new BasicTransitionFragment();
+        transaction.replace(R.id.sample_content_fragment, fragment);
+        transaction.commit();
+    }
+
+    @Override
+    public boolean onCreateOptionsMenu(Menu menu) {
+        getMenuInflater().inflate(R.menu.main, menu);
+        return true;
+    }
+
+    @Override
+    public boolean onPrepareOptionsMenu(Menu menu) {
+        MenuItem logToggle = menu.findItem(R.id.menu_toggle_log);
+        logToggle.setVisible(findViewById(R.id.sample_output) instanceof ViewAnimator);
+        logToggle.setTitle(mLogShown ? R.string.sample_hide_log : R.string.sample_show_log);
+
+        return super.onPrepareOptionsMenu(menu);
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        switch(item.getItemId()) {
+            case R.id.menu_toggle_log:
+                mLogShown = !mLogShown;
+                ViewAnimator output = (ViewAnimator) findViewById(R.id.sample_output);
+                if (mLogShown) {
+                    output.setDisplayedChild(1);
+                } else {
+                    output.setDisplayedChild(0);
+                }
+                supportInvalidateOptionsMenu();
+                return true;
+        }
+        return super.onOptionsItemSelected(item);
+    }
+
+    /** Create a chain of targets that will receive log data */
+    @Override
+    public void initializeLogging() {
+        // Wraps Android's native log framework.
+        LogWrapper logWrapper = new LogWrapper();
+        // Using Log, front-end to the logging chain, emulates android.util.log method signatures.
+        Log.setLogNode(logWrapper);
+
+        // Filter strips out everything except the message text.
+        MessageOnlyLogFilter msgFilter = new MessageOnlyLogFilter();
+        logWrapper.setNext(msgFilter);
+
+        // On screen logging via a fragment with a TextView.
+        LogFragment logFragment = (LogFragment) getSupportFragmentManager()
+                .findFragmentById(R.id.log_fragment);
+        msgFilter.setNext(logFragment.getLogView());
+
+        Log.i(TAG, "Ready");
+    }
+}
diff --git a/samples/browseable/repeatingAlarm/src/com.example.android.common/activities/SampleActivityBase.java b/samples/browseable/BasicTransition/src/com.example.android.common/activities/SampleActivityBase.java
similarity index 100%
copy from samples/browseable/repeatingAlarm/src/com.example.android.common/activities/SampleActivityBase.java
copy to samples/browseable/BasicTransition/src/com.example.android.common/activities/SampleActivityBase.java
diff --git a/samples/browseable/repeatingAlarm/src/com.example.android.common/logger/Log.java b/samples/browseable/BasicTransition/src/com.example.android.common/logger/Log.java
similarity index 100%
copy from samples/browseable/repeatingAlarm/src/com.example.android.common/logger/Log.java
copy to samples/browseable/BasicTransition/src/com.example.android.common/logger/Log.java
diff --git a/samples/browseable/repeatingAlarm/src/com.example.android.common/logger/LogFragment.java b/samples/browseable/BasicTransition/src/com.example.android.common/logger/LogFragment.java
similarity index 100%
copy from samples/browseable/repeatingAlarm/src/com.example.android.common/logger/LogFragment.java
copy to samples/browseable/BasicTransition/src/com.example.android.common/logger/LogFragment.java
diff --git a/samples/browseable/repeatingAlarm/src/com.example.android.common/logger/LogNode.java b/samples/browseable/BasicTransition/src/com.example.android.common/logger/LogNode.java
similarity index 100%
copy from samples/browseable/repeatingAlarm/src/com.example.android.common/logger/LogNode.java
copy to samples/browseable/BasicTransition/src/com.example.android.common/logger/LogNode.java
diff --git a/samples/browseable/repeatingAlarm/src/com.example.android.common/logger/LogView.java b/samples/browseable/BasicTransition/src/com.example.android.common/logger/LogView.java
similarity index 100%
copy from samples/browseable/repeatingAlarm/src/com.example.android.common/logger/LogView.java
copy to samples/browseable/BasicTransition/src/com.example.android.common/logger/LogView.java
diff --git a/samples/browseable/repeatingAlarm/src/com.example.android.common/logger/LogWrapper.java b/samples/browseable/BasicTransition/src/com.example.android.common/logger/LogWrapper.java
similarity index 100%
copy from samples/browseable/repeatingAlarm/src/com.example.android.common/logger/LogWrapper.java
copy to samples/browseable/BasicTransition/src/com.example.android.common/logger/LogWrapper.java
diff --git a/samples/browseable/repeatingAlarm/src/com.example.android.common/logger/MessageOnlyLogFilter.java b/samples/browseable/BasicTransition/src/com.example.android.common/logger/MessageOnlyLogFilter.java
similarity index 100%
copy from samples/browseable/repeatingAlarm/src/com.example.android.common/logger/MessageOnlyLogFilter.java
copy to samples/browseable/BasicTransition/src/com.example.android.common/logger/MessageOnlyLogFilter.java
diff --git a/samples/browseable/BasicTransition/src/com.example.android.common/view/SlidingTabLayout.java b/samples/browseable/BasicTransition/src/com.example.android.common/view/SlidingTabLayout.java
new file mode 100644
index 0000000..20049e3
--- /dev/null
+++ b/samples/browseable/BasicTransition/src/com.example.android.common/view/SlidingTabLayout.java
@@ -0,0 +1,314 @@
+/*
+ * 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.common.view;
+
+import android.content.Context;
+import android.graphics.Typeface;
+import android.os.Build;
+import android.support.v4.view.PagerAdapter;
+import android.support.v4.view.ViewPager;
+import android.util.AttributeSet;
+import android.util.TypedValue;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.HorizontalScrollView;
+import android.widget.TextView;
+
+/**
+ * To be used with ViewPager to provide a tab indicator component which give constant feedback as to
+ * the user's scroll progress.
+ * <p>
+ * To use the component, simply add it to your view hierarchy. Then in your
+ * {@link android.app.Activity} or {@link android.support.v4.app.Fragment} call
+ * {@link #setViewPager(ViewPager)} providing it the ViewPager this layout is being used for.
+ * <p>
+ * The colors can be customized in two ways. The first and simplest is to provide an array of colors
+ * via {@link #setSelectedIndicatorColors(int...)} and {@link #setDividerColors(int...)}. The
+ * alternative is via the {@link TabColorizer} interface which provides you complete control over
+ * which color is used for any individual position.
+ * <p>
+ * The views used as tabs can be customized by calling {@link #setCustomTabView(int, int)},
+ * providing the layout ID of your custom layout.
+ */
+public class SlidingTabLayout extends HorizontalScrollView {
+
+    /**
+     * Allows complete control over the colors drawn in the tab layout. Set with
+     * {@link #setCustomTabColorizer(TabColorizer)}.
+     */
+    public interface TabColorizer {
+
+        /**
+         * @return return the color of the indicator used when {@code position} is selected.
+         */
+        int getIndicatorColor(int position);
+
+        /**
+         * @return return the color of the divider drawn to the right of {@code position}.
+         */
+        int getDividerColor(int position);
+
+    }
+
+    private static final int TITLE_OFFSET_DIPS = 24;
+    private static final int TAB_VIEW_PADDING_DIPS = 16;
+    private static final int TAB_VIEW_TEXT_SIZE_SP = 12;
+
+    private int mTitleOffset;
+
+    private int mTabViewLayoutId;
+    private int mTabViewTextViewId;
+
+    private ViewPager mViewPager;
+    private ViewPager.OnPageChangeListener mViewPagerPageChangeListener;
+
+    private final SlidingTabStrip mTabStrip;
+
+    public SlidingTabLayout(Context context) {
+        this(context, null);
+    }
+
+    public SlidingTabLayout(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public SlidingTabLayout(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+
+        // Disable the Scroll Bar
+        setHorizontalScrollBarEnabled(false);
+        // Make sure that the Tab Strips fills this View
+        setFillViewport(true);
+
+        mTitleOffset = (int) (TITLE_OFFSET_DIPS * getResources().getDisplayMetrics().density);
+
+        mTabStrip = new SlidingTabStrip(context);
+        addView(mTabStrip, LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
+    }
+
+    /**
+     * Set the custom {@link TabColorizer} to be used.
+     *
+     * If you only require simple custmisation then you can use
+     * {@link #setSelectedIndicatorColors(int...)} and {@link #setDividerColors(int...)} to achieve
+     * similar effects.
+     */
+    public void setCustomTabColorizer(TabColorizer tabColorizer) {
+        mTabStrip.setCustomTabColorizer(tabColorizer);
+    }
+
+    /**
+     * Sets the colors to be used for indicating the selected tab. These colors are treated as a
+     * circular array. Providing one color will mean that all tabs are indicated with the same color.
+     */
+    public void setSelectedIndicatorColors(int... colors) {
+        mTabStrip.setSelectedIndicatorColors(colors);
+    }
+
+    /**
+     * Sets the colors to be used for tab dividers. These colors are treated as a circular array.
+     * Providing one color will mean that all tabs are indicated with the same color.
+     */
+    public void setDividerColors(int... colors) {
+        mTabStrip.setDividerColors(colors);
+    }
+
+    /**
+     * Set the {@link ViewPager.OnPageChangeListener}. When using {@link SlidingTabLayout} you are
+     * required to set any {@link ViewPager.OnPageChangeListener} through this method. This is so
+     * that the layout can update it's scroll position correctly.
+     *
+     * @see ViewPager#setOnPageChangeListener(ViewPager.OnPageChangeListener)
+     */
+    public void setOnPageChangeListener(ViewPager.OnPageChangeListener listener) {
+        mViewPagerPageChangeListener = listener;
+    }
+
+    /**
+     * Set the custom layout to be inflated for the tab views.
+     *
+     * @param layoutResId Layout id to be inflated
+     * @param textViewId id of the {@link TextView} in the inflated view
+     */
+    public void setCustomTabView(int layoutResId, int textViewId) {
+        mTabViewLayoutId = layoutResId;
+        mTabViewTextViewId = textViewId;
+    }
+
+    /**
+     * Sets the associated view pager. Note that the assumption here is that the pager content
+     * (number of tabs and tab titles) does not change after this call has been made.
+     */
+    public void setViewPager(ViewPager viewPager) {
+        mTabStrip.removeAllViews();
+
+        mViewPager = viewPager;
+        if (viewPager != null) {
+            viewPager.setOnPageChangeListener(new InternalViewPagerListener());
+            populateTabStrip();
+        }
+    }
+
+    /**
+     * Create a default view to be used for tabs. This is called if a custom tab view is not set via
+     * {@link #setCustomTabView(int, int)}.
+     */
+    protected TextView createDefaultTabView(Context context) {
+        TextView textView = new TextView(context);
+        textView.setGravity(Gravity.CENTER);
+        textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, TAB_VIEW_TEXT_SIZE_SP);
+        textView.setTypeface(Typeface.DEFAULT_BOLD);
+
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
+            // If we're running on Honeycomb or newer, then we can use the Theme's
+            // selectableItemBackground to ensure that the View has a pressed state
+            TypedValue outValue = new TypedValue();
+            getContext().getTheme().resolveAttribute(android.R.attr.selectableItemBackground,
+                    outValue, true);
+            textView.setBackgroundResource(outValue.resourceId);
+        }
+
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
+            // If we're running on ICS or newer, enable all-caps to match the Action Bar tab style
+            textView.setAllCaps(true);
+        }
+
+        int padding = (int) (TAB_VIEW_PADDING_DIPS * getResources().getDisplayMetrics().density);
+        textView.setPadding(padding, padding, padding, padding);
+
+        return textView;
+    }
+
+    private void populateTabStrip() {
+        final PagerAdapter adapter = mViewPager.getAdapter();
+        final View.OnClickListener tabClickListener = new TabClickListener();
+
+        for (int i = 0; i < adapter.getCount(); i++) {
+            View tabView = null;
+            TextView tabTitleView = null;
+
+            if (mTabViewLayoutId != 0) {
+                // If there is a custom tab view layout id set, try and inflate it
+                tabView = LayoutInflater.from(getContext()).inflate(mTabViewLayoutId, mTabStrip,
+                        false);
+                tabTitleView = (TextView) tabView.findViewById(mTabViewTextViewId);
+            }
+
+            if (tabView == null) {
+                tabView = createDefaultTabView(getContext());
+            }
+
+            if (tabTitleView == null && TextView.class.isInstance(tabView)) {
+                tabTitleView = (TextView) tabView;
+            }
+
+            tabTitleView.setText(adapter.getPageTitle(i));
+            tabView.setOnClickListener(tabClickListener);
+
+            mTabStrip.addView(tabView);
+        }
+    }
+
+    @Override
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+
+        if (mViewPager != null) {
+            scrollToTab(mViewPager.getCurrentItem(), 0);
+        }
+    }
+
+    private void scrollToTab(int tabIndex, int positionOffset) {
+        final int tabStripChildCount = mTabStrip.getChildCount();
+        if (tabStripChildCount == 0 || tabIndex < 0 || tabIndex >= tabStripChildCount) {
+            return;
+        }
+
+        View selectedChild = mTabStrip.getChildAt(tabIndex);
+        if (selectedChild != null) {
+            int targetScrollX = selectedChild.getLeft() + positionOffset;
+
+            if (tabIndex > 0 || positionOffset > 0) {
+                // If we're not at the first child and are mid-scroll, make sure we obey the offset
+                targetScrollX -= mTitleOffset;
+            }
+
+            scrollTo(targetScrollX, 0);
+        }
+    }
+
+    private class InternalViewPagerListener implements ViewPager.OnPageChangeListener {
+        private int mScrollState;
+
+        @Override
+        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
+            int tabStripChildCount = mTabStrip.getChildCount();
+            if ((tabStripChildCount == 0) || (position < 0) || (position >= tabStripChildCount)) {
+                return;
+            }
+
+            mTabStrip.onViewPagerPageChanged(position, positionOffset);
+
+            View selectedTitle = mTabStrip.getChildAt(position);
+            int extraOffset = (selectedTitle != null)
+                    ? (int) (positionOffset * selectedTitle.getWidth())
+                    : 0;
+            scrollToTab(position, extraOffset);
+
+            if (mViewPagerPageChangeListener != null) {
+                mViewPagerPageChangeListener.onPageScrolled(position, positionOffset,
+                        positionOffsetPixels);
+            }
+        }
+
+        @Override
+        public void onPageScrollStateChanged(int state) {
+            mScrollState = state;
+
+            if (mViewPagerPageChangeListener != null) {
+                mViewPagerPageChangeListener.onPageScrollStateChanged(state);
+            }
+        }
+
+        @Override
+        public void onPageSelected(int position) {
+            if (mScrollState == ViewPager.SCROLL_STATE_IDLE) {
+                mTabStrip.onViewPagerPageChanged(position, 0f);
+                scrollToTab(position, 0);
+            }
+
+            if (mViewPagerPageChangeListener != null) {
+                mViewPagerPageChangeListener.onPageSelected(position);
+            }
+        }
+
+    }
+
+    private class TabClickListener implements View.OnClickListener {
+        @Override
+        public void onClick(View v) {
+            for (int i = 0; i < mTabStrip.getChildCount(); i++) {
+                if (v == mTabStrip.getChildAt(i)) {
+                    mViewPager.setCurrentItem(i);
+                    return;
+                }
+            }
+        }
+    }
+
+}
diff --git a/samples/browseable/BasicTransition/src/com.example.android.common/view/SlidingTabStrip.java b/samples/browseable/BasicTransition/src/com.example.android.common/view/SlidingTabStrip.java
new file mode 100644
index 0000000..d5bbbae
--- /dev/null
+++ b/samples/browseable/BasicTransition/src/com.example.android.common/view/SlidingTabStrip.java
@@ -0,0 +1,208 @@
+/*
+ * 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.common.view;
+
+import android.R;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.util.AttributeSet;
+import android.util.TypedValue;
+import android.view.View;
+import android.widget.LinearLayout;
+
+class SlidingTabStrip extends LinearLayout {
+
+    private static final int DEFAULT_BOTTOM_BORDER_THICKNESS_DIPS = 2;
+    private static final byte DEFAULT_BOTTOM_BORDER_COLOR_ALPHA = 0x26;
+    private static final int SELECTED_INDICATOR_THICKNESS_DIPS = 8;
+    private static final int DEFAULT_SELECTED_INDICATOR_COLOR = 0xFF33B5E5;
+
+    private static final int DEFAULT_DIVIDER_THICKNESS_DIPS = 1;
+    private static final byte DEFAULT_DIVIDER_COLOR_ALPHA = 0x20;
+    private static final float DEFAULT_DIVIDER_HEIGHT = 0.5f;
+
+    private final int mBottomBorderThickness;
+    private final Paint mBottomBorderPaint;
+
+    private final int mSelectedIndicatorThickness;
+    private final Paint mSelectedIndicatorPaint;
+
+    private final int mDefaultBottomBorderColor;
+
+    private final Paint mDividerPaint;
+    private final float mDividerHeight;
+
+    private int mSelectedPosition;
+    private float mSelectionOffset;
+
+    private SlidingTabLayout.TabColorizer mCustomTabColorizer;
+    private final SimpleTabColorizer mDefaultTabColorizer;
+
+    SlidingTabStrip(Context context) {
+        this(context, null);
+    }
+
+    SlidingTabStrip(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        setWillNotDraw(false);
+
+        final float density = getResources().getDisplayMetrics().density;
+
+        TypedValue outValue = new TypedValue();
+        context.getTheme().resolveAttribute(R.attr.colorForeground, outValue, true);
+        final int themeForegroundColor =  outValue.data;
+
+        mDefaultBottomBorderColor = setColorAlpha(themeForegroundColor,
+                DEFAULT_BOTTOM_BORDER_COLOR_ALPHA);
+
+        mDefaultTabColorizer = new SimpleTabColorizer();
+        mDefaultTabColorizer.setIndicatorColors(DEFAULT_SELECTED_INDICATOR_COLOR);
+        mDefaultTabColorizer.setDividerColors(setColorAlpha(themeForegroundColor,
+                DEFAULT_DIVIDER_COLOR_ALPHA));
+
+        mBottomBorderThickness = (int) (DEFAULT_BOTTOM_BORDER_THICKNESS_DIPS * density);
+        mBottomBorderPaint = new Paint();
+        mBottomBorderPaint.setColor(mDefaultBottomBorderColor);
+
+        mSelectedIndicatorThickness = (int) (SELECTED_INDICATOR_THICKNESS_DIPS * density);
+        mSelectedIndicatorPaint = new Paint();
+
+        mDividerHeight = DEFAULT_DIVIDER_HEIGHT;
+        mDividerPaint = new Paint();
+        mDividerPaint.setStrokeWidth((int) (DEFAULT_DIVIDER_THICKNESS_DIPS * density));
+    }
+
+    void setCustomTabColorizer(SlidingTabLayout.TabColorizer customTabColorizer) {
+        mCustomTabColorizer = customTabColorizer;
+        invalidate();
+    }
+
+    void setSelectedIndicatorColors(int... colors) {
+        // Make sure that the custom colorizer is removed
+        mCustomTabColorizer = null;
+        mDefaultTabColorizer.setIndicatorColors(colors);
+        invalidate();
+    }
+
+    void setDividerColors(int... colors) {
+        // Make sure that the custom colorizer is removed
+        mCustomTabColorizer = null;
+        mDefaultTabColorizer.setDividerColors(colors);
+        invalidate();
+    }
+
+    void onViewPagerPageChanged(int position, float positionOffset) {
+        mSelectedPosition = position;
+        mSelectionOffset = positionOffset;
+        invalidate();
+    }
+
+    @Override
+    protected void onDraw(Canvas canvas) {
+        final int height = getHeight();
+        final int childCount = getChildCount();
+        final int dividerHeightPx = (int) (Math.min(Math.max(0f, mDividerHeight), 1f) * height);
+        final SlidingTabLayout.TabColorizer tabColorizer = mCustomTabColorizer != null
+                ? mCustomTabColorizer
+                : mDefaultTabColorizer;
+
+        // Thick colored underline below the current selection
+        if (childCount > 0) {
+            View selectedTitle = getChildAt(mSelectedPosition);
+            int left = selectedTitle.getLeft();
+            int right = selectedTitle.getRight();
+            int color = tabColorizer.getIndicatorColor(mSelectedPosition);
+
+            if (mSelectionOffset > 0f && mSelectedPosition < (getChildCount() - 1)) {
+                int nextColor = tabColorizer.getIndicatorColor(mSelectedPosition + 1);
+                if (color != nextColor) {
+                    color = blendColors(nextColor, color, mSelectionOffset);
+                }
+
+                // Draw the selection partway between the tabs
+                View nextTitle = getChildAt(mSelectedPosition + 1);
+                left = (int) (mSelectionOffset * nextTitle.getLeft() +
+                        (1.0f - mSelectionOffset) * left);
+                right = (int) (mSelectionOffset * nextTitle.getRight() +
+                        (1.0f - mSelectionOffset) * right);
+            }
+
+            mSelectedIndicatorPaint.setColor(color);
+
+            canvas.drawRect(left, height - mSelectedIndicatorThickness, right,
+                    height, mSelectedIndicatorPaint);
+        }
+
+        // Thin underline along the entire bottom edge
+        canvas.drawRect(0, height - mBottomBorderThickness, getWidth(), height, mBottomBorderPaint);
+
+        // Vertical separators between the titles
+        int separatorTop = (height - dividerHeightPx) / 2;
+        for (int i = 0; i < childCount - 1; i++) {
+            View child = getChildAt(i);
+            mDividerPaint.setColor(tabColorizer.getDividerColor(i));
+            canvas.drawLine(child.getRight(), separatorTop, child.getRight(),
+                    separatorTop + dividerHeightPx, mDividerPaint);
+        }
+    }
+
+    /**
+     * Set the alpha value of the {@code color} to be the given {@code alpha} value.
+     */
+    private static int setColorAlpha(int color, byte alpha) {
+        return Color.argb(alpha, Color.red(color), Color.green(color), Color.blue(color));
+    }
+
+    /**
+     * Blend {@code color1} and {@code color2} using the given ratio.
+     *
+     * @param ratio of which to blend. 1.0 will return {@code color1}, 0.5 will give an even blend,
+     *              0.0 will return {@code color2}.
+     */
+    private static int blendColors(int color1, int color2, float ratio) {
+        final float inverseRation = 1f - ratio;
+        float r = (Color.red(color1) * ratio) + (Color.red(color2) * inverseRation);
+        float g = (Color.green(color1) * ratio) + (Color.green(color2) * inverseRation);
+        float b = (Color.blue(color1) * ratio) + (Color.blue(color2) * inverseRation);
+        return Color.rgb((int) r, (int) g, (int) b);
+    }
+
+    private static class SimpleTabColorizer implements SlidingTabLayout.TabColorizer {
+        private int[] mIndicatorColors;
+        private int[] mDividerColors;
+
+        @Override
+        public final int getIndicatorColor(int position) {
+            return mIndicatorColors[position % mIndicatorColors.length];
+        }
+
+        @Override
+        public final int getDividerColor(int position) {
+            return mDividerColors[position % mDividerColors.length];
+        }
+
+        void setIndicatorColors(int... colors) {
+            mIndicatorColors = colors;
+        }
+
+        void setDividerColors(int... colors) {
+            mDividerColors = colors;
+        }
+    }
+}
\ No newline at end of file
diff --git a/samples/browseable/BatchStepSensor/AndroidManifest.xml b/samples/browseable/BatchStepSensor/AndroidManifest.xml
new file mode 100644
index 0000000..2c4e4f2
--- /dev/null
+++ b/samples/browseable/BatchStepSensor/AndroidManifest.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.example.android.batchstepsensor"
+    android:versionCode="1"
+    android:versionName="1.0">
+
+    <!-- This sample requires at least Android KitKat for sensor batching support -->
+    <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="19" />
+
+    <!-- Require the step counter and step detector sensors.
+    See the method BatchStepSensorFragment#isKitkatWithStepSensor() for a programmatic check if
+    support is optional and the application supports a case where these sensors are not available.
+    -->
+    <uses-feature android:name="android.hardware.sensor.stepcounter" />
+    <uses-feature android:name="android.hardware.sensor.stepdetector" />
+
+
+    <application android:allowBackup="true"
+        android:label="@string/app_name"
+        android:icon="@drawable/ic_launcher"
+        android:theme="@style/AppTheme">
+
+        <activity android:name=".MainActivity"
+                  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/browseable/BatchStepSensor/_index.jd b/samples/browseable/BatchStepSensor/_index.jd
new file mode 100644
index 0000000..a361294
--- /dev/null
+++ b/samples/browseable/BatchStepSensor/_index.jd
@@ -0,0 +1,27 @@
+
+
+
+page.tags="BatchStepSensor"
+sample.group=Sensors
+@jd:body
+
+<p>
+  This sample demonstrates the use of the two step sensors (step detector and
+  counter) and sensor batching. It shows how to register a {@link
+  android.hardware.SensorEventListener} with and without batching and shows how
+  these events are received.
+</p>
+
+<p>
+  The Step Detector sensor fires an event when a step is detected, while the
+  step counter returns the total number of steps since a listener was first
+  registered for this sensor. Both sensors only count steps while a listener is
+  registered.
+</p>
+
+<p>
+  This sample only covers the basic case, where a listener is only registered
+  while the app is running. Likewise, batched sensors can be used in the
+  background (when the CPU is suspended), which requires manually flushing the
+  sensor event queue before it overflows, which is not covered in this sample.
+</p>
diff --git a/samples/browseable/BatchStepSensor/res/drawable-hdpi/ic_action_cancel.png b/samples/browseable/BatchStepSensor/res/drawable-hdpi/ic_action_cancel.png
new file mode 100644
index 0000000..f889617
--- /dev/null
+++ b/samples/browseable/BatchStepSensor/res/drawable-hdpi/ic_action_cancel.png
Binary files differ
diff --git a/samples/browseable/BatchStepSensor/res/drawable-hdpi/ic_launcher.png b/samples/browseable/BatchStepSensor/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..564742c
--- /dev/null
+++ b/samples/browseable/BatchStepSensor/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/Basic/res/drawable-hdpi/tile.9.png b/samples/browseable/BatchStepSensor/res/drawable-hdpi/tile.9.png
similarity index 100%
copy from samples/browseable/Basic/res/drawable-hdpi/tile.9.png
copy to samples/browseable/BatchStepSensor/res/drawable-hdpi/tile.9.png
Binary files differ
diff --git a/samples/browseable/BatchStepSensor/res/drawable-mdpi/ic_action_cancel.png b/samples/browseable/BatchStepSensor/res/drawable-mdpi/ic_action_cancel.png
new file mode 100644
index 0000000..d5a9384
--- /dev/null
+++ b/samples/browseable/BatchStepSensor/res/drawable-mdpi/ic_action_cancel.png
Binary files differ
diff --git a/samples/browseable/BatchStepSensor/res/drawable-mdpi/ic_launcher.png b/samples/browseable/BatchStepSensor/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..08abe57
--- /dev/null
+++ b/samples/browseable/BatchStepSensor/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/BatchStepSensor/res/drawable-xhdpi/card_bg.9.png b/samples/browseable/BatchStepSensor/res/drawable-xhdpi/card_bg.9.png
new file mode 100644
index 0000000..23b30c1
--- /dev/null
+++ b/samples/browseable/BatchStepSensor/res/drawable-xhdpi/card_bg.9.png
Binary files differ
diff --git a/samples/browseable/BatchStepSensor/res/drawable-xhdpi/ic_cardaction_negative.png b/samples/browseable/BatchStepSensor/res/drawable-xhdpi/ic_cardaction_negative.png
new file mode 100644
index 0000000..1e6a64e
--- /dev/null
+++ b/samples/browseable/BatchStepSensor/res/drawable-xhdpi/ic_cardaction_negative.png
Binary files differ
diff --git a/samples/browseable/BatchStepSensor/res/drawable-xhdpi/ic_cardaction_negative_pressed.png b/samples/browseable/BatchStepSensor/res/drawable-xhdpi/ic_cardaction_negative_pressed.png
new file mode 100644
index 0000000..13c105e
--- /dev/null
+++ b/samples/browseable/BatchStepSensor/res/drawable-xhdpi/ic_cardaction_negative_pressed.png
Binary files differ
diff --git a/samples/browseable/BatchStepSensor/res/drawable-xhdpi/ic_cardaction_neutral.png b/samples/browseable/BatchStepSensor/res/drawable-xhdpi/ic_cardaction_neutral.png
new file mode 100644
index 0000000..f8874cd
--- /dev/null
+++ b/samples/browseable/BatchStepSensor/res/drawable-xhdpi/ic_cardaction_neutral.png
Binary files differ
diff --git a/samples/browseable/BatchStepSensor/res/drawable-xhdpi/ic_cardaction_neutral_pressed.png b/samples/browseable/BatchStepSensor/res/drawable-xhdpi/ic_cardaction_neutral_pressed.png
new file mode 100644
index 0000000..a8f5e67
--- /dev/null
+++ b/samples/browseable/BatchStepSensor/res/drawable-xhdpi/ic_cardaction_neutral_pressed.png
Binary files differ
diff --git a/samples/browseable/BatchStepSensor/res/drawable-xhdpi/ic_cardaction_positive.png b/samples/browseable/BatchStepSensor/res/drawable-xhdpi/ic_cardaction_positive.png
new file mode 100644
index 0000000..b0a68c3
--- /dev/null
+++ b/samples/browseable/BatchStepSensor/res/drawable-xhdpi/ic_cardaction_positive.png
Binary files differ
diff --git a/samples/browseable/BatchStepSensor/res/drawable-xhdpi/ic_cardaction_positive_pressed.png b/samples/browseable/BatchStepSensor/res/drawable-xhdpi/ic_cardaction_positive_pressed.png
new file mode 100644
index 0000000..528b5aa
--- /dev/null
+++ b/samples/browseable/BatchStepSensor/res/drawable-xhdpi/ic_cardaction_positive_pressed.png
Binary files differ
diff --git a/samples/browseable/BatchStepSensor/res/drawable-xhdpi/ic_launcher.png b/samples/browseable/BatchStepSensor/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..15bafae
--- /dev/null
+++ b/samples/browseable/BatchStepSensor/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/BatchStepSensor/res/drawable-xxhdpi/ic_action_cancel.png b/samples/browseable/BatchStepSensor/res/drawable-xxhdpi/ic_action_cancel.png
new file mode 100644
index 0000000..331c545
--- /dev/null
+++ b/samples/browseable/BatchStepSensor/res/drawable-xxhdpi/ic_action_cancel.png
Binary files differ
diff --git a/samples/browseable/BatchStepSensor/res/drawable-xxhdpi/ic_launcher.png b/samples/browseable/BatchStepSensor/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..40bdd35
--- /dev/null
+++ b/samples/browseable/BatchStepSensor/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/BatchStepSensor/res/drawable/card_action_bg.xml b/samples/browseable/BatchStepSensor/res/drawable/card_action_bg.xml
new file mode 100644
index 0000000..f86cf2f
--- /dev/null
+++ b/samples/browseable/BatchStepSensor/res/drawable/card_action_bg.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:drawable="@color/card_action" android:state_pressed="true" />
+    <item android:drawable="@color/card_action_focused" android:state_focused="true" />
+    <item android:drawable="@color/card_action_item_bg" />
+</selector>
\ No newline at end of file
diff --git a/samples/browseable/BatchStepSensor/res/drawable/card_action_bg_negative.xml b/samples/browseable/BatchStepSensor/res/drawable/card_action_bg_negative.xml
new file mode 100644
index 0000000..05d38ac
--- /dev/null
+++ b/samples/browseable/BatchStepSensor/res/drawable/card_action_bg_negative.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:drawable="@color/card_action_negative" android:state_pressed="true" />
+    <item android:drawable="@color/card_action_negative_focused" android:state_focused="true" />
+    <item android:drawable="@color/card_action_item_bg" />
+</selector>
\ No newline at end of file
diff --git a/samples/browseable/BatchStepSensor/res/drawable/card_action_bg_positive.xml b/samples/browseable/BatchStepSensor/res/drawable/card_action_bg_positive.xml
new file mode 100644
index 0000000..4e92f24
--- /dev/null
+++ b/samples/browseable/BatchStepSensor/res/drawable/card_action_bg_positive.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:drawable="@color/card_action_positive" android:state_pressed="true" />
+    <item android:drawable="@color/card_action_positive_focused" android:state_focused="true" />
+    <item android:drawable="@color/card_action_item_bg" />
+</selector>
\ No newline at end of file
diff --git a/samples/browseable/BatchStepSensor/res/drawable/card_action_icon_negative.xml b/samples/browseable/BatchStepSensor/res/drawable/card_action_icon_negative.xml
new file mode 100644
index 0000000..6a797dc
--- /dev/null
+++ b/samples/browseable/BatchStepSensor/res/drawable/card_action_icon_negative.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:drawable="@drawable/ic_cardaction_negative_pressed" android:state_pressed="true" />
+    <item android:drawable="@drawable/ic_cardaction_negative" />
+</selector>
\ No newline at end of file
diff --git a/samples/browseable/BatchStepSensor/res/drawable/card_action_icon_neutral.xml b/samples/browseable/BatchStepSensor/res/drawable/card_action_icon_neutral.xml
new file mode 100644
index 0000000..73e9214
--- /dev/null
+++ b/samples/browseable/BatchStepSensor/res/drawable/card_action_icon_neutral.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:drawable="@drawable/ic_cardaction_neutral_pressed" android:state_pressed="true" />
+    <item android:drawable="@drawable/ic_cardaction_neutral" />
+</selector>
\ No newline at end of file
diff --git a/samples/browseable/BatchStepSensor/res/drawable/card_action_icon_positive.xml b/samples/browseable/BatchStepSensor/res/drawable/card_action_icon_positive.xml
new file mode 100644
index 0000000..63f82d6
--- /dev/null
+++ b/samples/browseable/BatchStepSensor/res/drawable/card_action_icon_positive.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:drawable="@drawable/ic_cardaction_positive_pressed" android:state_pressed="true" />
+    <item android:drawable="@drawable/ic_cardaction_positive" />
+</selector>
\ No newline at end of file
diff --git a/samples/browseable/BatchStepSensor/res/drawable/card_action_text.xml b/samples/browseable/BatchStepSensor/res/drawable/card_action_text.xml
new file mode 100644
index 0000000..cddf5cd
--- /dev/null
+++ b/samples/browseable/BatchStepSensor/res/drawable/card_action_text.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_pressed="true" android:color="@color/card_action_inverted" />
+    <item android:state_focused="true" android:color="@color/card_action_inverted" />
+    <item android:color="@color/card_action" />
+</selector>
\ No newline at end of file
diff --git a/samples/browseable/BatchStepSensor/res/drawable/card_action_text_negative.xml b/samples/browseable/BatchStepSensor/res/drawable/card_action_text_negative.xml
new file mode 100644
index 0000000..90f2c05
--- /dev/null
+++ b/samples/browseable/BatchStepSensor/res/drawable/card_action_text_negative.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_pressed="true" android:color="@color/card_action_inverted"/>
+    <item android:state_focused="true" android:color="@color/card_action_inverted"/>
+    <item android:color="@color/card_action_negative"/>
+</selector>
\ No newline at end of file
diff --git a/samples/browseable/BatchStepSensor/res/drawable/card_action_text_positive.xml b/samples/browseable/BatchStepSensor/res/drawable/card_action_text_positive.xml
new file mode 100644
index 0000000..c3ff402
--- /dev/null
+++ b/samples/browseable/BatchStepSensor/res/drawable/card_action_text_positive.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_pressed="true" android:color="@color/card_action_inverted"/>
+    <item android:state_focused="true" android:color="@color/card_action_inverted"/>
+    <item android:color="@color/card_action_positive"/>
+</selector>
\ No newline at end of file
diff --git a/samples/browseable/BatchStepSensor/res/drawable/card_overlay_focused.xml b/samples/browseable/BatchStepSensor/res/drawable/card_overlay_focused.xml
new file mode 100644
index 0000000..787167d
--- /dev/null
+++ b/samples/browseable/BatchStepSensor/res/drawable/card_overlay_focused.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+       android:shape="rectangle">
+    <stroke
+        android:width="5dp"
+        android:color="#aa99CC00"/>
+</shape>
\ No newline at end of file
diff --git a/samples/browseable/BatchStepSensor/res/drawable/card_separator.xml b/samples/browseable/BatchStepSensor/res/drawable/card_separator.xml
new file mode 100644
index 0000000..6bb5630
--- /dev/null
+++ b/samples/browseable/BatchStepSensor/res/drawable/card_separator.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="line">
+    <stroke android:color="#CCC" />
+    <size android:height="1dp" />
+</shape>
\ No newline at end of file
diff --git a/samples/browseable/repeatingAlarm/res/values/base-strings.xml b/samples/browseable/BatchStepSensor/res/layout/activity_main.xml
old mode 100644
new mode 100755
similarity index 61%
copy from samples/browseable/repeatingAlarm/res/values/base-strings.xml
copy to samples/browseable/BatchStepSensor/res/layout/activity_main.xml
index c11b89b..b8a123e
--- a/samples/browseable/repeatingAlarm/res/values/base-strings.xml
+++ b/samples/browseable/BatchStepSensor/res/layout/activity_main.xml
@@ -17,16 +17,12 @@
 
 
 
-<resources>
-    <string name="app_name">repeatingAlarm</string>
-    <string name="intro_message">
-        <![CDATA[
-        
-            
-                Introductory text that explains what the sample is intended to demonstrate. Edit
-                in template-params.xml.
-            
-        
-        ]]>
-    </string>
-</resources>
+<fragment
+    android:id="@+id/fragment_cardstream"
+    android:name="com.example.android.batchstepsensor.CardStreamFragment"
+    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=".MainActivity"
+    tools:layout="@layout/cardstream"/>
diff --git a/samples/browseable/BatchStepSensor/res/layout/card.xml b/samples/browseable/BatchStepSensor/res/layout/card.xml
new file mode 100644
index 0000000..24bffeb
--- /dev/null
+++ b/samples/browseable/BatchStepSensor/res/layout/card.xml
@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 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.
+-->
+
+
+
+<com.example.android.batchstepsensor.CardLayout
+    android:id="@+id/card_layout"
+    style="@style/Card"
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content">
+
+    <LinearLayout
+        android:id="@+id/card_actionarea"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:layout_below="@+id/card_contentarea"
+        android:background="@color/card_action_bg"
+        android:orientation="vertical"
+        android:paddingBottom="@dimen/card_action_margin"
+        android:visibility="gone"
+        >
+        <include layout="@layout/card_button_seperator"/>
+    </LinearLayout>
+
+
+    <LinearLayout
+        android:id="@id/card_contentarea"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="vertical"
+        style="@style/CardContentArea">
+
+        <TextView
+            android:id="@+id/card_title"
+            style="@style/CardTitle"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"/>
+
+        <TextView
+            android:id="@+id/card_content"
+            style="@style/CardContent"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_below="@id/card_title"/>
+
+    </LinearLayout>
+
+    <View
+        android:id="@+id/card_overlay"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:layout_alignBottom="@id/card_contentarea"
+        android:layout_alignLeft="@id/card_contentarea"
+        android:layout_alignRight="@id/card_contentarea"
+        android:layout_alignTop="@id/card_contentarea"
+        android:layout_alignWithParentIfMissing="false"
+        android:visibility="invisible"/>
+
+</com.example.android.batchstepsensor.CardLayout>
diff --git a/samples/browseable/repeatingAlarm/res/values/base-strings.xml b/samples/browseable/BatchStepSensor/res/layout/card_button_negative.xml
similarity index 64%
copy from samples/browseable/repeatingAlarm/res/values/base-strings.xml
copy to samples/browseable/BatchStepSensor/res/layout/card_button_negative.xml
index c11b89b..bf66150 100644
--- a/samples/browseable/repeatingAlarm/res/values/base-strings.xml
+++ b/samples/browseable/BatchStepSensor/res/layout/card_button_negative.xml
@@ -17,16 +17,9 @@
 
 
 
-<resources>
-    <string name="app_name">repeatingAlarm</string>
-    <string name="intro_message">
-        <![CDATA[
-        
-            
-                Introductory text that explains what the sample is intended to demonstrate. Edit
-                in template-params.xml.
-            
-        
-        ]]>
-    </string>
-</resources>
+<com.example.android.batchstepsensor.CardActionButton xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/card_button"
+    style="@style/CardActionNegative"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:gravity="center_vertical" />
\ No newline at end of file
diff --git a/samples/browseable/repeatingAlarm/res/values/base-strings.xml b/samples/browseable/BatchStepSensor/res/layout/card_button_neutral.xml
similarity index 64%
copy from samples/browseable/repeatingAlarm/res/values/base-strings.xml
copy to samples/browseable/BatchStepSensor/res/layout/card_button_neutral.xml
index c11b89b..7f759fc 100644
--- a/samples/browseable/repeatingAlarm/res/values/base-strings.xml
+++ b/samples/browseable/BatchStepSensor/res/layout/card_button_neutral.xml
@@ -17,16 +17,9 @@
 
 
 
-<resources>
-    <string name="app_name">repeatingAlarm</string>
-    <string name="intro_message">
-        <![CDATA[
-        
-            
-                Introductory text that explains what the sample is intended to demonstrate. Edit
-                in template-params.xml.
-            
-        
-        ]]>
-    </string>
-</resources>
+<com.example.android.batchstepsensor.CardActionButton xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/card_button"
+    style="@style/CardActionNeutral"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:gravity="center_vertical" />
diff --git a/samples/browseable/repeatingAlarm/res/values/base-strings.xml b/samples/browseable/BatchStepSensor/res/layout/card_button_positive.xml
similarity index 64%
copy from samples/browseable/repeatingAlarm/res/values/base-strings.xml
copy to samples/browseable/BatchStepSensor/res/layout/card_button_positive.xml
index c11b89b..2011f9c 100644
--- a/samples/browseable/repeatingAlarm/res/values/base-strings.xml
+++ b/samples/browseable/BatchStepSensor/res/layout/card_button_positive.xml
@@ -17,16 +17,9 @@
 
 
 
-<resources>
-    <string name="app_name">repeatingAlarm</string>
-    <string name="intro_message">
-        <![CDATA[
-        
-            
-                Introductory text that explains what the sample is intended to demonstrate. Edit
-                in template-params.xml.
-            
-        
-        ]]>
-    </string>
-</resources>
+<com.example.android.batchstepsensor.CardActionButton xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/card_button"
+    style="@style/CardActionPositive"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:gravity="center_vertical" />
diff --git a/samples/browseable/BatchStepSensor/res/layout/card_button_seperator.xml b/samples/browseable/BatchStepSensor/res/layout/card_button_seperator.xml
new file mode 100644
index 0000000..6731242
--- /dev/null
+++ b/samples/browseable/BatchStepSensor/res/layout/card_button_seperator.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<merge xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <ImageView
+        android:id="@+id/card_separator"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:src="@drawable/card_separator" />
+
+</merge>
\ No newline at end of file
diff --git a/samples/browseable/BatchStepSensor/res/layout/card_progress.xml b/samples/browseable/BatchStepSensor/res/layout/card_progress.xml
new file mode 100644
index 0000000..1bf349f
--- /dev/null
+++ b/samples/browseable/BatchStepSensor/res/layout/card_progress.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical"
+    style="@style/CardProgressLayout">
+
+    <TextView
+        android:id="@+id/card_progress_text"
+        style="@style/CardProgressText"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        />
+
+    <ProgressBar
+        android:id="@+id/card_progress"
+        style="@android:style/Widget.Holo.ProgressBar.Horizontal"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        />
+
+</LinearLayout>
\ No newline at end of file
diff --git a/samples/browseable/BatchStepSensor/res/layout/cardstream.xml b/samples/browseable/BatchStepSensor/res/layout/cardstream.xml
new file mode 100644
index 0000000..463af5c
--- /dev/null
+++ b/samples/browseable/BatchStepSensor/res/layout/cardstream.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 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.
+-->
+
+
+
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:fillViewport="true">
+
+    <com.example.android.batchstepsensor.CardStreamLinearLayout
+        style="@style/CardStream"
+        android:id="@+id/card_stream"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent">
+    </com.example.android.batchstepsensor.CardStreamLinearLayout>
+</ScrollView>
diff --git a/samples/browseable/BasicMediaRouter/res/values-sw600dp/dimens.xml b/samples/browseable/BatchStepSensor/res/values-sw600dp/template-dimens.xml
similarity index 100%
copy from samples/browseable/BasicMediaRouter/res/values-sw600dp/dimens.xml
copy to samples/browseable/BatchStepSensor/res/values-sw600dp/template-dimens.xml
diff --git a/samples/browseable/BasicMediaRouter/res/values-sw600dp/styles.xml b/samples/browseable/BatchStepSensor/res/values-sw600dp/template-styles.xml
similarity index 100%
copy from samples/browseable/BasicMediaRouter/res/values-sw600dp/styles.xml
copy to samples/browseable/BatchStepSensor/res/values-sw600dp/template-styles.xml
diff --git a/samples/browseable/BatchStepSensor/res/values-sw720dp-land/dimens.xml b/samples/browseable/BatchStepSensor/res/values-sw720dp-land/dimens.xml
new file mode 100644
index 0000000..00059fc
--- /dev/null
+++ b/samples/browseable/BatchStepSensor/res/values-sw720dp-land/dimens.xml
@@ -0,0 +1,5 @@
+<resources>
+    <!-- Customize dimensions originally defined in res/values/dimens.xml (such as
+         screen margins) for sw720dp devices (e.g. 10" tablets) in landscape here. -->
+    <dimen name="activity_horizontal_margin">128dp</dimen>
+</resources>
diff --git a/samples/browseable/BatchStepSensor/res/values-v11/styles.xml b/samples/browseable/BatchStepSensor/res/values-v11/styles.xml
new file mode 100644
index 0000000..3c02242
--- /dev/null
+++ b/samples/browseable/BatchStepSensor/res/values-v11/styles.xml
@@ -0,0 +1,11 @@
+<resources>
+
+    <!--
+        Base application theme for API 11+. This theme completely replaces
+        AppBaseTheme from res/values/styles.xml on API 11+ devices.
+    -->
+    <style name="AppBaseTheme" parent="android:Theme.Holo.Light">
+        <!-- API 11 theme customizations can go here. -->
+    </style>
+
+</resources>
diff --git a/samples/browseable/BatchStepSensor/res/values-v14/styles.xml b/samples/browseable/BatchStepSensor/res/values-v14/styles.xml
new file mode 100644
index 0000000..a91fd03
--- /dev/null
+++ b/samples/browseable/BatchStepSensor/res/values-v14/styles.xml
@@ -0,0 +1,12 @@
+<resources>
+
+    <!--
+        Base application theme for API 14+. This theme completely replaces
+        AppBaseTheme from BOTH res/values/styles.xml and
+        res/values-v11/styles.xml on API 14+ devices.
+    -->
+    <style name="AppBaseTheme" parent="android:Theme.Holo.Light.DarkActionBar">
+        <!-- API 14 theme customizations can go here. -->
+    </style>
+
+</resources>
diff --git a/samples/browseable/BatchStepSensor/res/values-v16/styles.xml b/samples/browseable/BatchStepSensor/res/values-v16/styles.xml
new file mode 100644
index 0000000..2b380aa
--- /dev/null
+++ b/samples/browseable/BatchStepSensor/res/values-v16/styles.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+    <style name="CardTitle" parent="@style/CardTitleBase">
+        <item name="android:fontFamily">sans-serif-condensed</item>
+    </style>
+
+    <style name="CardContent" parent="@style/CardContentBase">
+        <item name="android:fontFamily">sans-serif-light</item>
+    </style>
+</resources>
\ No newline at end of file
diff --git a/samples/browseable/BatchStepSensor/res/values/attrs.xml b/samples/browseable/BatchStepSensor/res/values/attrs.xml
new file mode 100644
index 0000000..16b5260
--- /dev/null
+++ b/samples/browseable/BatchStepSensor/res/values/attrs.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+    <declare-styleable name="CardStream">
+        <attr name="animationDuration" format="enum">
+            <enum name="slow" value="1001"/>
+            <enum name="normal" value="1002"/>
+            <enum name="fast" value="1003"/>
+        </attr>
+        <attr name="animators" format="string"/>
+    </declare-styleable>
+
+
+</resources>
\ No newline at end of file
diff --git a/samples/browseable/BatchStepSensor/res/values/base-strings.xml b/samples/browseable/BatchStepSensor/res/values/base-strings.xml
new file mode 100644
index 0000000..341b6bc
--- /dev/null
+++ b/samples/browseable/BatchStepSensor/res/values/base-strings.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 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">BatchStepSensor</string>
+    <string name="intro_message">
+        <![CDATA[
+        
+            
+            This sample demonstrates the use of the two step sensors (step detector and counter) and
+            sensor batching.\n\n It shows how to register a SensorEventListener with and without
+            batching and shows how these events are received.\n\nThe Step Detector sensor fires an
+            event when a step is detected, while the step counter returns the total number of
+            steps since a listener was first registered for this sensor.
+            Both sensors only count steps while a listener is registered. This sample only covers the
+            basic case, where a listener is only registered while the app is running. Likewise,
+            batched sensors can be used in the background (when the CPU is suspended), which
+            requires manually flushing the sensor event queue before it overflows, which is not
+            covered in this sample.
+            
+        
+        ]]>
+    </string>
+</resources>
diff --git a/samples/browseable/BatchStepSensor/res/values/color.xml b/samples/browseable/BatchStepSensor/res/values/color.xml
new file mode 100644
index 0000000..98717d8
--- /dev/null
+++ b/samples/browseable/BatchStepSensor/res/values/color.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+    <color name="card_action_inverted">@android:color/white</color>
+
+    <color name="card_content_textcolor">#444</color>
+
+    <color name="card_action_bg">#DDD</color>
+    <color name="card_action_item_bg">#F4F4F4</color>
+
+    <!-- Neutral Actions -->
+    <color name="card_action_focused">#FFE3F4FC</color>
+    <color name="card_action">#FF47B4EA</color>
+
+    <!-- Negative Actions -->
+    <color name="card_action_negative_focused">#FFFBCBCA</color>
+    <color name="card_action_negative">#FFF64940</color>
+
+    <!-- Positive Actions -->
+    <color name="card_action_positive_focused">#FFE4F0AF</color>
+    <color name="card_action_positive">#FFA0CC00</color>
+</resources>
\ No newline at end of file
diff --git a/samples/browseable/BatchStepSensor/res/values/dimens.xml b/samples/browseable/BatchStepSensor/res/values/dimens.xml
new file mode 100644
index 0000000..b025f1f
--- /dev/null
+++ b/samples/browseable/BatchStepSensor/res/values/dimens.xml
@@ -0,0 +1,14 @@
+<resources>
+
+    <dimen name="card_content_text">14sp</dimen>
+    <dimen name="card_content_title">24sp</dimen>
+
+    <dimen name="card_padding">15dp</dimen>
+    <dimen name="card_margin">10dp</dimen>
+
+    <dimen name="card_action_margin">3dp</dimen>
+    <dimen name="card_action_padding">8dp</dimen>
+
+    <dimen name="card_stream_bottom_padding">90dp</dimen>
+
+</resources>
diff --git a/samples/browseable/BatchStepSensor/res/values/ids.xml b/samples/browseable/BatchStepSensor/res/values/ids.xml
new file mode 100644
index 0000000..c5d1b78
--- /dev/null
+++ b/samples/browseable/BatchStepSensor/res/values/ids.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <item name="card_layout" type="id"/>
+    <item name="card_actionarea" type="id"/>
+    <item name="card_contentarea" type="id"/>
+    <item name="card_title" type="id"/>
+    <item name="card_content" type="id"/>
+    <item name="card_overlay" type="id"/>
+</resources>
\ No newline at end of file
diff --git a/samples/browseable/BatchStepSensor/res/values/strings.xml b/samples/browseable/BatchStepSensor/res/values/strings.xml
new file mode 100644
index 0000000..9c0a8ad
--- /dev/null
+++ b/samples/browseable/BatchStepSensor/res/values/strings.xml
@@ -0,0 +1,75 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<resources>
+    <string name="intro_title">Introduction</string>
+
+    <string name="batching_queue_title">Background sensor batching</string>
+    <string name="batching_queue_description">Batching allows the sensor to report sensor events at
+        a specified frequency.\n\nThe system delays calls to the SensorEventListener and deliver
+        them in intervals, based on the maximum report latency specified when the listener is
+        registered. Note that this only means that the call to onSensorChanged() is delayed, the
+        total number of calls is identical as if no batching was used. Sensors only deliver events
+        while the CPU is awake. If the CPU is asleep and a batched sensor event listener is still
+        registered, the sensor will continue to collect events until it runs out of memory and
+        overwrites old values. This use case is not covered by this sample. (The sensor event queue
+        should be flushed using a scheduled background thread.) \n\nIn this sample app data is only
+        collected while the app is running and the CPU is awake. In this case the sensor will
+        deliver events before the queue fills up.
+    </string>
+
+    <string name="explanation_description">The age of a sensor event describes the delay between
+        when it was recorded by the sensor until it was delivered to the SensorEventListener.
+    </string>
+
+    <string name="register_detector_title">Register step detector sensor</string>
+    <string name="register_detector_description">Register a listener for the STEP DETECTOR
+        sensor.\n\nThis sensor delivers an event when the user takes a step. One event is received
+        per step.
+    </string>
+
+    <string name="register_counter_title">Register step counter sensor</string>
+    <string name="register_counter_description">Register a listener for the STEP COUNTER
+        sensor.\n\nThis sensor triggers events when a step is detected, but applies algorithms to
+        filter out false positives. Events from this sensor have higher latency than the step
+        detector and contain the total number of steps taken since the sensor was first registered.
+    </string>
+
+    <string name="register_0">No batching (delay=0)</string>
+    <string name="register_5">5s batching (delay=5000ms)</string>
+    <string name="register_10">10s batching (delay=10000ms)</string>
+
+    <string name="counting_title">Total Steps: %1$d</string>
+    <string name="sensor_counter">Step Counter</string>
+    <string name="sensor_detector">Step Detector</string>
+    <string name="counting_description">Sensor: %1$s\nMax sensor event delay: %2$,d \u00B5s\nAge of
+        events in s:\n%3$s
+    </string>
+
+    <string name="error_title">Error</string>
+    <string name="error_nosensor">This sample requires at least Android KitKat (4.4) and a device
+        with the step sensor.\n\nThis device does not appear to meet these requirements, as an
+        alternative you may want to consider using the gyro sensor and implement your own step
+        recognition as a fallback.
+    </string>
+    <string name="warning_nobatching">The listener has been registered, but batch mode could not be
+        enabled.\n\nIt is likely that it is not supported by this device.\n\nSensor events will be
+        delivered in continuous mode.
+    </string>
+
+    <string name="action_notagain">Do not show again</string>
+</resources>
\ No newline at end of file
diff --git a/samples/browseable/BatchStepSensor/res/values/styles.xml b/samples/browseable/BatchStepSensor/res/values/styles.xml
new file mode 100644
index 0000000..23e8181
--- /dev/null
+++ b/samples/browseable/BatchStepSensor/res/values/styles.xml
@@ -0,0 +1,92 @@
+<resources>
+
+    <!-- Card Stream -->
+    <style name="CardStream">
+        <item name="android:paddingBottom">@dimen/card_stream_bottom_padding</item>
+        <item name="android:divider">@null</item>
+        <item name="android:orientation">vertical</item>
+    </style>
+
+    <!-- Main card -->
+    <style name="Card">
+        <item name="android:background">@drawable/card_bg</item>
+        <item name="android:layout_margin">@dimen/card_margin</item>
+    </style>
+
+    <style name="CardContentArea">
+        <item name="android:paddingBottom">@dimen/card_padding</item>
+    </style>
+
+    <style name="CardActionArea">
+        <item name="android:background">@color/card_action_bg</item>
+        <item name="android:orientation">vertical</item>
+        <item name="android:paddingBottom">@dimen/card_action_margin</item>
+    </style>
+
+    <style name="CardElement">
+        <item name="android:paddingLeft">@dimen/card_padding</item>
+        <item name="android:paddingRight">@dimen/card_padding</item>
+    </style>
+
+    <!-- Content of main card -->
+    <style name="CardTitleBase" parent="@style/CardElement">
+        <item name="android:paddingTop">@dimen/card_padding</item>
+        <item name="android:textSize">@dimen/card_content_title</item>
+    </style>
+
+    <style name="CardTitle" parent="@style/CardTitleBase">
+    </style>
+
+    <style name="CardContentBase" parent="@style/CardElement">
+        <item name="android:paddingTop">@dimen/card_padding</item>
+        <item name="android:textSize">@dimen/card_content_text</item>
+        <item name="android:textColor">@color/card_content_textcolor</item>
+    </style>
+
+    <style name="CardContent" parent="@style/CardContentBase">
+    </style>
+
+    <!-- Action Area Items -->
+    <style name="CardAction">
+        <item name="android:textSize">17sp</item>
+        <item name="android:layout_marginTop">@dimen/card_action_margin</item>
+        <item name="android:layout_marginLeft">@dimen/card_action_margin</item>
+        <item name="android:layout_marginRight">@dimen/card_action_margin</item>
+        <item name="android:paddingLeft">@dimen/card_action_padding</item>
+        <item name="android:drawablePadding">@dimen/card_action_padding</item>
+    </style>
+
+    <style name="CardActionNeutral" parent="@style/CardAction">
+        <item name="android:background">@drawable/card_action_bg</item>
+        <item name="android:drawableStart">@drawable/card_action_icon_neutral</item>
+        <item name="android:textColor">@drawable/card_action_text</item>
+    </style>
+
+    <style name="CardActionNegative" parent="@style/CardAction">
+        <item name="android:background">@drawable/card_action_bg_negative</item>
+        <item name="android:drawableStart">@drawable/card_action_icon_negative</item>
+        <item name="android:textColor">@drawable/card_action_text_negative</item>
+    </style>
+
+    <style name="CardActionPositive" parent="@style/CardAction">
+        <item name="android:background">@drawable/card_action_bg_positive</item>
+        <item name="android:drawableStart">@drawable/card_action_icon_positive</item>
+        <item name="android:textColor">@drawable/card_action_text_positive</item>
+    </style>
+
+    <!-- Card Action Progress -->
+    <style name="CardProgressLayout" parent="@style/CardAction">
+        <item name="android:layout_marginLeft">@dimen/card_action_margin</item>
+        <item name="android:layout_marginRight">@dimen/card_action_margin</item>
+        <item name="android:paddingLeft">@dimen/card_action_padding</item>
+        <item name="android:paddingRight">@dimen/card_action_padding</item>
+        <item name="android:background">#EEE</item>
+    </style>
+
+    <style name="CardProgressText" parent="@style/CardAction">
+        <item name="android:textColor">#77000000</item>
+        <item name="android:textSize">12sp</item>
+        <item name="android:paddingLeft">0dp</item>
+    </style>
+
+</resources>
\ No newline at end of file
diff --git a/samples/browseable/Basic/res/values/dimens.xml b/samples/browseable/BatchStepSensor/res/values/template-dimens.xml
similarity index 100%
copy from samples/browseable/Basic/res/values/dimens.xml
copy to samples/browseable/BatchStepSensor/res/values/template-dimens.xml
diff --git a/samples/browseable/Basic/res/values/styles.xml b/samples/browseable/BatchStepSensor/res/values/template-styles.xml
similarity index 100%
copy from samples/browseable/Basic/res/values/styles.xml
copy to samples/browseable/BatchStepSensor/res/values/template-styles.xml
diff --git a/samples/browseable/BatchStepSensor/src/com.example.android.batchstepsensor/BatchStepSensorFragment.java b/samples/browseable/BatchStepSensor/src/com.example.android.batchstepsensor/BatchStepSensorFragment.java
new file mode 100644
index 0000000..aab0fc3
--- /dev/null
+++ b/samples/browseable/BatchStepSensor/src/com.example.android.batchstepsensor/BatchStepSensorFragment.java
@@ -0,0 +1,588 @@
+/*
+* Copyright 2014 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+package com.example.android.batchstepsensor;
+
+import android.app.Activity;
+import android.content.pm.PackageManager;
+import android.hardware.Sensor;
+import android.hardware.SensorEvent;
+import android.hardware.SensorEventListener;
+import android.hardware.SensorManager;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+
+import com.example.android.common.logger.Log;
+
+public class BatchStepSensorFragment extends Fragment implements OnCardClickListener {
+
+    public static final String TAG = "StepSensorSample";
+    // Cards
+    private CardStreamFragment mCards = null;
+
+    // Card tags
+    public static final String CARD_INTRO = "intro";
+    public static final String CARD_REGISTER_DETECTOR = "register_detector";
+    public static final String CARD_REGISTER_COUNTER = "register_counter";
+    public static final String CARD_BATCHING_DESCRIPTION = "register_batching_description";
+    public static final String CARD_COUNTING = "counting";
+    public static final String CARD_EXPLANATION = "explanation";
+    public static final String CARD_NOBATCHSUPPORT = "error";
+
+    // Actions from REGISTER cards
+    public static final int ACTION_REGISTER_DETECT_NOBATCHING = 10;
+    public static final int ACTION_REGISTER_DETECT_BATCHING_5s = 11;
+    public static final int ACTION_REGISTER_DETECT_BATCHING_10s = 12;
+    public static final int ACTION_REGISTER_COUNT_NOBATCHING = 21;
+    public static final int ACTION_REGISTER_COUNT_BATCHING_5s = 22;
+    public static final int ACTION_REGISTER_COUNT_BATCHING_10s = 23;
+    // Action from COUNTING card
+    public static final int ACTION_UNREGISTER = 1;
+    // Actions from description cards
+    private static final int ACTION_BATCHING_DESCRIPTION_DISMISS = 2;
+    private static final int ACTION_EXPLANATION_DISMISS = 3;
+
+    // State of application, used to register for sensors when app is restored
+    public static final int STATE_OTHER = 0;
+    public static final int STATE_COUNTER = 1;
+    public static final int STATE_DETECTOR = 2;
+
+    // Bundle tags used to store data when restoring application state
+    private static final String BUNDLE_STATE = "state";
+    private static final String BUNDLE_LATENCY = "latency";
+    private static final String BUNDLE_STEPS = "steps";
+
+    // max batch latency is specified in microseconds
+    private static final int BATCH_LATENCY_0 = 0; // no batching
+    private static final int BATCH_LATENCY_10s = 10000000;
+    private static final int BATCH_LATENCY_5s = 5000000;
+
+    /*
+    For illustration we keep track of the last few events and show their delay from when the
+    event occurred until it was received by the event listener.
+    These variables keep track of the list of timestamps and the number of events.
+     */
+    // Number of events to keep in queue and display on card
+    private static final int EVENT_QUEUE_LENGTH = 10;
+    // List of timestamps when sensor events occurred
+    private float[] mEventDelays = new float[EVENT_QUEUE_LENGTH];
+
+    // number of events in event list
+    private int mEventLength = 0;
+    // pointer to next entry in sensor event list
+    private int mEventData = 0;
+
+    // Steps counted in current session
+    private int mSteps = 0;
+    // Value of the step counter sensor when the listener was registered.
+    // (Total steps are calculated from this value.)
+    private int mCounterSteps = 0;
+    // Steps counted by the step counter previously. Used to keep counter consistent across rotation
+    // changes
+    private int mPreviousCounterSteps = 0;
+    // State of the app (STATE_OTHER, STATE_COUNTER or STATE_DETECTOR)
+    private int mState = STATE_OTHER;
+    // When a listener is registered, the batch sensor delay in microseconds
+    private int mMaxDelay = 0;
+
+    @Override
+    public void onResume() {
+        super.onResume();
+
+        CardStreamFragment stream = getCardStream();
+        if (stream.getVisibleCardCount() < 1) {
+            // No cards are visible, started for the first time
+            // Prepare all cards and show the intro card.
+            initialiseCards();
+            showIntroCard();
+            // Show the registration card if the hardware is supported, show an error otherwise
+            if (isKitkatWithStepSensor()) {
+                showRegisterCard();
+            } else {
+                showErrorCard();
+            }
+        }
+    }
+
+    @Override
+    public void onPause() {
+        super.onPause();
+        // BEGIN_INCLUDE(onpause)
+        // Unregister the listener when the application is paused
+        unregisterListeners();
+        // END_INCLUDE(onpause)
+    }
+
+    /**
+     * Returns true if this device is supported. It needs to be running Android KitKat (4.4) or
+     * higher and has a step counter and step detector sensor.
+     * This check is useful when an app provides an alternative implementation or different
+     * functionality if the step sensors are not available or this code runs on a platform version
+     * below Android KitKat. If this functionality is required, then the minSDK parameter should
+     * be specified appropriately in the AndroidManifest.
+     *
+     * @return True iff the device can run this sample
+     */
+    private boolean isKitkatWithStepSensor() {
+        // BEGIN_INCLUDE(iskitkatsensor)
+        // Require at least Android KitKat
+        int currentApiVersion = android.os.Build.VERSION.SDK_INT;
+        // Check that the device supports the step counter and detector sensors
+        PackageManager packageManager = getActivity().getPackageManager();
+        return currentApiVersion >= android.os.Build.VERSION_CODES.KITKAT
+                && packageManager.hasSystemFeature(PackageManager.FEATURE_SENSOR_STEP_COUNTER)
+                && packageManager.hasSystemFeature(PackageManager.FEATURE_SENSOR_STEP_DETECTOR);
+        // END_INCLUDE(iskitkatsensor)
+    }
+
+    /**
+     * Handles a click on a card action.
+     * Registers a SensorEventListener (see {@link #registerEventListener(int, int)}) with the
+     * selected delay, dismisses cards and unregisters the listener
+     * (see {@link #unregisterListeners()}).
+     * Actions are defined when a card is created.
+     *
+     * @param cardActionId
+     * @param cardTag
+     */
+    @Override
+    public void onCardClick(int cardActionId, String cardTag) {
+
+        switch (cardActionId) {
+            // BEGIN_INCLUDE(onclick)
+            // Register Step Counter card
+            case ACTION_REGISTER_COUNT_NOBATCHING:
+                registerEventListener(BATCH_LATENCY_0, Sensor.TYPE_STEP_COUNTER);
+                break;
+            case ACTION_REGISTER_COUNT_BATCHING_5s:
+                registerEventListener(BATCH_LATENCY_5s, Sensor.TYPE_STEP_COUNTER);
+                break;
+            case ACTION_REGISTER_COUNT_BATCHING_10s:
+                registerEventListener(BATCH_LATENCY_10s, Sensor.TYPE_STEP_COUNTER);
+                break;
+
+            // Register Step Detector card
+            case ACTION_REGISTER_DETECT_NOBATCHING:
+                registerEventListener(BATCH_LATENCY_0, Sensor.TYPE_STEP_DETECTOR);
+                break;
+            case ACTION_REGISTER_DETECT_BATCHING_5s:
+                registerEventListener(BATCH_LATENCY_5s, Sensor.TYPE_STEP_DETECTOR);
+                break;
+            case ACTION_REGISTER_DETECT_BATCHING_10s:
+                registerEventListener(BATCH_LATENCY_10s, Sensor.TYPE_STEP_DETECTOR);
+                break;
+
+            // Unregister card
+            case ACTION_UNREGISTER:
+                showRegisterCard();
+                unregisterListeners();
+                // reset the application state when explicitly unregistered
+                mState = STATE_OTHER;
+                break;
+            // END_INCLUDE(onclick)
+            // Explanation cards
+            case ACTION_BATCHING_DESCRIPTION_DISMISS:
+                // permanently remove the batch description card, it will not be shown again
+                getCardStream().removeCard(CARD_BATCHING_DESCRIPTION);
+                break;
+            case ACTION_EXPLANATION_DISMISS:
+                // permanently remove the explanation card, it will not be shown again
+                getCardStream().removeCard(CARD_EXPLANATION);
+        }
+
+        // For register cards, display the counting card
+        if (cardTag.equals(CARD_REGISTER_COUNTER) || cardTag.equals(CARD_REGISTER_DETECTOR)) {
+            showCountingCards();
+        }
+    }
+
+    /**
+     * Register a {@link android.hardware.SensorEventListener} for the sensor and max batch delay.
+     * The maximum batch delay specifies the maximum duration in microseconds for which subsequent
+     * sensor events can be temporarily stored by the sensor before they are delivered to the
+     * registered SensorEventListener. A larger delay allows the system to handle sensor events more
+     * efficiently, allowing the system to switch to a lower power state while the sensor is
+     * capturing events. Once the max delay is reached, all stored events are delivered to the
+     * registered listener. Note that this value only specifies the maximum delay, the listener may
+     * receive events quicker. A delay of 0 disables batch mode and registers the listener in
+     * continuous mode.
+     * The optimium batch delay depends on the application. For example, a delay of 5 seconds or
+     * higher may be appropriate for an  application that does not update the UI in real time.
+     *
+     * @param maxdelay
+     * @param sensorType
+     */
+    private void registerEventListener(int maxdelay, int sensorType) {
+        // BEGIN_INCLUDE(register)
+
+        // Keep track of state so that the correct sensor type and batch delay can be set up when
+        // the app is restored (for example on screen rotation).
+        mMaxDelay = maxdelay;
+        if (sensorType == Sensor.TYPE_STEP_COUNTER) {
+            mState = STATE_COUNTER;
+            /*
+            Reset the initial step counter value, the first event received by the event listener is
+            stored in mCounterSteps and used to calculate the total number of steps taken.
+             */
+            mCounterSteps = 0;
+            Log.i(TAG, "Event listener for step counter sensor registered with a max delay of "
+                    + mMaxDelay);
+        } else {
+            mState = STATE_DETECTOR;
+            Log.i(TAG, "Event listener for step detector sensor registered with a max delay of "
+                    + mMaxDelay);
+        }
+
+        // Get the default sensor for the sensor type from the SenorManager
+        SensorManager sensorManager =
+                (SensorManager) getActivity().getSystemService(Activity.SENSOR_SERVICE);
+        // sensorType is either Sensor.TYPE_STEP_COUNTER or Sensor.TYPE_STEP_DETECTOR
+        Sensor sensor = sensorManager.getDefaultSensor(sensorType);
+
+        // Register the listener for this sensor in batch mode.
+        // If the max delay is 0, events will be delivered in continuous mode without batching.
+        final boolean batchMode = sensorManager.registerListener(
+                mListener, sensor, SensorManager.SENSOR_DELAY_NORMAL, maxdelay);
+
+        if (!batchMode) {
+            // Batch mode could not be enabled, show a warning message and switch to continuous mode
+            getCardStream().getCard(CARD_NOBATCHSUPPORT)
+                    .setDescription(getString(R.string.warning_nobatching));
+            getCardStream().showCard(CARD_NOBATCHSUPPORT);
+            Log.w(TAG, "Could not register sensor listener in batch mode, " +
+                    "falling back to continuous mode.");
+        }
+
+        if (maxdelay > 0 && batchMode) {
+            // Batch mode was enabled successfully, show a description card
+            getCardStream().showCard(CARD_BATCHING_DESCRIPTION);
+        }
+
+        // Show the explanation card
+        getCardStream().showCard(CARD_EXPLANATION);
+
+        // END_INCLUDE(register)
+
+    }
+
+    /**
+     * Unregisters the sensor listener if it is registered.
+     */
+    private void unregisterListeners() {
+        // BEGIN_INCLUDE(unregister)
+        SensorManager sensorManager =
+                (SensorManager) getActivity().getSystemService(Activity.SENSOR_SERVICE);
+        sensorManager.unregisterListener(mListener);
+        Log.i(TAG, "Sensor listener unregistered.");
+
+        // END_INCLUDE(unregister)
+    }
+
+    /**
+     * Resets the step counter by clearing all counting variables and lists.
+     */
+    private void resetCounter() {
+        // BEGIN_INCLUDE(reset)
+        mSteps = 0;
+        mCounterSteps = 0;
+        mEventLength = 0;
+        mEventDelays = new float[EVENT_QUEUE_LENGTH];
+        mPreviousCounterSteps = 0;
+        // END_INCLUDE(reset)
+    }
+
+
+    /**
+     * Listener that handles step sensor events for step detector and step counter sensors.
+     */
+    private final SensorEventListener mListener = new SensorEventListener() {
+        @Override
+        public void onSensorChanged(SensorEvent event) {
+            // BEGIN_INCLUDE(sensorevent)
+            // store the delay of this event
+            recordDelay(event);
+            final String delayString = getDelayString();
+
+            if (event.sensor.getType() == Sensor.TYPE_STEP_DETECTOR) {
+                // A step detector event is received for each step.
+                // This means we need to count steps ourselves
+
+                mSteps += event.values.length;
+
+                // Update the card with the latest step count
+                getCardStream().getCard(CARD_COUNTING)
+                        .setTitle(getString(R.string.counting_title, mSteps))
+                        .setDescription(getString(R.string.counting_description,
+                                getString(R.string.sensor_detector), mMaxDelay, delayString));
+
+                Log.i(TAG,
+                        "New step detected by STEP_DETECTOR sensor. Total step count: " + mSteps);
+
+            } else if (event.sensor.getType() == Sensor.TYPE_STEP_COUNTER) {
+
+                /*
+                A step counter event contains the total number of steps since the listener
+                was first registered. We need to keep track of this initial value to calculate the
+                number of steps taken, as the first value a listener receives is undefined.
+                 */
+                if (mCounterSteps < 1) {
+                    // initial value
+                    mCounterSteps = (int) event.values[0];
+                }
+
+                // Calculate steps taken based on first counter value received.
+                mSteps = (int) event.values[0] - mCounterSteps;
+
+                // Add the number of steps previously taken, otherwise the counter would start at 0.
+                // This is needed to keep the counter consistent across rotation changes.
+                mSteps = mSteps + mPreviousCounterSteps;
+
+                // Update the card with the latest step count
+                getCardStream().getCard(CARD_COUNTING)
+                        .setTitle(getString(R.string.counting_title, mSteps))
+                        .setDescription(getString(R.string.counting_description,
+                                getString(R.string.sensor_counter), mMaxDelay, delayString));
+                Log.i(TAG, "New step detected by STEP_COUNTER sensor. Total step count: " + mSteps);
+                // END_INCLUDE(sensorevent)
+            }
+        }
+
+        @Override
+        public void onAccuracyChanged(Sensor sensor, int accuracy) {
+
+        }
+    };
+
+    /**
+     * Records the delay for the event.
+     *
+     * @param event
+     */
+    private void recordDelay(SensorEvent event) {
+        // Calculate the delay from when event was recorded until it was received here in ms
+        // Event timestamp is recorded in us accuracy, but ms accuracy is sufficient here
+        mEventDelays[mEventData] = System.currentTimeMillis() - (event.timestamp / 1000000L);
+
+        // Increment length counter
+        mEventLength = Math.min(EVENT_QUEUE_LENGTH, mEventLength + 1);
+        // Move pointer to the next (oldest) location
+        mEventData = (mEventData + 1) % EVENT_QUEUE_LENGTH;
+    }
+
+    private final StringBuffer mDelayStringBuffer = new StringBuffer();
+
+    /**
+     * Returns a string describing the sensor delays recorded in
+     * {@link #recordDelay(android.hardware.SensorEvent)}.
+     *
+     * @return
+     */
+    private String getDelayString() {
+        // Empty the StringBuffer
+        mDelayStringBuffer.setLength(0);
+
+        // Loop over all recorded delays and append them to the buffer as a decimal
+        for (int i = 0; i < mEventLength; i++) {
+            if (i > 0) {
+                mDelayStringBuffer.append(", ");
+            }
+            final int index = (mEventData + i) % EVENT_QUEUE_LENGTH;
+            final float delay = mEventDelays[index] / 1000f; // convert delay from ms into s
+            mDelayStringBuffer.append(String.format("%1.1f", delay));
+        }
+
+        return mDelayStringBuffer.toString();
+    }
+
+    /**
+     * Records the state of the application into the {@link android.os.Bundle}.
+     *
+     * @param outState
+     */
+    @Override
+    public void onSaveInstanceState(Bundle outState) {
+        // BEGIN_INCLUDE(saveinstance)
+        super.onSaveInstanceState(outState);
+        // Store all variables required to restore the state of the application
+        outState.putInt(BUNDLE_LATENCY, mMaxDelay);
+        outState.putInt(BUNDLE_STATE, mState);
+        outState.putInt(BUNDLE_STEPS, mSteps);
+        // END_INCLUDE(saveinstance)
+    }
+
+    @Override
+    public void onActivityCreated(Bundle savedInstanceState) {
+        super.onActivityCreated(savedInstanceState);
+        // BEGIN_INCLUDE(restore)
+        // Fragment is being restored, reinitialise its state with data from the bundle
+        if (savedInstanceState != null) {
+            resetCounter();
+            mSteps = savedInstanceState.getInt(BUNDLE_STEPS);
+            mState = savedInstanceState.getInt(BUNDLE_STATE);
+            mMaxDelay = savedInstanceState.getInt(BUNDLE_LATENCY);
+
+            // Register listeners again if in detector or counter states with restored delay
+            if (mState == STATE_DETECTOR) {
+                registerEventListener(mMaxDelay, Sensor.TYPE_STEP_DETECTOR);
+            } else if (mState == STATE_COUNTER) {
+                // store the previous number of steps to keep  step counter count consistent
+                mPreviousCounterSteps = mSteps;
+                registerEventListener(mMaxDelay, Sensor.TYPE_STEP_COUNTER);
+            }
+        }
+        // END_INCLUDE(restore)
+    }
+
+    /**
+     * Hides the registration cards, reset the counter and show the step counting card.
+     */
+    private void showCountingCards() {
+        // Hide the registration cards
+        getCardStream().hideCard(CARD_REGISTER_DETECTOR);
+        getCardStream().hideCard(CARD_REGISTER_COUNTER);
+
+        // Show the explanation card if it has not been dismissed
+        getCardStream().showCard(CARD_EXPLANATION);
+
+        // Reset the step counter, then show the step counting card
+        resetCounter();
+
+        // Set the inital text for the step counting card before a step is recorded
+        String sensor = "-";
+        if (mState == STATE_COUNTER) {
+            sensor = getString(R.string.sensor_counter);
+        } else if (mState == STATE_DETECTOR) {
+            sensor = getString(R.string.sensor_detector);
+        }
+        // Set initial text
+        getCardStream().getCard(CARD_COUNTING)
+                .setTitle(getString(R.string.counting_title, 0))
+                .setDescription(getString(R.string.counting_description, sensor, mMaxDelay, "-"));
+
+        // Show the counting card and make it undismissable
+        getCardStream().showCard(CARD_COUNTING, false);
+
+    }
+
+    /**
+     * Show the introduction card
+     */
+    private void showIntroCard() {
+        Card c = new Card.Builder(this, CARD_INTRO)
+                .setTitle(getString(R.string.intro_title))
+                .setDescription(getString(R.string.intro_message))
+                .build(getActivity());
+        getCardStream().addCard(c, true);
+    }
+
+    /**
+     * Show two registration cards, one for the step detector and counter sensors.
+     */
+    private void showRegisterCard() {
+        // Hide the counting and explanation cards
+        getCardStream().hideCard(CARD_BATCHING_DESCRIPTION);
+        getCardStream().hideCard(CARD_EXPLANATION);
+        getCardStream().hideCard(CARD_COUNTING);
+
+        // Show two undismissable registration cards, one for each step sensor
+        getCardStream().showCard(CARD_REGISTER_DETECTOR, false);
+        getCardStream().showCard(CARD_REGISTER_COUNTER, false);
+    }
+
+    /**
+     * Show the error card.
+     */
+    private void showErrorCard() {
+        getCardStream().showCard(CARD_NOBATCHSUPPORT, false);
+    }
+
+    /**
+     * Initialise Cards.
+     */
+    private void initialiseCards() {
+        // Step counting
+        Card c = new Card.Builder(this, CARD_COUNTING)
+                .setTitle("Steps")
+                .setDescription("")
+                .addAction("Unregister Listener", ACTION_UNREGISTER, Card.ACTION_NEGATIVE)
+                .build(getActivity());
+        getCardStream().addCard(c);
+
+        // Register step detector listener
+        c = new Card.Builder(this, CARD_REGISTER_DETECTOR)
+                .setTitle(getString(R.string.register_detector_title))
+                .setDescription(getString(R.string.register_detector_description))
+                .addAction(getString(R.string.register_0),
+                        ACTION_REGISTER_DETECT_NOBATCHING, Card.ACTION_NEUTRAL)
+                .addAction(getString(R.string.register_5),
+                        ACTION_REGISTER_DETECT_BATCHING_5s, Card.ACTION_NEUTRAL)
+                .addAction(getString(R.string.register_10),
+                        ACTION_REGISTER_DETECT_BATCHING_10s, Card.ACTION_NEUTRAL)
+                .build(getActivity());
+        getCardStream().addCard(c);
+
+        // Register step counter listener
+        c = new Card.Builder(this, CARD_REGISTER_COUNTER)
+                .setTitle(getString(R.string.register_counter_title))
+                .setDescription(getString(R.string.register_counter_description))
+                .addAction(getString(R.string.register_0),
+                        ACTION_REGISTER_COUNT_NOBATCHING, Card.ACTION_NEUTRAL)
+                .addAction(getString(R.string.register_5),
+                        ACTION_REGISTER_COUNT_BATCHING_5s, Card.ACTION_NEUTRAL)
+                .addAction(getString(R.string.register_10),
+                        ACTION_REGISTER_COUNT_BATCHING_10s, Card.ACTION_NEUTRAL)
+                .build(getActivity());
+        getCardStream().addCard(c);
+
+
+        // Batching description
+        c = new Card.Builder(this, CARD_BATCHING_DESCRIPTION)
+                .setTitle(getString(R.string.batching_queue_title))
+                .setDescription(getString(R.string.batching_queue_description))
+                .addAction(getString(R.string.action_notagain),
+                        ACTION_BATCHING_DESCRIPTION_DISMISS, Card.ACTION_POSITIVE)
+                .build(getActivity());
+        getCardStream().addCard(c);
+
+        // Explanation
+        c = new Card.Builder(this, CARD_EXPLANATION)
+                .setDescription(getString(R.string.explanation_description))
+                .addAction(getString(R.string.action_notagain),
+                        ACTION_EXPLANATION_DISMISS, Card.ACTION_POSITIVE)
+                .build(getActivity());
+        getCardStream().addCard(c);
+
+        // Error
+        c = new Card.Builder(this, CARD_NOBATCHSUPPORT)
+                .setTitle(getString(R.string.error_title))
+                .setDescription(getString(R.string.error_nosensor))
+                .build(getActivity());
+        getCardStream().addCard(c);
+    }
+
+    /**
+     * Returns the cached CardStreamFragment used to show cards.
+     *
+     * @return
+     */
+    private CardStreamFragment getCardStream() {
+        if (mCards == null) {
+            mCards = ((CardStream) getActivity()).getCardStream();
+        }
+        return mCards;
+    }
+
+}
diff --git a/samples/browseable/BatchStepSensor/src/com.example.android.batchstepsensor/Card.java b/samples/browseable/BatchStepSensor/src/com.example.android.batchstepsensor/Card.java
new file mode 100644
index 0000000..fb885c7
--- /dev/null
+++ b/samples/browseable/BatchStepSensor/src/com.example.android.batchstepsensor/Card.java
@@ -0,0 +1,750 @@
+/*
+* Copyright 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.batchstepsensor;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
+import android.app.Activity;
+import android.graphics.Color;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.ProgressBar;
+import android.widget.TextView;
+
+import java.util.ArrayList;
+
+/**
+ * A Card contains a description and has a visual state. Optionally a card also contains a title,
+ * progress indicator and zero or more actions. It is constructed through the {@link Builder}.
+ */
+public class Card {
+
+    public static final int ACTION_POSITIVE = 1;
+    public static final int ACTION_NEGATIVE = 2;
+    public static final int ACTION_NEUTRAL = 3;
+
+    public static final int PROGRESS_TYPE_NO_PROGRESS = 0;
+    public static final int PROGRESS_TYPE_NORMAL = 1;
+    public static final int PROGRESS_TYPE_INDETERMINATE = 2;
+    public static final int PROGRESS_TYPE_LABEL = 3;
+
+    private OnCardClickListener mClickListener;
+
+
+    // The card model contains a reference to its desired layout (for extensibility), title,
+    // description, zero to many action buttons, and zero or 1 progress indicators.
+    private int mLayoutId = R.layout.card;
+
+    /**
+     * Tag that uniquely identifies this card.
+     */
+    private String mTag = null;
+
+    private String mTitle = null;
+    private String mDescription = null;
+
+    private View mCardView = null;
+    private View mOverlayView = null;
+    private TextView mTitleView = null;
+    private TextView mDescView = null;
+    private View mActionAreaView = null;
+
+    private Animator mOngoingAnimator = null;
+
+    /**
+     * Visual state, either {@link #CARD_STATE_NORMAL}, {@link #CARD_STATE_FOCUSED} or
+     * {@link #CARD_STATE_INACTIVE}.
+     */
+    private int mCardState = CARD_STATE_NORMAL;
+    public static final int CARD_STATE_NORMAL = 1;
+    public static final int CARD_STATE_FOCUSED = 2;
+    public static final int CARD_STATE_INACTIVE = 3;
+
+    /**
+     * Represent actions that can be taken from the card.  Stylistically the developer can
+     * designate the action as positive, negative (ok/cancel, for instance), or neutral.
+     * This "type" can be used as a UI hint.
+     * @see com.example.android.sensors.batchstepsensor.Card.CardAction
+     */
+    private ArrayList<CardAction> mCardActions = new ArrayList<CardAction>();
+
+    /**
+     * Some cards will have a sense of "progress" which should be associated with, but separated
+     * from its "parent" card.  To push for simplicity in samples, Cards are designed to have
+     * a maximum of one progress indicator per Card.
+     */
+    private CardProgress mCardProgress = null;
+
+    public Card() {
+    }
+
+    public String getTag() {
+        return mTag;
+    }
+
+    public View getView() {
+        return mCardView;
+    }
+
+
+    public Card setDescription(String desc) {
+        if (mDescView != null) {
+            mDescription = desc;
+            mDescView.setText(desc);
+        }
+        return this;
+    }
+
+    public Card setTitle(String title) {
+        if (mTitleView != null) {
+            mTitle = title;
+            mTitleView.setText(title);
+        }
+        return this;
+    }
+
+
+    /**
+     * Return the UI state, either {@link #CARD_STATE_NORMAL}, {@link #CARD_STATE_FOCUSED}
+     * or {@link #CARD_STATE_INACTIVE}.
+     */
+    public int getState() {
+        return mCardState;
+    }
+
+    /**
+     * Set the UI state. The parameter describes the state and must be either
+     * {@link #CARD_STATE_NORMAL}, {@link #CARD_STATE_FOCUSED} or {@link #CARD_STATE_INACTIVE}.
+     * Note: This method must be called from the UI Thread.
+     * @param state
+     * @return The card itself, allows for chaining of calls
+     */
+    public Card setState(int state) {
+        mCardState = state;
+        if (null != mOverlayView) {
+            if (null != mOngoingAnimator) {
+                mOngoingAnimator.end();
+                mOngoingAnimator = null;
+            }
+            switch (state) {
+                case CARD_STATE_NORMAL: {
+                    mOverlayView.setVisibility(View.GONE);
+                    mOverlayView.setAlpha(1.f);
+                    break;
+                }
+                case CARD_STATE_FOCUSED: {
+                    mOverlayView.setVisibility(View.VISIBLE);
+                    mOverlayView.setBackgroundResource(R.drawable.card_overlay_focused);
+                    ObjectAnimator animator = ObjectAnimator.ofFloat(mOverlayView, "alpha", 0.f);
+                    animator.setRepeatMode(ObjectAnimator.REVERSE);
+                    animator.setRepeatCount(ObjectAnimator.INFINITE);
+                    animator.setDuration(1000);
+                    animator.start();
+                    mOngoingAnimator = animator;
+                    break;
+                }
+                case CARD_STATE_INACTIVE: {
+                    mOverlayView.setVisibility(View.VISIBLE);
+                    mOverlayView.setAlpha(1.f);
+                    mOverlayView.setBackgroundColor(Color.argb(0xaa, 0xcc, 0xcc, 0xcc));
+                    break;
+                }
+            }
+        }
+        return this;
+    }
+
+    /**
+     * Set the type of progress indicator.
+     * The progress type can only be changed if the Card was initially build with a progress
+     * indicator.
+     * See {@link Builder#setProgressType(int)}.
+     * Must be a value of either {@link #PROGRESS_TYPE_NORMAL},
+     * {@link #PROGRESS_TYPE_INDETERMINATE}, {@link #PROGRESS_TYPE_LABEL} or
+     * {@link #PROGRESS_TYPE_NO_PROGRESS}.
+     * @param progressType
+     * @return The card itself, allows for chaining of calls
+     */
+    public Card setProgressType(int progressType) {
+        if (mCardProgress == null) {
+            mCardProgress = new CardProgress();
+        }
+        mCardProgress.setProgressType(progressType);
+        return this;
+    }
+
+    /**
+     * Return the progress indicator type. A value of either {@link #PROGRESS_TYPE_NORMAL},
+     * {@link #PROGRESS_TYPE_INDETERMINATE}, {@link #PROGRESS_TYPE_LABEL}. Otherwise if no progress
+     * indicator is enabled, {@link #PROGRESS_TYPE_NO_PROGRESS} is returned.
+     * @return
+     */
+    public int getProgressType() {
+        if (mCardProgress == null) {
+            return PROGRESS_TYPE_NO_PROGRESS;
+        }
+        return mCardProgress.progressType;
+    }
+
+    /**
+     * Set the progress to the specified value. Only applicable if the card has a
+     * {@link #PROGRESS_TYPE_NORMAL} progress type.
+     * @param progress
+     * @return
+     * @see #setMaxProgress(int)
+     */
+    public Card setProgress(int progress) {
+        if (mCardProgress != null) {
+            mCardProgress.setProgress(progress);
+        }
+        return this;
+    }
+
+    /**
+     * Set the range of the progress to 0...max. Only applicable if the card has a
+     * {@link #PROGRESS_TYPE_NORMAL} progress type.
+     * @return
+     */
+    public Card setMaxProgress(int max){
+        if (mCardProgress != null) {
+            mCardProgress.setMax(max);
+        }
+        return this;
+    }
+
+    /**
+     * Set the label text for the progress if the card has a progress type of
+     * {@link #PROGRESS_TYPE_NORMAL}, {@link #PROGRESS_TYPE_INDETERMINATE} or
+     * {@link #PROGRESS_TYPE_LABEL}
+     * @param text
+     * @return
+     */
+    public Card setProgressLabel(String text) {
+        if (mCardProgress != null) {
+            mCardProgress.setProgressLabel(text);
+        }
+        return this;
+    }
+
+    /**
+     * Toggle the visibility of the progress section of the card. Only applicable if
+     * the card has a progress type of
+     * {@link #PROGRESS_TYPE_NORMAL}, {@link #PROGRESS_TYPE_INDETERMINATE} or
+     * {@link #PROGRESS_TYPE_LABEL}.
+     * @param isVisible
+     * @return
+     */
+    public Card setProgressVisibility(boolean isVisible) {
+        if (mCardProgress.progressView == null) {
+            return this; // Card does not have progress
+        }
+        mCardProgress.progressView.setVisibility(isVisible ? View.VISIBLE : View.GONE);
+
+        return this;
+    }
+
+    /**
+     * Adds an action to this card during build time.
+     *
+     * @param label
+     * @param id
+     * @param type
+     */
+    private void addAction(String label, int id, int type) {
+        CardAction cardAction = new CardAction();
+        cardAction.label = label;
+        cardAction.id = id;
+        cardAction.type = type;
+        mCardActions.add(cardAction);
+    }
+
+    /**
+     * Toggles the visibility of a card action.
+     * @param actionId
+     * @param isVisible
+     * @return
+     */
+    public Card setActionVisibility(int actionId, boolean isVisible) {
+        int visibilityFlag = isVisible ? View.VISIBLE : View.GONE;
+        for (CardAction action : mCardActions) {
+            if (action.id == actionId && action.actionView != null) {
+                action.actionView.setVisibility(visibilityFlag);
+            }
+        }
+        return this;
+    }
+
+    /**
+     * Toggles visibility of the action area of this Card through an animation.
+     * @param isVisible
+     * @return
+     */
+    public Card setActionAreaVisibility(boolean isVisible) {
+        if (mActionAreaView == null) {
+            return this; // Card does not have an action area
+        }
+
+        if (isVisible) {
+            // Show the action area
+            mActionAreaView.setVisibility(View.VISIBLE);
+            mActionAreaView.setPivotY(0.f);
+            mActionAreaView.setPivotX(mCardView.getWidth() / 2.f);
+            mActionAreaView.setAlpha(0.5f);
+            mActionAreaView.setRotationX(-90.f);
+            mActionAreaView.animate().rotationX(0.f).alpha(1.f).setDuration(400);
+        } else {
+            // Hide the action area
+            mActionAreaView.setPivotY(0.f);
+            mActionAreaView.setPivotX(mCardView.getWidth() / 2.f);
+            mActionAreaView.animate().rotationX(-90.f).alpha(0.f).setDuration(400).setListener(
+                    new AnimatorListenerAdapter() {
+                        @Override
+                        public void onAnimationEnd(Animator animation) {
+                            mActionAreaView.setVisibility(View.GONE);
+                        }
+                    });
+        }
+        return this;
+    }
+
+
+    /**
+     * Creates a shallow clone of the card.  Shallow means all values are present, but no views.
+     * This is useful for saving/restoring in the case of configuration changes, like screen
+     * rotation.
+     *
+     * @return A shallow clone of the card instance
+     */
+    public Card createShallowClone() {
+        Card cloneCard = new Card();
+
+        // Outer card values
+        cloneCard.mTitle = mTitle;
+        cloneCard.mDescription = mDescription;
+        cloneCard.mTag = mTag;
+        cloneCard.mLayoutId = mLayoutId;
+        cloneCard.mCardState = mCardState;
+
+        // Progress
+        if (mCardProgress != null) {
+            cloneCard.mCardProgress = mCardProgress.createShallowClone();
+        }
+
+        // Actions
+        for (CardAction action : mCardActions) {
+            cloneCard.mCardActions.add(action.createShallowClone());
+        }
+
+        return cloneCard;
+    }
+
+
+    /**
+     * Prepare the card to be stored for configuration change.
+     */
+    public void prepareForConfigurationChange() {
+        // Null out views.
+        mCardView = null;
+        for (CardAction action : mCardActions) {
+            action.actionView = null;
+        }
+        mCardProgress.progressView = null;
+    }
+
+    /**
+     * Creates a new {@link #Card}.
+     */
+    public static class Builder {
+        private Card mCard;
+
+        /**
+         * Instantiate the builder with data from a shallow clone.
+         * @param listener
+         * @param card
+         * @see Card#createShallowClone()
+         */
+        protected Builder(OnCardClickListener listener, Card card) {
+            mCard = card;
+            mCard.mClickListener = listener;
+        }
+
+        /**
+         * Instantiate the builder with the tag of the card.
+         * @param listener
+         * @param tag
+         */
+        public Builder(OnCardClickListener listener, String tag) {
+            mCard = new Card();
+            mCard.mTag = tag;
+            mCard.mClickListener = listener;
+        }
+
+        public Builder setTitle(String title) {
+            mCard.mTitle = title;
+            return this;
+        }
+
+        public Builder setDescription(String desc) {
+            mCard.mDescription = desc;
+            return this;
+        }
+
+        /**
+         * Add an action.
+         * The type describes how this action will be displayed. Accepted values are
+         * {@link #ACTION_NEUTRAL}, {@link #ACTION_POSITIVE} or {@link #ACTION_NEGATIVE}.
+         *
+         * @param label The text to display for this action
+         * @param id Identifier for this action, supplied in the click listener
+         * @param type UI style of action
+         * @return
+         */
+        public Builder addAction(String label, int id, int type) {
+            mCard.addAction(label, id, type);
+            return this;
+        }
+
+        /**
+         * Override the default layout.
+         * The referenced layout file has to contain the same identifiers as defined in the default
+         * layout configuration.
+         * @param layout
+         * @return
+         * @see R.layout.card
+         */
+        public Builder setLayout(int layout) {
+            mCard.mLayoutId = layout;
+            return this;
+        }
+
+        /**
+         * Set the type of progress bar to display.
+         * Accepted values are:
+         * <ul>
+         *     <li>{@link #PROGRESS_TYPE_NO_PROGRESS} disables the progress indicator</li>
+         *     <li>{@link #PROGRESS_TYPE_NORMAL} 
+         *     displays a standard, linear progress indicator.</li>
+         *     <li>{@link #PROGRESS_TYPE_INDETERMINATE} displays an indeterminate (infite) progress
+         *     indicator.</li>
+         *     <li>{@link #PROGRESS_TYPE_LABEL} only displays a label text in the progress area
+         *     of the card.</li>
+         * </ul>
+         *
+         * @param progressType
+         * @return
+         */
+        public Builder setProgressType(int progressType) {
+            mCard.setProgressType(progressType);
+            return this;
+        }
+
+        public Builder setProgressLabel(String label) {
+            // ensure the progress layout has been initialized, use 'no progress' by default
+            if (mCard.mCardProgress == null) {
+                mCard.setProgressType(PROGRESS_TYPE_NO_PROGRESS);
+            }
+            mCard.mCardProgress.label = label;
+            return this;
+        }
+
+        public Builder setProgressMaxValue(int maxValue) {
+            // ensure the progress layout has been initialized, use 'no progress' by default
+            if (mCard.mCardProgress == null) {
+                mCard.setProgressType(PROGRESS_TYPE_NO_PROGRESS);
+            }
+            mCard.mCardProgress.maxValue = maxValue;
+            return this;
+        }
+
+        public Builder setStatus(int status) {
+            mCard.setState(status);
+            return this;
+        }
+
+        public Card build(Activity activity) {
+            LayoutInflater inflater = activity.getLayoutInflater();
+            // Inflating the card.
+            ViewGroup cardView = (ViewGroup) inflater.inflate(mCard.mLayoutId,
+                    (ViewGroup) activity.findViewById(R.id.card_stream), false);
+
+            // Check that the layout contains a TextView with the card_title id
+            View viewTitle = cardView.findViewById(R.id.card_title);
+            if (mCard.mTitle != null && viewTitle != null) {
+                mCard.mTitleView = (TextView) viewTitle;
+                mCard.mTitleView.setText(mCard.mTitle);
+            } else if (viewTitle != null) {
+                viewTitle.setVisibility(View.GONE);
+            }
+
+            // Check that the layout contains a TextView with the card_content id
+            View viewDesc = cardView.findViewById(R.id.card_content);
+            if (mCard.mDescription != null && viewDesc != null) {
+                mCard.mDescView = (TextView) viewDesc;
+                mCard.mDescView.setText(mCard.mDescription);
+            } else if (viewDesc != null) {
+                cardView.findViewById(R.id.card_content).setVisibility(View.GONE);
+            }
+
+
+            ViewGroup actionArea = (ViewGroup) cardView.findViewById(R.id.card_actionarea);
+
+            // Inflate Progress
+            initializeProgressView(inflater, actionArea);
+
+            // Inflate all action views.
+            initializeActionViews(inflater, cardView, actionArea);
+
+            mCard.mCardView = cardView;
+            mCard.mOverlayView = cardView.findViewById(R.id.card_overlay);
+
+            return mCard;
+        }
+
+        /**
+         * Initialize data from the given card.
+         * @param card
+         * @return
+         * @see Card#createShallowClone()
+         */
+        public Builder cloneFromCard(Card card) {
+            mCard = card.createShallowClone();
+            return this;
+        }
+
+        /**
+         * Build the action views by inflating the appropriate layouts and setting the text and 
+         * values.
+         * @param inflater
+         * @param cardView
+         * @param actionArea
+         */
+        private void initializeActionViews(LayoutInflater inflater, ViewGroup cardView,
+                                           ViewGroup actionArea) {
+            if (!mCard.mCardActions.isEmpty()) {
+                // Set action area to visible only when actions are visible
+                actionArea.setVisibility(View.VISIBLE);
+                mCard.mActionAreaView = actionArea;
+            }
+
+            // Inflate all card actions
+            for (final CardAction action : mCard.mCardActions) {
+
+                int useActionLayout = 0;
+                switch (action.type) {
+                    case Card.ACTION_POSITIVE:
+                        useActionLayout = R.layout.card_button_positive;
+                        break;
+                    case Card.ACTION_NEGATIVE:
+                        useActionLayout = R.layout.card_button_negative;
+                        break;
+                    case Card.ACTION_NEUTRAL:
+                    default:
+                        useActionLayout = R.layout.card_button_neutral;
+                        break;
+                }
+
+                action.actionView = inflater.inflate(useActionLayout, actionArea, false);
+                Button actionButton = (Button) action.actionView.findViewById(R.id.card_button);
+
+                actionButton.setText(action.label);
+                actionButton.setOnClickListener(new View.OnClickListener() {
+                    @Override
+                    public void onClick(View v) {
+                        mCard.mClickListener.onCardClick(action.id, mCard.mTag);
+                    }
+                });
+                actionArea.addView(action.actionView);
+            }
+        }
+
+        /**
+         * Build the progress view into the given ViewGroup.
+         *
+         * @param inflater
+         * @param actionArea
+         */
+        private void initializeProgressView(LayoutInflater inflater, ViewGroup actionArea) {
+
+            // Only inflate progress layout if a progress type other than NO_PROGRESS was set.
+            if (mCard.mCardProgress != null) {
+                //Setup progress card.
+                View progressView = inflater.inflate(R.layout.card_progress, actionArea, false);
+                ProgressBar progressBar = 
+                        (ProgressBar) progressView.findViewById(R.id.card_progress);
+                ((TextView) progressView.findViewById(R.id.card_progress_text))
+                        .setText(mCard.mCardProgress.label);
+                progressBar.setMax(mCard.mCardProgress.maxValue);
+                progressBar.setProgress(0);
+                mCard.mCardProgress.progressView = progressView;
+                mCard.mCardProgress.setProgressType(mCard.getProgressType());
+                actionArea.addView(progressView);
+            }
+        }
+    }
+
+    /**
+     * Represents a clickable action, accessible from the bottom of the card.
+     * Fields include the label, an ID to specify the action that was performed in the callback,
+     * an action type (positive, negative, neutral), and the callback.
+     */
+    public class CardAction {
+
+        public String label;
+        public int id;
+        public int type;
+        public View actionView;
+
+        public CardAction createShallowClone() {
+            CardAction actionClone = new CardAction();
+            actionClone.label = label;
+            actionClone.id = id;
+            actionClone.type = type;
+            return actionClone;
+            // Not the view.  Never the view (don't want to hold view references for
+            // onConfigurationChange.
+        }
+
+    }
+
+    /**
+     * Describes the progress of a {@link Card}.
+     * Three types of progress are supported:
+     * <ul><li>{@link Card#PROGRESS_TYPE_NORMAL: Standard progress bar with label text</li>
+     * <li>{@link Card#PROGRESS_TYPE_INDETERMINATE}: Indeterminate progress bar with label txt</li>
+     * <li>{@link Card#PROGRESS_TYPE_LABEL}: Label only, no progresss bar</li>
+     * </ul>
+     */
+    public class CardProgress {
+        private int progressType = Card.PROGRESS_TYPE_NO_PROGRESS;
+        private String label = "";
+        private int currProgress = 0;
+        private int maxValue = 100;
+
+        public View progressView = null;
+        private ProgressBar progressBar = null;
+        private TextView progressLabel = null;
+
+        public CardProgress createShallowClone() {
+            CardProgress progressClone = new CardProgress();
+            progressClone.label = label;
+            progressClone.currProgress = currProgress;
+            progressClone.maxValue = maxValue;
+            progressClone.progressType = progressType;
+            return progressClone;
+        }
+
+        /**
+         * Set the progress. Only useful for the type {@link #PROGRESS_TYPE_NORMAL}.
+         * @param progress
+         * @see android.widget.ProgressBar#setProgress(int)
+         */
+        public void setProgress(int progress) {
+            currProgress = progress;
+            final ProgressBar bar = getProgressBar();
+            if (bar != null) {
+                bar.setProgress(currProgress);
+                bar.invalidate();
+            }
+        }
+
+        /**
+         * Set the range of the progress to 0...max.
+         * Only useful for the type {@link #PROGRESS_TYPE_NORMAL}.
+         * @param max
+         * @see android.widget.ProgressBar#setMax(int)
+         */
+        public void setMax(int max) {
+            maxValue = max;
+            final ProgressBar bar = getProgressBar();
+            if (bar != null) {
+                bar.setMax(maxValue);
+            }
+        }
+
+        /**
+         * Set the label text that appears near the progress indicator.
+         * @param text
+         */
+        public void setProgressLabel(String text) {
+            label = text;
+            final TextView labelView = getProgressLabel();
+            if (labelView != null) {
+                labelView.setText(text);
+            }
+        }
+
+        /**
+         * Set how progress is displayed. The parameter must be one of three supported types:
+         * <ul><li>{@link Card#PROGRESS_TYPE_NORMAL: Standard progress bar with label text</li>
+         * <li>{@link Card#PROGRESS_TYPE_INDETERMINATE}: 
+         * Indeterminate progress bar with label txt</li>
+         * <li>{@link Card#PROGRESS_TYPE_LABEL}: Label only, no progresss bar</li>
+         * @param type
+         */
+        public void setProgressType(int type) {
+            progressType = type;
+            if (progressView != null) {
+                switch (type) {
+                    case PROGRESS_TYPE_NO_PROGRESS: {
+                        progressView.setVisibility(View.GONE);
+                        break;
+                    }
+                    case PROGRESS_TYPE_NORMAL: {
+                        progressView.setVisibility(View.VISIBLE);
+                        getProgressBar().setIndeterminate(false);
+                        break;
+                    }
+                    case PROGRESS_TYPE_INDETERMINATE: {
+                        progressView.setVisibility(View.VISIBLE);
+                        getProgressBar().setIndeterminate(true);
+                        break;
+                    }
+                }
+            }
+        }
+
+        private TextView getProgressLabel() {
+            if (progressLabel != null) {
+                return progressLabel;
+            } else if (progressView != null) {
+                progressLabel = (TextView) progressView.findViewById(R.id.card_progress_text);
+                return progressLabel;
+            } else {
+                return null;
+            }
+        }
+
+        private ProgressBar getProgressBar() {
+            if (progressBar != null) {
+                return progressBar;
+            } else if (progressView != null) {
+                progressBar = (ProgressBar) progressView.findViewById(R.id.card_progress);
+                return progressBar;
+            } else {
+                return null;
+            }
+        }
+
+    }
+}
+
diff --git a/samples/browseable/BatchStepSensor/src/com.example.android.batchstepsensor/CardActionButton.java b/samples/browseable/BatchStepSensor/src/com.example.android.batchstepsensor/CardActionButton.java
new file mode 100644
index 0000000..ea37e66
--- /dev/null
+++ b/samples/browseable/BatchStepSensor/src/com.example.android.batchstepsensor/CardActionButton.java
@@ -0,0 +1,69 @@
+/*
+* Copyright 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.batchstepsensor;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.animation.BounceInterpolator;
+import android.view.animation.DecelerateInterpolator;
+import android.widget.Button;
+
+/**
+ * Custom Button with a special 'pressed' effect for touch events.
+ */
+public class CardActionButton extends Button {
+
+    public CardActionButton(Context context) {
+        super(context);
+    }
+
+    public CardActionButton(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public CardActionButton(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+    }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent event) {
+
+        switch(event.getAction()){
+            case MotionEvent.ACTION_DOWN:
+                setPressed(true);
+                animate().scaleX(0.98f).scaleY(0.98f).alpha(0.8f).setDuration(100).
+                        setInterpolator(new DecelerateInterpolator());
+                break;
+            case MotionEvent.ACTION_UP:
+                animate().scaleX(1.0f).scaleY(1.f).alpha(1.0f).setDuration(50).
+                        setInterpolator(new BounceInterpolator());
+                break;
+            case MotionEvent.ACTION_CANCEL:
+                animate().scaleX(1.0f).scaleY(1.f).alpha(1.0f).setDuration(50).
+                        setInterpolator(new BounceInterpolator());
+                break;
+        }
+
+        return super.onTouchEvent(event);
+    }
+
+}
+
diff --git a/samples/browseable/BatchStepSensor/src/com.example.android.batchstepsensor/CardLayout.java b/samples/browseable/BatchStepSensor/src/com.example.android.batchstepsensor/CardLayout.java
new file mode 100644
index 0000000..8215275
--- /dev/null
+++ b/samples/browseable/BatchStepSensor/src/com.example.android.batchstepsensor/CardLayout.java
@@ -0,0 +1,94 @@
+/*
+* Copyright 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.batchstepsensor;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.ViewConfiguration;
+import android.widget.RelativeLayout;
+
+/**
+ * Custom Button with a special 'pressed' effect for touch events.
+ */
+public class CardLayout extends RelativeLayout {
+
+    private boolean mSwiping = false;
+    private float mDownX = 0.f;
+    private float mDownY = 0.f;
+    private float mTouchSlop = 0.f;
+
+    public CardLayout(Context context) {
+        super(context);
+        init();
+    }
+
+    public CardLayout(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        init();
+    }
+
+    public CardLayout(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+        init();
+    }
+
+    private void init(){
+        setFocusable(true);
+        setDescendantFocusability(FOCUS_AFTER_DESCENDANTS);
+        setWillNotDraw(false);
+        setClickable(true);
+
+        mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop() * 2.f;
+    }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent event) {
+        switch(event.getAction()){
+            case MotionEvent.ACTION_CANCEL:
+            case MotionEvent.ACTION_UP:
+                mSwiping = false;
+                break;
+        }
+        return super.onTouchEvent(event);
+    }
+
+    @Override
+    public boolean onInterceptTouchEvent(MotionEvent event) {
+
+        switch(event.getAction()){
+            case MotionEvent.ACTION_MOVE:
+                if( !mSwiping ){
+                    mSwiping = Math.abs(mDownX - event.getX()) > mTouchSlop;
+                }
+                break;
+            case MotionEvent.ACTION_DOWN:
+                mDownX = event.getX();
+                mDownY = event.getY();
+                mSwiping = false;
+                break;
+            case MotionEvent.ACTION_CANCEL:
+            case MotionEvent.ACTION_UP:
+                mSwiping = false;
+                break;
+        }
+        return mSwiping;
+    }
+}
\ No newline at end of file
diff --git a/samples/browseable/BatchStepSensor/src/com.example.android.batchstepsensor/CardStream.java b/samples/browseable/BatchStepSensor/src/com.example.android.batchstepsensor/CardStream.java
new file mode 100644
index 0000000..5de9852
--- /dev/null
+++ b/samples/browseable/BatchStepSensor/src/com.example.android.batchstepsensor/CardStream.java
@@ -0,0 +1,25 @@
+/*
+* Copyright 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.batchstepsensor;
+
+public interface CardStream {
+    public CardStreamFragment getCardStream();
+}
+
diff --git a/samples/browseable/BatchStepSensor/src/com.example.android.batchstepsensor/CardStreamAnimator.java b/samples/browseable/BatchStepSensor/src/com.example.android.batchstepsensor/CardStreamAnimator.java
new file mode 100644
index 0000000..a22ddd7
--- /dev/null
+++ b/samples/browseable/BatchStepSensor/src/com.example.android.batchstepsensor/CardStreamAnimator.java
@@ -0,0 +1,120 @@
+/*
+* Copyright 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.batchstepsensor;
+
+import android.animation.ObjectAnimator;
+import android.content.Context;
+import android.view.View;
+
+/**
+ * An abstract class which defines animators for CardStreamLinearLayout.
+ */
+abstract class CardStreamAnimator {
+
+    protected float mSpeedFactor = 1.f;
+
+    /**
+     * Set speed factor of animations. Higher value means longer duration & slow animation.
+     *
+     * @param speedFactor speed type 1: SLOW, 2: NORMAL, 3:FAST
+     */
+    public void setSpeedFactor(float speedFactor) {
+        mSpeedFactor = speedFactor;
+    }
+
+    /**
+     * Define initial animation of each child which fired when a user rotate a screen.
+     *
+     * @param context
+     * @return ObjectAnimator for initial animation
+     */
+    public abstract ObjectAnimator getInitalAnimator(Context context);
+
+    /**
+     * Define disappearing animation of a child which fired when a view is removed programmatically
+     *
+     * @param context
+     * @return ObjectAnimator for disappearing animation
+     */
+    public abstract ObjectAnimator getDisappearingAnimator(Context context);
+
+    /**
+     * Define appearing animation of a child which fired when a view is added programmatically
+     *
+     * @param context
+     * @return ObjectAnimator for appearing animation
+     */
+    public abstract ObjectAnimator getAppearingAnimator(Context context);
+
+    /**
+     * Define swipe-in (back to the origin position) animation of a child
+     * which fired when a view is not moved enough to be removed.
+     *
+     * @param view   target view
+     * @param deltaX delta distance by x-axis
+     * @param deltaY delta distance by y-axis
+     * @return ObjectAnimator for swipe-in animation
+     */
+    public abstract ObjectAnimator getSwipeInAnimator(View view, float deltaX, float deltaY);
+
+    /**
+     * Define swipe-out animation of a child
+     * which fired when a view is removing by a user swipe action.
+     *
+     * @param view   target view
+     * @param deltaX delta distance by x-axis
+     * @param deltaY delta distance by y-axis
+     * @return ObjectAnimator for swipe-out animation
+     */
+    public abstract ObjectAnimator getSwipeOutAnimator(View view, float deltaX, float deltaY);
+
+    /**
+     * A simple CardStreamAnimator implementation which is used to turn animations off.
+     */
+    public static class EmptyAnimator extends CardStreamAnimator {
+
+        @Override
+        public ObjectAnimator getInitalAnimator(Context context) {
+            return null;
+        }
+
+        @Override
+        public ObjectAnimator getDisappearingAnimator(Context context) {
+            return null;
+        }
+
+        @Override
+        public ObjectAnimator getAppearingAnimator(Context context) {
+            return null;
+        }
+
+        @Override
+        public ObjectAnimator getSwipeInAnimator(View view, float deltaX, float deltaY) {
+            return null;
+        }
+
+        @Override
+        public ObjectAnimator getSwipeOutAnimator(View view, float deltaX, float deltaY) {
+            return null;
+        }
+    }
+
+}
+
diff --git a/samples/browseable/BatchStepSensor/src/com.example.android.batchstepsensor/CardStreamFragment.java b/samples/browseable/BatchStepSensor/src/com.example.android.batchstepsensor/CardStreamFragment.java
new file mode 100644
index 0000000..9f8b7cb
--- /dev/null
+++ b/samples/browseable/BatchStepSensor/src/com.example.android.batchstepsensor/CardStreamFragment.java
@@ -0,0 +1,275 @@
+/*
+* Copyright 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.batchstepsensor;
+
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+
+
+/**
+ * A Fragment that handles a stream of cards.
+ * Cards can be shown or hidden. When a card is shown it can also be marked as not-dismissible, see
+ * {@link CardStreamLinearLayout#addCard(android.view.View, boolean)}.
+ */
+public class CardStreamFragment extends Fragment {
+
+    private static final int INITIAL_SIZE = 15;
+    private CardStreamLinearLayout mLayout = null;
+    private LinkedHashMap<String, Card> mVisibleCards = new LinkedHashMap<String, Card>(INITIAL_SIZE);
+    private HashMap<String, Card> mHiddenCards = new HashMap<String, Card>(INITIAL_SIZE);
+    private HashSet<String> mDismissibleCards = new HashSet<String>(INITIAL_SIZE);
+
+    // Set the listener to handle dismissed cards by moving them to the hidden cards map.
+    private CardStreamLinearLayout.OnDissmissListener mCardDismissListener =
+            new CardStreamLinearLayout.OnDissmissListener() {
+                @Override
+                public void onDismiss(String tag) {
+                    dismissCard(tag);
+                }
+            };
+
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+                             Bundle savedInstanceState) {
+
+        View view = inflater.inflate(R.layout.cardstream, container, false);
+        mLayout = (CardStreamLinearLayout) view.findViewById(R.id.card_stream);
+        mLayout.setOnDismissListener(mCardDismissListener);
+
+        return view;
+    }
+
+    /**
+     * Add a visible, dismissible card to the card stream.
+     *
+     * @param card
+     */
+    public void addCard(Card card) {
+        final String tag = card.getTag();
+
+        if (!mVisibleCards.containsKey(tag) && !mHiddenCards.containsKey(tag)) {
+            final View view = card.getView();
+            view.setTag(tag);
+            mHiddenCards.put(tag, card);
+        }
+    }
+
+    /**
+     * Add and show a card.
+     *
+     * @param card
+     * @param show
+     */
+    public void addCard(Card card, boolean show) {
+        addCard(card);
+        if (show) {
+            showCard(card.getTag());
+        }
+    }
+
+    /**
+     * Remove a card and return true if it has been successfully removed.
+     *
+     * @param tag
+     * @return
+     */
+    public boolean removeCard(String tag) {
+        // Attempt to remove a visible card first
+        Card card = mVisibleCards.get(tag);
+        if (card != null) {
+            // Card is visible, also remove from layout
+            mVisibleCards.remove(tag);
+            mLayout.removeView(card.getView());
+            return true;
+        } else {
+            // Card is hidden, no need to remove from layout
+            card = mHiddenCards.remove(tag);
+            return card != null;
+        }
+    }
+
+    /**
+     * Show a dismissible card, returns false if the card could not be shown.
+     *
+     * @param tag
+     * @return
+     */
+    public boolean showCard(String tag) {
+        return showCard(tag, true);
+    }
+
+    /**
+     * Show a card, returns false if the card could not be shown.
+     *
+     * @param tag
+     * @param dismissible
+     * @return
+     */
+    public boolean showCard(String tag, boolean dismissible) {
+        final Card card = mHiddenCards.get(tag);
+        // ensure the card is hidden and not already visible
+        if (card != null && !mVisibleCards.containsValue(tag)) {
+            mHiddenCards.remove(tag);
+            mVisibleCards.put(tag, card);
+            mLayout.addCard(card.getView(), dismissible);
+            if (dismissible) {
+                mDismissibleCards.add(tag);
+            }
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Hides the card, returns false if the card could not be hidden.
+     *
+     * @param tag
+     * @return
+     */
+    public boolean hideCard(String tag) {
+        final Card card = mVisibleCards.get(tag);
+        if (card != null) {
+            mVisibleCards.remove(tag);
+            mDismissibleCards.remove(tag);
+            mHiddenCards.put(tag, card);
+
+            mLayout.removeView(card.getView());
+            return true;
+        }
+        return mHiddenCards.containsValue(tag);
+    }
+
+
+    private void dismissCard(String tag) {
+        final Card card = mVisibleCards.get(tag);
+        if (card != null) {
+            mDismissibleCards.remove(tag);
+            mVisibleCards.remove(tag);
+            mHiddenCards.put(tag, card);
+        }
+    }
+
+
+    public boolean isCardVisible(String tag) {
+        return mVisibleCards.containsValue(tag);
+    }
+
+    /**
+     * Returns true if the card is shown and is dismissible.
+     *
+     * @param tag
+     * @return
+     */
+    public boolean isCardDismissible(String tag) {
+        return mDismissibleCards.contains(tag);
+    }
+
+    /**
+     * Returns the Card for this tag.
+     *
+     * @param tag
+     * @return
+     */
+    public Card getCard(String tag) {
+        final Card card = mVisibleCards.get(tag);
+        if (card != null) {
+            return card;
+        } else {
+            return mHiddenCards.get(tag);
+        }
+    }
+
+    /**
+     * Moves the view port to show the card with this tag.
+     *
+     * @param tag
+     * @see CardStreamLinearLayout#setFirstVisibleCard(String)
+     */
+    public void setFirstVisibleCard(String tag) {
+        final Card card = mVisibleCards.get(tag);
+        if (card != null) {
+            mLayout.setFirstVisibleCard(tag);
+        }
+    }
+
+    public int getVisibleCardCount() {
+        return mVisibleCards.size();
+    }
+
+    public Collection<Card> getVisibleCards() {
+        return mVisibleCards.values();
+    }
+
+    public void restoreState(CardStreamState state, OnCardClickListener callback) {
+        // restore hidden cards
+        for (Card c : state.hiddenCards) {
+            Card card = new Card.Builder(callback,c).build(getActivity());
+            mHiddenCards.put(card.getTag(), card);
+        }
+
+        // temporarily set up list of dismissible
+        final HashSet<String> dismissibleCards = state.dismissibleCards;
+
+        //restore shown cards
+        for (Card c : state.visibleCards) {
+            Card card = new Card.Builder(callback,c).build(getActivity());
+            addCard(card);
+            final String tag = card.getTag();
+            showCard(tag, dismissibleCards.contains(tag));
+        }
+
+        // move to first visible card
+        final String firstShown = state.shownTag;
+        if (firstShown != null) {
+            mLayout.setFirstVisibleCard(firstShown);
+        }
+
+        mLayout.triggerShowInitialAnimation();
+    }
+
+    public CardStreamState dumpState() {
+        final Card[] visible = cloneCards(mVisibleCards.values());
+        final Card[] hidden = cloneCards(mHiddenCards.values());
+        final HashSet<String> dismissible = new HashSet<String>(mDismissibleCards);
+        final String firstVisible = mLayout.getFirstVisibleCardTag();
+
+        return new CardStreamState(visible, hidden, dismissible, firstVisible);
+    }
+
+    private Card[] cloneCards(Collection<Card> cards) {
+        Card[] cardArray = new Card[cards.size()];
+        int i = 0;
+        for (Card c : cards) {
+            cardArray[i++] = c.createShallowClone();
+        }
+
+        return cardArray;
+    }
+
+}
diff --git a/samples/browseable/BatchStepSensor/src/com.example.android.batchstepsensor/CardStreamLinearLayout.java b/samples/browseable/BatchStepSensor/src/com.example.android.batchstepsensor/CardStreamLinearLayout.java
new file mode 100644
index 0000000..aeab770
--- /dev/null
+++ b/samples/browseable/BatchStepSensor/src/com.example.android.batchstepsensor/CardStreamLinearLayout.java
@@ -0,0 +1,569 @@
+/*
+* Copyright 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.batchstepsensor;
+
+import android.animation.Animator;
+import android.animation.LayoutTransition;
+import android.animation.ObjectAnimator;
+import android.annotation.SuppressLint;
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Rect;
+import android.os.Build;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewConfiguration;
+import android.view.ViewGroup;
+import android.view.ViewParent;
+import android.widget.LinearLayout;
+import android.widget.ScrollView;
+
+import com.example.android.common.logger.Log;
+
+import java.util.ArrayList;
+
+/**
+ * A Layout that contains a stream of card views.
+ */
+public class CardStreamLinearLayout extends LinearLayout {
+
+    public static final int ANIMATION_SPEED_SLOW = 1001;
+    public static final int ANIMATION_SPEED_NORMAL = 1002;
+    public static final int ANIMATION_SPEED_FAST = 1003;
+
+    private static final String TAG = "CardStreamLinearLayout";
+    private final ArrayList<View> mFixedViewList = new ArrayList<View>();
+    private final Rect mChildRect = new Rect();
+    private CardStreamAnimator mAnimators;
+    private OnDissmissListener mDismissListener = null;
+    private boolean mLayouted = false;
+    private boolean mSwiping = false;
+    private String mFirstVisibleCardTag = null;
+    private boolean mShowInitialAnimation = false;
+
+    /**
+     * Handle touch events to fade/move dragged items as they are swiped out
+     */
+    private OnTouchListener mTouchListener = new OnTouchListener() {
+
+        private float mDownX;
+        private float mDownY;
+
+        @Override
+        public boolean onTouch(final View v, MotionEvent event) {
+
+            switch (event.getAction()) {
+                case MotionEvent.ACTION_DOWN:
+                    mDownX = event.getX();
+                    mDownY = event.getY();
+                    break;
+                case MotionEvent.ACTION_CANCEL:
+                    resetAnimatedView(v);
+                    mSwiping = false;
+                    mDownX = 0.f;
+                    mDownY = 0.f;
+                    break;
+                case MotionEvent.ACTION_MOVE: {
+
+                    float x = event.getX() + v.getTranslationX();
+                    float y = event.getY() + v.getTranslationY();
+
+                    mDownX = mDownX == 0.f ? x : mDownX;
+                    mDownY = mDownY == 0.f ? x : mDownY;
+
+                    float deltaX = x - mDownX;
+                    float deltaY = y - mDownY;
+
+                    if (!mSwiping && isSwiping(deltaX, deltaY)) {
+                        mSwiping = true;
+                        v.getParent().requestDisallowInterceptTouchEvent(true);
+                    } else {
+                        swipeView(v, deltaX, deltaY);
+                    }
+                }
+                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 y = event.getY() + v.getTranslationY();
+
+                        float deltaX = x - mDownX;
+                        float deltaY = y - mDownX;
+                        float deltaXAbs = Math.abs(deltaX);
+
+                        // User let go - figure out whether to animate the view out, or back into place
+                        boolean remove = deltaXAbs > v.getWidth() / 4 && !isFixedView(v);
+                        if( remove )
+                            handleViewSwipingOut(v, deltaX, deltaY);
+                        else
+                            handleViewSwipingIn(v, deltaX, deltaY);
+                    }
+                    mDownX = 0.f;
+                    mDownY = 0.f;
+                    mSwiping = false;
+                }
+                break;
+                default:
+                    return false;
+            }
+            return false;
+        }
+    };
+    private int mSwipeSlop = -1;
+    /**
+     * Handle end-transition animation event of each child and launch a following animation.
+     */
+    private LayoutTransition.TransitionListener mTransitionListener
+            = new LayoutTransition.TransitionListener() {
+
+        @Override
+        public void startTransition(LayoutTransition transition, ViewGroup container, View
+                view, int transitionType) {
+            Log.d(TAG, "Start LayoutTransition animation:" + transitionType);
+        }
+
+        @Override
+        public void endTransition(LayoutTransition transition, ViewGroup container,
+                                  final View view, int transitionType) {
+
+            Log.d(TAG, "End LayoutTransition animation:" + transitionType);
+            if (transitionType == LayoutTransition.APPEARING) {
+                final View area = view.findViewById(R.id.card_actionarea);
+                if (area != null) {
+                    runShowActionAreaAnimation(container, area);
+                }
+            }
+        }
+    };
+    /**
+     * Handle a hierarchy change event
+     * when a new child is added, scroll to bottom and hide action area..
+     */
+    private OnHierarchyChangeListener mOnHierarchyChangeListener
+            = new OnHierarchyChangeListener() {
+        @Override
+        public void onChildViewAdded(final View parent, final View child) {
+
+            Log.d(TAG, "child is added: " + child);
+
+            ViewParent scrollView = parent.getParent();
+            if (scrollView != null && scrollView instanceof ScrollView) {
+                ((ScrollView) scrollView).fullScroll(FOCUS_DOWN);
+            }
+
+            if (getLayoutTransition() != null) {
+                View view = child.findViewById(R.id.card_actionarea);
+                if (view != null)
+                    view.setAlpha(0.f);
+            }
+        }
+
+        @Override
+        public void onChildViewRemoved(View parent, View child) {
+            Log.d(TAG, "child is removed: " + child);
+            mFixedViewList.remove(child);
+        }
+    };
+    private int mLastDownX;
+
+    public CardStreamLinearLayout(Context context) {
+        super(context);
+        initialize(null, 0);
+    }
+
+    public CardStreamLinearLayout(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        initialize(attrs, 0);
+    }
+
+    @SuppressLint("NewApi")
+    public CardStreamLinearLayout(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+        initialize(attrs, defStyle);
+    }
+
+    /**
+     * add a card view w/ canDismiss flag.
+     *
+     * @param cardView   a card view
+     * @param canDismiss flag to indicate this card is dismissible or not.
+     */
+    public void addCard(View cardView, boolean canDismiss) {
+        if (cardView.getParent() == null) {
+            initCard(cardView, canDismiss);
+
+            ViewGroup.LayoutParams param = cardView.getLayoutParams();
+            if(param == null)
+                param = generateDefaultLayoutParams();
+
+            super.addView(cardView, -1, param);
+        }
+    }
+
+    @Override
+    public void addView(View child, int index, ViewGroup.LayoutParams params) {
+        if (child.getParent() == null) {
+            initCard(child, true);
+            super.addView(child, index, params);
+        }
+    }
+
+    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
+    @Override
+    protected void onLayout(boolean changed, int l, int t, int r, int b) {
+        super.onLayout(changed, l, t, r, b);
+        Log.d(TAG, "onLayout: " + changed);
+
+        if( changed && !mLayouted ){
+            mLayouted = true;
+
+            ObjectAnimator animator;
+            LayoutTransition layoutTransition = new LayoutTransition();
+
+            animator = mAnimators.getDisappearingAnimator(getContext());
+            layoutTransition.setAnimator(LayoutTransition.DISAPPEARING, animator);
+
+            animator = mAnimators.getAppearingAnimator(getContext());
+            layoutTransition.setAnimator(LayoutTransition.APPEARING, animator);
+
+            layoutTransition.addTransitionListener(mTransitionListener);
+
+            if( animator != null )
+                layoutTransition.setDuration(animator.getDuration());
+
+            setLayoutTransition(layoutTransition);
+
+            if( mShowInitialAnimation )
+                runInitialAnimations();
+
+            if (mFirstVisibleCardTag != null) {
+                scrollToCard(mFirstVisibleCardTag);
+                mFirstVisibleCardTag = null;
+            }
+        }
+    }
+
+    /**
+     * Check whether a user moved enough distance to start a swipe action or not.
+     *
+     * @param deltaX
+     * @param deltaY
+     * @return true if a user is swiping.
+     */
+    protected boolean isSwiping(float deltaX, float deltaY) {
+
+        if (mSwipeSlop < 0) {
+            //get swipping slop from ViewConfiguration;
+            mSwipeSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
+        }
+
+        boolean swipping = false;
+        float absDeltaX = Math.abs(deltaX);
+
+        if( absDeltaX > mSwipeSlop )
+            return true;
+
+        return swipping;
+    }
+
+    /**
+     * Swipe a view by moving distance
+     *
+     * @param child a target view
+     * @param deltaX x moving distance by x-axis.
+     * @param deltaY y moving distance by y-axis.
+     */
+    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
+    protected void swipeView(View child, float deltaX, float deltaY) {
+        if (isFixedView(child)){
+            deltaX = deltaX / 4;
+        }
+
+        float deltaXAbs = Math.abs(deltaX);
+        float fractionCovered = deltaXAbs / (float) child.getWidth();
+
+        child.setTranslationX(deltaX);
+        child.setAlpha(1.f - fractionCovered);
+
+        if (deltaX > 0)
+            child.setRotationY(-15.f * fractionCovered);
+        else
+            child.setRotationY(15.f * fractionCovered);
+    }
+
+    protected void notifyOnDismissEvent( View child ){
+        if( child == null || mDismissListener == null )
+            return;
+
+        mDismissListener.onDismiss((String) child.getTag());
+    }
+
+    /**
+     * get the tag of the first visible child in this layout
+     *
+     * @return tag of the first visible child or null
+     */
+    public String getFirstVisibleCardTag() {
+
+        final int count = getChildCount();
+
+        if (count == 0)
+            return null;
+
+        for (int index = 0; index < count; ++index) {
+            //check the position of each view.
+            View child = getChildAt(index);
+            if (child.getGlobalVisibleRect(mChildRect) == true)
+                return (String) child.getTag();
+        }
+
+        return null;
+    }
+
+    /**
+     * Set the first visible card of this linear layout.
+     *
+     * @param tag tag of a card which should already added to this layout.
+     */
+    public void setFirstVisibleCard(String tag) {
+        if (tag == null)
+            return; //do nothing.
+
+        if (mLayouted) {
+            scrollToCard(tag);
+        } else {
+            //keep the tag for next use.
+            mFirstVisibleCardTag = tag;
+        }
+    }
+
+    /**
+     * If this flag is set,
+     * after finishing initial onLayout event, an initial animation which is defined in DefaultCardStreamAnimator is launched.
+     */
+    public void triggerShowInitialAnimation(){
+        mShowInitialAnimation = true;
+    }
+
+    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
+    public void setCardStreamAnimator( CardStreamAnimator animators ){
+
+        if( animators == null )
+            mAnimators = new CardStreamAnimator.EmptyAnimator();
+        else
+            mAnimators = animators;
+
+        LayoutTransition layoutTransition = getLayoutTransition();
+
+        if( layoutTransition != null ){
+            layoutTransition.setAnimator( LayoutTransition.APPEARING,
+                    mAnimators.getAppearingAnimator(getContext()) );
+            layoutTransition.setAnimator( LayoutTransition.DISAPPEARING,
+                    mAnimators.getDisappearingAnimator(getContext()) );
+        }
+    }
+
+    /**
+     * set a OnDismissListener which called when user dismiss a card.
+     *
+     * @param listener
+     */
+    public void setOnDismissListener(OnDissmissListener listener) {
+        mDismissListener = listener;
+    }
+
+    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
+    private void initialize(AttributeSet attrs, int defStyle) {
+
+        float speedFactor = 1.f;
+
+        if (attrs != null) {
+            TypedArray a = getContext().obtainStyledAttributes(attrs,
+                    R.styleable.CardStream, defStyle, 0);
+
+            if( a != null ){
+                int speedType = a.getInt(R.styleable.CardStream_animationDuration, 1001);
+                switch (speedType){
+                    case ANIMATION_SPEED_FAST:
+                        speedFactor = 0.5f;
+                        break;
+                    case ANIMATION_SPEED_NORMAL:
+                        speedFactor = 1.f;
+                        break;
+                    case ANIMATION_SPEED_SLOW:
+                        speedFactor = 2.f;
+                        break;
+                }
+
+                String animatorName = a.getString(R.styleable.CardStream_animators);
+
+                try {
+                    if( animatorName != null )
+                        mAnimators = (CardStreamAnimator) getClass().getClassLoader()
+                                .loadClass(animatorName).newInstance();
+                } catch (Exception e) {
+                    Log.e(TAG, "Fail to load animator:" + animatorName, e);
+                } finally {
+                    if(mAnimators == null)
+                        mAnimators = new DefaultCardStreamAnimator();
+                }
+                a.recycle();
+            }
+        }
+
+        mAnimators.setSpeedFactor(speedFactor);
+        mSwipeSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
+        setOnHierarchyChangeListener(mOnHierarchyChangeListener);
+    }
+
+    private void initCard(View cardView, boolean canDismiss) {
+        resetAnimatedView(cardView);
+        cardView.setOnTouchListener(mTouchListener);
+        if (!canDismiss)
+            mFixedViewList.add(cardView);
+    }
+
+    private boolean isFixedView(View v) {
+        return mFixedViewList.contains(v);
+    }
+
+    private void resetAnimatedView(View child) {
+        child.setAlpha(1.f);
+        child.setTranslationX(0.f);
+        child.setTranslationY(0.f);
+        child.setRotation(0.f);
+        child.setRotationY(0.f);
+        child.setRotationX(0.f);
+        child.setScaleX(1.f);
+        child.setScaleY(1.f);
+    }
+
+    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
+    private void runInitialAnimations() {
+        if( mAnimators == null )
+            return;
+
+        final int count = getChildCount();
+
+        for (int index = 0; index < count; ++index) {
+            final View child = getChildAt(index);
+            ObjectAnimator animator =  mAnimators.getInitalAnimator(getContext());
+            if( animator != null ){
+                animator.setTarget(child);
+                animator.start();
+            }
+        }
+    }
+
+    private void runShowActionAreaAnimation(View parent, View area) {
+        area.setPivotY(0.f);
+        area.setPivotX(parent.getWidth() / 2.f);
+
+        area.setAlpha(0.5f);
+        area.setRotationX(-90.f);
+        area.animate().rotationX(0.f).alpha(1.f).setDuration(400);
+    }
+
+    private void handleViewSwipingOut(final View child, float deltaX, float deltaY) {
+        ObjectAnimator animator = mAnimators.getSwipeOutAnimator(child, deltaX, deltaY);
+        if( animator != null ){
+            animator.addListener(new EndAnimationWrapper() {
+                @Override
+                public void onAnimationEnd(Animator animation) {
+                    removeView(child);
+                    notifyOnDismissEvent(child);
+                }
+            });
+        } else {
+            removeView(child);
+            notifyOnDismissEvent(child);
+        }
+
+        if( animator != null ){
+            animator.setTarget(child);
+            animator.start();
+        }
+    }
+
+    private void handleViewSwipingIn(final View child, float deltaX, float deltaY) {
+        ObjectAnimator animator = mAnimators.getSwipeInAnimator(child, deltaX, deltaY);
+        if( animator != null ){
+            animator.addListener(new EndAnimationWrapper() {
+                @Override
+                public void onAnimationEnd(Animator animation) {
+                    child.setTranslationY(0.f);
+                    child.setTranslationX(0.f);
+                }
+            });
+        } else {
+            child.setTranslationY(0.f);
+            child.setTranslationX(0.f);
+        }
+
+        if( animator != null ){
+            animator.setTarget(child);
+            animator.start();
+        }
+    }
+
+    private void scrollToCard(String tag) {
+
+
+        final int count = getChildCount();
+        for (int index = 0; index < count; ++index) {
+            View child = getChildAt(index);
+
+            if (tag.equals(child.getTag())) {
+
+                ViewParent parent = getParent();
+                if( parent != null && parent instanceof ScrollView ){
+                    ((ScrollView)parent).smoothScrollTo(
+                            0, child.getTop() - getPaddingTop() - child.getPaddingTop());
+                }
+                return;
+            }
+        }
+    }
+
+    public interface OnDissmissListener {
+        public void onDismiss(String tag);
+    }
+
+    /**
+     * Empty default AnimationListener
+     */
+    private abstract class EndAnimationWrapper implements Animator.AnimatorListener {
+
+        @Override
+        public void onAnimationStart(Animator animation) {
+        }
+
+        @Override
+        public void onAnimationCancel(Animator animation) {
+        }
+
+        @Override
+        public void onAnimationRepeat(Animator animation) {
+        }
+    }//end of inner class
+}
diff --git a/samples/browseable/BatchStepSensor/src/com.example.android.batchstepsensor/CardStreamState.java b/samples/browseable/BatchStepSensor/src/com.example.android.batchstepsensor/CardStreamState.java
new file mode 100644
index 0000000..08432a9
--- /dev/null
+++ b/samples/browseable/BatchStepSensor/src/com.example.android.batchstepsensor/CardStreamState.java
@@ -0,0 +1,40 @@
+/*
+* Copyright 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.batchstepsensor;
+
+import java.util.HashSet;
+
+/**
+ * A struct object that holds the state of a {@link CardStreamFragment}.
+ */
+class CardStreamState{
+    protected Card[] visibleCards;
+    protected Card[] hiddenCards;
+    protected HashSet<String> dismissibleCards;
+    protected String shownTag;
+
+    protected CardStreamState(Card[] visible, Card[] hidden, HashSet<String> dismissible, String shownTag) {
+        visibleCards = visible;
+        hiddenCards = hidden;
+        dismissibleCards = dismissible;
+        this.shownTag = shownTag;
+    }
+
+}
diff --git a/samples/browseable/BatchStepSensor/src/com.example.android.batchstepsensor/DefaultCardStreamAnimator.java b/samples/browseable/BatchStepSensor/src/com.example.android.batchstepsensor/DefaultCardStreamAnimator.java
new file mode 100644
index 0000000..19ef43b
--- /dev/null
+++ b/samples/browseable/BatchStepSensor/src/com.example.android.batchstepsensor/DefaultCardStreamAnimator.java
@@ -0,0 +1,124 @@
+/*
+* Copyright 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.batchstepsensor;
+
+import android.animation.ObjectAnimator;
+import android.animation.PropertyValuesHolder;
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.graphics.Point;
+import android.os.Build;
+import android.view.View;
+import android.view.WindowManager;
+import android.view.animation.BounceInterpolator;
+
+class DefaultCardStreamAnimator extends CardStreamAnimator {
+
+    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
+    @Override
+    public ObjectAnimator getDisappearingAnimator(Context context){
+
+        ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(new Object(),
+                PropertyValuesHolder.ofFloat("alpha", 1.f, 0.f),
+                PropertyValuesHolder.ofFloat("scaleX", 1.f, 0.f),
+                PropertyValuesHolder.ofFloat("scaleY", 1.f, 0.f),
+                PropertyValuesHolder.ofFloat("rotation", 0.f, 270.f));
+
+        animator.setDuration((long) (200 * mSpeedFactor));
+        return animator;
+    }
+
+    @TargetApi(Build.VERSION_CODES.HONEYCOMB_MR2)
+    @Override
+    public ObjectAnimator getAppearingAnimator(Context context){
+
+        final Point outPoint = new Point();
+        WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
+        wm.getDefaultDisplay().getSize(outPoint);
+
+        ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(new Object(),
+                PropertyValuesHolder.ofFloat("alpha", 0.f, 1.f),
+                PropertyValuesHolder.ofFloat("translationY", outPoint.y / 2.f, 0.f),
+                PropertyValuesHolder.ofFloat("rotation", -45.f, 0.f));
+
+        animator.setDuration((long) (200 * mSpeedFactor));
+        return animator;
+    }
+
+    @TargetApi(Build.VERSION_CODES.HONEYCOMB_MR2)
+    @Override
+    public ObjectAnimator getInitalAnimator(Context context){
+
+        ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(new Object(),
+                PropertyValuesHolder.ofFloat("alpha", 0.5f, 1.f),
+                PropertyValuesHolder.ofFloat("rotation", 60.f, 0.f));
+
+        animator.setDuration((long) (200 * mSpeedFactor));
+        return animator;
+    }
+
+    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
+    @Override
+    public ObjectAnimator getSwipeInAnimator(View view, float deltaX, float deltaY){
+
+        float deltaXAbs = Math.abs(deltaX);
+
+        float fractionCovered = 1.f - (deltaXAbs / view.getWidth());
+        long duration = Math.abs((int) ((1 - fractionCovered) * 200 * mSpeedFactor));
+
+        // Animate position and alpha of swiped item
+
+        ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(view,
+                PropertyValuesHolder.ofFloat("alpha", 1.f),
+                PropertyValuesHolder.ofFloat("translationX", 0.f),
+                PropertyValuesHolder.ofFloat("rotationY", 0.f));
+
+        animator.setDuration(duration).setInterpolator(new BounceInterpolator());
+
+        return  animator;
+    }
+
+    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
+    @Override
+    public ObjectAnimator getSwipeOutAnimator(View view, float deltaX, float deltaY){
+
+        float endX;
+        float endRotationY;
+
+        float deltaXAbs = Math.abs(deltaX);
+
+        float fractionCovered = 1.f - (deltaXAbs / view.getWidth());
+        long duration = Math.abs((int) ((1 - fractionCovered) * 200 * mSpeedFactor));
+
+        endX = deltaX < 0 ? -view.getWidth() : view.getWidth();
+        if (deltaX > 0)
+            endRotationY = -15.f;
+        else
+            endRotationY = 15.f;
+
+        // Animate position and alpha of swiped item
+        return ObjectAnimator.ofPropertyValuesHolder(view,
+                PropertyValuesHolder.ofFloat("alpha", 0.f),
+                PropertyValuesHolder.ofFloat("translationX", endX),
+                PropertyValuesHolder.ofFloat("rotationY", endRotationY)).setDuration(duration);
+
+    }
+
+}
diff --git a/samples/browseable/BatchStepSensor/src/com.example.android.batchstepsensor/MainActivity.java b/samples/browseable/BatchStepSensor/src/com.example.android.batchstepsensor/MainActivity.java
new file mode 100644
index 0000000..bb1f9a1
--- /dev/null
+++ b/samples/browseable/BatchStepSensor/src/com.example.android.batchstepsensor/MainActivity.java
@@ -0,0 +1,91 @@
+/*
+* Copyright 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.batchstepsensor;
+
+import android.os.Bundle;
+import android.support.v4.app.FragmentManager;
+import android.support.v4.app.FragmentTransaction;
+import android.view.Menu;
+
+import com.example.android.common.activities.SampleActivityBase;
+import com.example.android.common.logger.Log;
+
+public class MainActivity extends SampleActivityBase implements CardStream {
+    public static final String TAG = "MainActivity";
+    public static final String FRAGTAG = "BatchStepSensorFragment";
+
+    private CardStreamFragment mCardStreamFragment;
+
+    private StreamRetentionFragment mRetentionFragment;
+    private static final String RETENTION_TAG = "retention";
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_main);
+
+        FragmentManager fm = getSupportFragmentManager();
+        BatchStepSensorFragment fragment =
+                (BatchStepSensorFragment) fm.findFragmentByTag(FRAGTAG);
+
+        if (fragment == null) {
+            FragmentTransaction transaction = fm.beginTransaction();
+            fragment = new BatchStepSensorFragment();
+            transaction.add(fragment, FRAGTAG);
+            transaction.commit();
+        }
+
+        // Use fragment as click listener for cards, but must implement correct interface
+        if(!(fragment instanceof OnCardClickListener)){
+            throw new ClassCastException("BatchStepSensorFragment must " +
+                    "implement OnCardClickListener interface.");
+        }
+        OnCardClickListener clickListener = (OnCardClickListener) fm.findFragmentByTag(FRAGTAG);
+
+        mRetentionFragment = (StreamRetentionFragment) fm.findFragmentByTag(RETENTION_TAG);
+        if (mRetentionFragment == null) {
+            mRetentionFragment = new StreamRetentionFragment();
+            fm.beginTransaction().add(mRetentionFragment, RETENTION_TAG).commit();
+        } else {
+            // If the retention fragment already existed, we need to pull some state.
+            // pull state out
+            CardStreamState state = mRetentionFragment.getCardStream();
+
+            // dump it in CardStreamFragment.
+            mCardStreamFragment =
+                    (CardStreamFragment) fm.findFragmentById(R.id.fragment_cardstream);
+            mCardStreamFragment.restoreState(state, clickListener);
+        }
+    }
+
+    public CardStreamFragment getCardStream() {
+        if (mCardStreamFragment == null) {
+            mCardStreamFragment = (CardStreamFragment)
+                    getSupportFragmentManager().findFragmentById(R.id.fragment_cardstream);
+        }
+        return mCardStreamFragment;
+    }
+
+    @Override
+    protected void onSaveInstanceState(Bundle outState) {
+        super.onSaveInstanceState(outState);
+        CardStreamState state = getCardStream().dumpState();
+        mRetentionFragment.storeCardStream(state);
+    }
+}
diff --git a/samples/browseable/BatchStepSensor/src/com.example.android.batchstepsensor/OnCardClickListener.java b/samples/browseable/BatchStepSensor/src/com.example.android.batchstepsensor/OnCardClickListener.java
new file mode 100644
index 0000000..f024110
--- /dev/null
+++ b/samples/browseable/BatchStepSensor/src/com.example.android.batchstepsensor/OnCardClickListener.java
@@ -0,0 +1,24 @@
+/*
+* Copyright 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.batchstepsensor;
+
+public interface OnCardClickListener {
+    public void onCardClick(int cardActionId, String cardTag);
+}
diff --git a/samples/browseable/BatchStepSensor/src/com.example.android.batchstepsensor/StreamRetentionFragment.java b/samples/browseable/BatchStepSensor/src/com.example.android.batchstepsensor/StreamRetentionFragment.java
new file mode 100644
index 0000000..7cd7f2b
--- /dev/null
+++ b/samples/browseable/BatchStepSensor/src/com.example.android.batchstepsensor/StreamRetentionFragment.java
@@ -0,0 +1,41 @@
+/*
+* Copyright 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.batchstepsensor;
+
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+
+public class StreamRetentionFragment extends Fragment {
+
+    CardStreamState mState;
+
+    @Override
+    public void onActivityCreated(Bundle savedInstanceState) {
+        super.onActivityCreated(savedInstanceState);
+        setRetainInstance(true);
+    }
+
+    public void storeCardStream(CardStreamState state) {
+        mState = state;
+    }
+
+    public CardStreamState getCardStream() {
+        return mState;
+    }
+}
diff --git a/samples/browseable/repeatingAlarm/src/com.example.android.common/activities/SampleActivityBase.java b/samples/browseable/BatchStepSensor/src/com.example.android.common/activities/SampleActivityBase.java
similarity index 100%
copy from samples/browseable/repeatingAlarm/src/com.example.android.common/activities/SampleActivityBase.java
copy to samples/browseable/BatchStepSensor/src/com.example.android.common/activities/SampleActivityBase.java
diff --git a/samples/browseable/repeatingAlarm/src/com.example.android.common/logger/Log.java b/samples/browseable/BatchStepSensor/src/com.example.android.common/logger/Log.java
similarity index 100%
copy from samples/browseable/repeatingAlarm/src/com.example.android.common/logger/Log.java
copy to samples/browseable/BatchStepSensor/src/com.example.android.common/logger/Log.java
diff --git a/samples/browseable/repeatingAlarm/src/com.example.android.common/logger/LogFragment.java b/samples/browseable/BatchStepSensor/src/com.example.android.common/logger/LogFragment.java
similarity index 100%
copy from samples/browseable/repeatingAlarm/src/com.example.android.common/logger/LogFragment.java
copy to samples/browseable/BatchStepSensor/src/com.example.android.common/logger/LogFragment.java
diff --git a/samples/browseable/repeatingAlarm/src/com.example.android.common/logger/LogNode.java b/samples/browseable/BatchStepSensor/src/com.example.android.common/logger/LogNode.java
similarity index 100%
copy from samples/browseable/repeatingAlarm/src/com.example.android.common/logger/LogNode.java
copy to samples/browseable/BatchStepSensor/src/com.example.android.common/logger/LogNode.java
diff --git a/samples/browseable/repeatingAlarm/src/com.example.android.common/logger/LogView.java b/samples/browseable/BatchStepSensor/src/com.example.android.common/logger/LogView.java
similarity index 100%
copy from samples/browseable/repeatingAlarm/src/com.example.android.common/logger/LogView.java
copy to samples/browseable/BatchStepSensor/src/com.example.android.common/logger/LogView.java
diff --git a/samples/browseable/repeatingAlarm/src/com.example.android.common/logger/LogWrapper.java b/samples/browseable/BatchStepSensor/src/com.example.android.common/logger/LogWrapper.java
similarity index 100%
copy from samples/browseable/repeatingAlarm/src/com.example.android.common/logger/LogWrapper.java
copy to samples/browseable/BatchStepSensor/src/com.example.android.common/logger/LogWrapper.java
diff --git a/samples/browseable/repeatingAlarm/src/com.example.android.common/logger/MessageOnlyLogFilter.java b/samples/browseable/BatchStepSensor/src/com.example.android.common/logger/MessageOnlyLogFilter.java
similarity index 100%
copy from samples/browseable/repeatingAlarm/src/com.example.android.common/logger/MessageOnlyLogFilter.java
copy to samples/browseable/BatchStepSensor/src/com.example.android.common/logger/MessageOnlyLogFilter.java
diff --git a/samples/browseable/BluetoothLeGatt/res/values-sw600dp/dimens.xml b/samples/browseable/BluetoothLeGatt/res/values-sw600dp/template-dimens.xml
similarity index 100%
rename from samples/browseable/BluetoothLeGatt/res/values-sw600dp/dimens.xml
rename to samples/browseable/BluetoothLeGatt/res/values-sw600dp/template-dimens.xml
diff --git a/samples/browseable/BluetoothLeGatt/res/values-sw600dp/styles.xml b/samples/browseable/BluetoothLeGatt/res/values-sw600dp/template-styles.xml
similarity index 100%
rename from samples/browseable/BluetoothLeGatt/res/values-sw600dp/styles.xml
rename to samples/browseable/BluetoothLeGatt/res/values-sw600dp/template-styles.xml
diff --git a/samples/browseable/BluetoothLeGatt/res/values/dimens.xml b/samples/browseable/BluetoothLeGatt/res/values/template-dimens.xml
similarity index 100%
rename from samples/browseable/BluetoothLeGatt/res/values/dimens.xml
rename to samples/browseable/BluetoothLeGatt/res/values/template-dimens.xml
diff --git a/samples/browseable/BluetoothLeGatt/res/values/styles.xml b/samples/browseable/BluetoothLeGatt/res/values/template-styles.xml
similarity index 100%
rename from samples/browseable/BluetoothLeGatt/res/values/styles.xml
rename to samples/browseable/BluetoothLeGatt/res/values/template-styles.xml
diff --git a/samples/browseable/BorderlessButtons/res/values-sw600dp/dimens.xml b/samples/browseable/BorderlessButtons/res/values-sw600dp/template-dimens.xml
similarity index 100%
rename from samples/browseable/BorderlessButtons/res/values-sw600dp/dimens.xml
rename to samples/browseable/BorderlessButtons/res/values-sw600dp/template-dimens.xml
diff --git a/samples/browseable/BorderlessButtons/res/values-sw600dp/styles.xml b/samples/browseable/BorderlessButtons/res/values-sw600dp/template-styles.xml
similarity index 100%
rename from samples/browseable/BorderlessButtons/res/values-sw600dp/styles.xml
rename to samples/browseable/BorderlessButtons/res/values-sw600dp/template-styles.xml
diff --git a/samples/browseable/BorderlessButtons/res/values/dimens.xml b/samples/browseable/BorderlessButtons/res/values/dimens.xml
index 39e710b..71a1fc7 100644
--- a/samples/browseable/BorderlessButtons/res/values/dimens.xml
+++ b/samples/browseable/BorderlessButtons/res/values/dimens.xml
@@ -16,17 +16,10 @@
 
 <resources>
 
-    <!-- Define standard dimensions to comply with Holo-style grids and rhythm. -->
+    <dimen name="standard_touch_target_size">48dp</dimen>
 
-    <dimen name="margin_tiny">4dp</dimen>
-    <dimen name="margin_small">8dp</dimen>
-    <dimen name="margin_medium">16dp</dimen>
-    <dimen name="margin_large">32dp</dimen>
-    <dimen name="margin_huge">64dp</dimen>
+    <!-- Meta-dimension that switches on screen size -->
 
-    <!-- Semantic definitions -->
-
-    <dimen name="horizontal_page_margin">@dimen/margin_medium</dimen>
-    <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+    <dimen name="page_margin">@dimen/margin_medium</dimen>
 
 </resources>
diff --git a/samples/browseable/BorderlessButtons/res/values/styles.xml b/samples/browseable/BorderlessButtons/res/values/styles.xml
index 404623e..36e0445 100644
--- a/samples/browseable/BorderlessButtons/res/values/styles.xml
+++ b/samples/browseable/BorderlessButtons/res/values/styles.xml
@@ -16,27 +16,16 @@
 
 <resources>
 
-    <!-- Activity themes -->
-
-    <style name="Theme.Base" parent="android:Theme.Holo.Light" />
-
-    <style name="Theme.Sample" parent="Theme.Base" />
-
-    <style name="AppTheme" parent="Theme.Sample" />
     <!-- Widget styling -->
 
-    <style name="Widget" />
-
-    <style name="Widget.SampleMessage">
+    <style name="Widget.DescriptionBar">
+        <item name="android:background">#fb3</item>
+        <item name="android:paddingTop">@dimen/margin_medium</item>
+        <item name="android:paddingBottom">@dimen/margin_medium</item>
+        <item name="android:paddingLeft">@dimen/page_margin</item>
+        <item name="android:paddingRight">@dimen/page_margin</item>
         <item name="android:textAppearance">?android:textAppearanceMedium</item>
         <item name="android:lineSpacingMultiplier">1.1</item>
     </style>
 
-    <style name="Widget.SampleMessageTile">
-        <item name="android:background">@drawable/tile</item>
-        <item name="android:shadowColor">#7F000000</item>
-        <item name="android:shadowDy">-3.5</item>
-        <item name="android:shadowRadius">2</item>
-    </style>
-
 </resources>
diff --git a/samples/browseable/AppRestrictions/res/values/dimens.xml b/samples/browseable/BorderlessButtons/res/values/template-dimens.xml
similarity index 100%
copy from samples/browseable/AppRestrictions/res/values/dimens.xml
copy to samples/browseable/BorderlessButtons/res/values/template-dimens.xml
diff --git a/samples/browseable/AppRestrictions/res/values/styles.xml b/samples/browseable/BorderlessButtons/res/values/template-styles.xml
similarity index 100%
copy from samples/browseable/AppRestrictions/res/values/styles.xml
copy to samples/browseable/BorderlessButtons/res/values/template-styles.xml
diff --git a/samples/browseable/CardEmulation/AndroidManifest.xml b/samples/browseable/CardEmulation/AndroidManifest.xml
new file mode 100644
index 0000000..4a4af08
--- /dev/null
+++ b/samples/browseable/CardEmulation/AndroidManifest.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 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.cardemulation"
+    android:versionCode="1"
+    android:versionName="1.0">
+
+    <!-- Card emulation was introduced in API 19. -->
+    <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="19" />
+    <uses-feature android:name="android.hardware.nfc.hce" android:required="true" />
+    <uses-permission android:name="android.permission.NFC" />
+
+    <application android:allowBackup="true"
+        android:label="@string/app_name"
+        android:icon="@drawable/ic_launcher"
+        android:theme="@style/AppTheme">
+
+        <!-- Basic UI for sample discoverability. -->
+        <activity android:name=".MainActivity"
+                  android:label="@string/app_name">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+
+        <!-- BEGIN_INCLUDE(CardEmulationManifest) -->
+        <!-- Service for handling communication with NFC terminal. -->
+        <service android:name=".CardService"
+                 android:exported="true"
+                 android:permission="android.permission.BIND_NFC_SERVICE">
+            <!-- Intent filter indicating that we support card emulation. -->
+            <intent-filter>
+                <action android:name="android.nfc.cardemulation.action.HOST_APDU_SERVICE"/>
+                <category android:name="android.intent.category.DEFAULT"/>
+            </intent-filter>
+            <!-- Required XML configuration file, listing the AIDs that we are emulating cards
+                 for. This defines what protocols our card emulation service supports. -->
+            <meta-data android:name="android.nfc.cardemulation.host_apdu_service"
+                       android:resource="@xml/aid_list"/>
+        </service>
+        <!-- END_INCLUDE(CardEmulationManifest) -->
+    </application>
+
+
+</manifest>
diff --git a/samples/browseable/CardEmulation/_index.jd b/samples/browseable/CardEmulation/_index.jd
new file mode 100644
index 0000000..1f3e3c7
--- /dev/null
+++ b/samples/browseable/CardEmulation/_index.jd
@@ -0,0 +1,19 @@
+
+
+
+page.tags="CardEmulation"
+sample.group=Connectivity
+@jd:body
+
+<p>
+  This sample demonstrates how to emulate an NFC card, using the <a href=
+  "{@docRoot}guide/topics/connectivity/nfc/hce.html">Host Card Emulation</a>
+  feature added in Android 4.4. This sample makes the device appear as a
+  loyalty card whenever the screen is on and the user taps their device on an
+  appropriately configured NFC reader.
+</p>
+
+<p>
+  The <a href="{@docRoot}samples/CardReader/index.html">CardReader</a> sample
+  can be used to read the loyalty card implemented in this sample.
+</p>
diff --git a/samples/browseable/CardEmulation/res/drawable-hdpi/ic_launcher.png b/samples/browseable/CardEmulation/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..0be8f85
--- /dev/null
+++ b/samples/browseable/CardEmulation/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/Basic/res/drawable-hdpi/tile.9.png b/samples/browseable/CardEmulation/res/drawable-hdpi/tile.9.png
similarity index 100%
copy from samples/browseable/Basic/res/drawable-hdpi/tile.9.png
copy to samples/browseable/CardEmulation/res/drawable-hdpi/tile.9.png
Binary files differ
diff --git a/samples/browseable/CardEmulation/res/drawable-mdpi/ic_launcher.png b/samples/browseable/CardEmulation/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..eb13405
--- /dev/null
+++ b/samples/browseable/CardEmulation/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/CardEmulation/res/drawable-xhdpi/ic_launcher.png b/samples/browseable/CardEmulation/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..8d1e6a6
--- /dev/null
+++ b/samples/browseable/CardEmulation/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/CardEmulation/res/drawable-xxhdpi/card_background.png b/samples/browseable/CardEmulation/res/drawable-xxhdpi/card_background.png
new file mode 100644
index 0000000..86a7ba7
--- /dev/null
+++ b/samples/browseable/CardEmulation/res/drawable-xxhdpi/card_background.png
Binary files differ
diff --git a/samples/browseable/CardEmulation/res/drawable-xxhdpi/ic_launcher.png b/samples/browseable/CardEmulation/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..7ea109f
--- /dev/null
+++ b/samples/browseable/CardEmulation/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/CardEmulation/res/layout-w720dp/activity_main.xml b/samples/browseable/CardEmulation/res/layout-w720dp/activity_main.xml
new file mode 100755
index 0000000..c9a52f6
--- /dev/null
+++ b/samples/browseable/CardEmulation/res/layout-w720dp/activity_main.xml
@@ -0,0 +1,73 @@
+<!--
+  Copyright 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"
+      android:orientation="horizontal"
+      android:layout_width="match_parent"
+      android:layout_height="match_parent"
+      android:id="@+id/sample_main_layout">
+
+    <LinearLayout
+          android:id="@+id/sample_output"
+          android:layout_width="0px"
+          android:layout_height="match_parent"
+          android:layout_weight="1"
+          android:orientation="vertical">
+
+        <FrameLayout
+              style="@style/Widget.SampleMessageTile"
+              android:layout_width="match_parent"
+              android:layout_height="wrap_content">
+
+            <TextView
+                  style="@style/Widget.SampleMessage"
+                  android:layout_width="match_parent"
+                  android:layout_height="wrap_content"
+                  android:paddingLeft="@dimen/margin_medium"
+                  android:paddingRight="@dimen/margin_medium"
+                  android:paddingTop="@dimen/margin_large"
+                  android:paddingBottom="@dimen/margin_large"
+                  android:text="@string/intro_message" />
+        </FrameLayout>
+
+        <View
+              android:layout_width="match_parent"
+              android:layout_height="1dp"
+              android:background="@android:color/darker_gray" />
+
+        <fragment
+              android:name="com.example.android.common.logger.LogFragment"
+              android:id="@+id/log_fragment"
+              android:layout_width="match_parent"
+              android:layout_height="0px"
+              android:layout_weight="1" />
+
+    </LinearLayout>
+
+    <View
+          android:layout_width="1dp"
+          android:layout_height="match_parent"
+          android:background="@android:color/darker_gray" />
+
+    <FrameLayout
+          android:id="@+id/sample_content_fragment"
+          android:layout_weight="2"
+          android:layout_width="0px"
+          android:layout_height="match_parent" />
+
+</LinearLayout>
+
+
diff --git a/samples/browseable/CardEmulation/res/layout/activity_main.xml b/samples/browseable/CardEmulation/res/layout/activity_main.xml
new file mode 100755
index 0000000..1ae4f98
--- /dev/null
+++ b/samples/browseable/CardEmulation/res/layout/activity_main.xml
@@ -0,0 +1,65 @@
+<!--
+  Copyright 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"
+      android:orientation="vertical"
+      android:layout_width="match_parent"
+      android:layout_height="match_parent"
+      android:id="@+id/sample_main_layout">
+
+    <ViewAnimator
+          android:id="@+id/sample_output"
+          android:layout_width="match_parent"
+          android:layout_height="0px"
+          android:layout_weight="1">
+
+        <ScrollView
+              style="@style/Widget.SampleMessageTile"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent">
+
+            <TextView
+                  style="@style/Widget.SampleMessage"
+                  android:layout_width="match_parent"
+                  android:layout_height="wrap_content"
+                  android:paddingLeft="@dimen/horizontal_page_margin"
+                  android:paddingRight="@dimen/horizontal_page_margin"
+                  android:paddingTop="@dimen/vertical_page_margin"
+                  android:paddingBottom="@dimen/vertical_page_margin"
+                  android:text="@string/intro_message" />
+        </ScrollView>
+
+        <fragment
+              android:name="com.example.android.common.logger.LogFragment"
+              android:id="@+id/log_fragment"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent" />
+
+    </ViewAnimator>
+
+    <View
+          android:layout_width="match_parent"
+          android:layout_height="1dp"
+          android:background="@android:color/darker_gray" />
+
+    <FrameLayout
+          android:id="@+id/sample_content_fragment"
+          android:layout_weight="2"
+          android:layout_width="match_parent"
+          android:layout_height="0px" />
+
+</LinearLayout>
+
diff --git a/samples/browseable/CardEmulation/res/layout/main_fragment.xml b/samples/browseable/CardEmulation/res/layout/main_fragment.xml
new file mode 100644
index 0000000..2c69743
--- /dev/null
+++ b/samples/browseable/CardEmulation/res/layout/main_fragment.xml
@@ -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.
+-->
+
+<FrameLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="380dp"
+    android:layout_height="242.25dp"
+    android:layout_gravity="center"
+    android:layout_margin="20dp">
+    <ImageView
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:src="@drawable/card_background"
+        />
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:orientation="vertical"
+        android:padding="20dp"
+        android:layout_gravity="center"
+        android:clickable="true">
+        <TextView
+            android:id="@+id/card_title"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/card_title"
+            android:fontFamily="sans-serif-condensed"
+            android:textStyle="bold"
+            android:textSize="32dp"
+            />
+        <TextView
+            android:id="@+id/card_account_label"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/account_number"
+            android:fontFamily="sans-serif"
+            android:textStyle="bold"
+            android:textSize="18dp"
+            android:layout_marginTop="40dp"
+            />
+        <EditText
+            android:id="@+id/card_account_field"
+            android:width="360dp"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:fontFamily="sans-serif-condensed"
+            android:textStyle="bold"
+            android:textSize="42dp"
+            android:singleLine="true"
+            android:inputType="number" />
+    </LinearLayout>
+</FrameLayout>
\ No newline at end of file
diff --git a/samples/training/bitmapfun/BitmapFun/src/main/res/values/colors.xml b/samples/browseable/CardEmulation/res/menu/main.xml
similarity index 60%
copy from samples/training/bitmapfun/BitmapFun/src/main/res/values/colors.xml
copy to samples/browseable/CardEmulation/res/menu/main.xml
index 7e4a4fe..b49c2c5 100644
--- a/samples/training/bitmapfun/BitmapFun/src/main/res/values/colors.xml
+++ b/samples/browseable/CardEmulation/res/menu/main.xml
@@ -1,23 +1,21 @@
-<?xml version="1.0" encoding="utf-8"?>
 <!--
-  Copyright (C) 2012 The Android Open Source Project
+  Copyright 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
+      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>
-
-    <color name="grid_state_pressed">#BB7dbcd3</color>
-    <color name="grid_state_focused">#777dbcd3</color>
-
-</resources>
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:id="@+id/menu_toggle_log"
+          android:showAsAction="always"
+          android:title="@string/sample_show_log" />
+</menu>
diff --git a/samples/browseable/AppRestrictions/res/values-sw600dp/dimens.xml b/samples/browseable/CardEmulation/res/values-sw600dp/template-dimens.xml
similarity index 100%
copy from samples/browseable/AppRestrictions/res/values-sw600dp/dimens.xml
copy to samples/browseable/CardEmulation/res/values-sw600dp/template-dimens.xml
diff --git a/samples/browseable/AppRestrictions/res/values-sw600dp/styles.xml b/samples/browseable/CardEmulation/res/values-sw600dp/template-styles.xml
similarity index 100%
copy from samples/browseable/AppRestrictions/res/values-sw600dp/styles.xml
copy to samples/browseable/CardEmulation/res/values-sw600dp/template-styles.xml
diff --git a/samples/browseable/repeatingAlarm/res/values/base-strings.xml b/samples/browseable/CardEmulation/res/values/base-strings.xml
similarity index 62%
copy from samples/browseable/repeatingAlarm/res/values/base-strings.xml
copy to samples/browseable/CardEmulation/res/values/base-strings.xml
index c11b89b..9062a23 100644
--- a/samples/browseable/repeatingAlarm/res/values/base-strings.xml
+++ b/samples/browseable/CardEmulation/res/values/base-strings.xml
@@ -18,13 +18,17 @@
 
 
 <resources>
-    <string name="app_name">repeatingAlarm</string>
+    <string name="app_name">CardEmulation</string>
     <string name="intro_message">
         <![CDATA[
         
             
-                Introductory text that explains what the sample is intended to demonstrate. Edit
-                in template-params.xml.
+            This sample demonstrates how to emulate an NFC card, using the "host card emulation"
+            feature added in Android 4.4. This sample makes the device appear as a loyalty card
+            whenever the screen is on and the user taps their device on an appropriately configured
+            NFC reader.
+
+            The "CardReader" sample can be used to read the loyalty card implemented in this sample.
             
         
         ]]>
diff --git a/samples/training/bitmapfun/BitmapFun/src/main/res/values/colors.xml b/samples/browseable/CardEmulation/res/values/strings.xml
old mode 100644
new mode 100755
similarity index 67%
copy from samples/training/bitmapfun/BitmapFun/src/main/res/values/colors.xml
copy to samples/browseable/CardEmulation/res/values/strings.xml
index 7e4a4fe..7b9d9ec
--- a/samples/training/bitmapfun/BitmapFun/src/main/res/values/colors.xml
+++ b/samples/browseable/CardEmulation/res/values/strings.xml
@@ -1,12 +1,11 @@
-<?xml version="1.0" encoding="utf-8"?>
 <!--
-  Copyright (C) 2012 The Android Open Source Project
+  Copyright 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
+      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,
@@ -14,10 +13,7 @@
   See the License for the specific language governing permissions and
   limitations under the License.
 -->
-
 <resources>
-
-    <color name="grid_state_pressed">#BB7dbcd3</color>
-    <color name="grid_state_focused">#777dbcd3</color>
-
+    <string name="sample_show_log">Show Log</string>
+    <string name="sample_hide_log">Hide Log</string>
 </resources>
diff --git a/samples/browseable/Basic/res/values/dimens.xml b/samples/browseable/CardEmulation/res/values/template-dimens.xml
similarity index 100%
copy from samples/browseable/Basic/res/values/dimens.xml
copy to samples/browseable/CardEmulation/res/values/template-dimens.xml
diff --git a/samples/browseable/Basic/res/values/styles.xml b/samples/browseable/CardEmulation/res/values/template-styles.xml
similarity index 100%
copy from samples/browseable/Basic/res/values/styles.xml
copy to samples/browseable/CardEmulation/res/values/template-styles.xml
diff --git a/samples/browseable/CardEmulation/res/xml/aid_list.xml b/samples/browseable/CardEmulation/res/xml/aid_list.xml
new file mode 100644
index 0000000..15ed754
--- /dev/null
+++ b/samples/browseable/CardEmulation/res/xml/aid_list.xml
@@ -0,0 +1,64 @@
+<?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.
+-->
+
+<!-- This file defines which AIDs this application should emulate cards for.
+
+     Vendor-specific AIDs should always start with an "F", according to the ISO 7816 spec. We
+     recommended vendor-specific AIDs be at least 6 characters long, to provide sufficient
+     uniqueness. Note, however, that longer AIDs may impose a burden on non-Android NFC terminals.
+     AIDs may not exceed 32 characters (16 bytes).
+
+     Additionally, AIDs must always contain an even number of characters, in hexadecimal format.
+
+     In order to avoid prompting the user to select which service they want to use when the device
+     is scanned, this app must be selected as the default handler for an AID group by the user, or
+     the terminal must select *all* AIDs defined in the category simultaneously ("exact match").
+-->
+<!-- BEGIN_INCLUDE(CardEmulationXML) -->
+<host-apdu-service xmlns:android="http://schemas.android.com/apk/res/android"
+    android:description="@string/service_name"
+    android:requireDeviceUnlock="false">
+    <!--
+    If category="payment" is used for any aid-groups, you must also add an android:apduServiceBanner
+    attribute above, like so:
+
+    android:apduServiceBanner="@drawable/settings_banner"
+
+     apduServiceBanner should be 260x96 dp. In pixels, that works out to...
+       - drawable-xxhdpi: 780x288 px
+       - drawable-xhdpi:  520x192 px
+       - drawable-hdpi:   390x144 px
+       - drawable-mdpi:   260x96  px
+
+    The apduServiceBanner is displayed in the "Tap & Pay" menu in the system Settings app, and
+    is only displayed for apps which implement the "payment" AID category.
+
+    Since this sample is implementing a non-standard card type (a loyalty card, specifically), we
+    do not need to define a banner.
+
+    Important: category="payment" should only be used for industry-standard payment cards. If you are
+        implementing a closed-loop payment system (e.g. stored value cards for a specific merchant
+        or transit system), use category="other". This is because only one "payment" card may be
+        active at a time, whereas all "other" cards are active simultaneously (subject to AID
+        dispatch).
+    -->
+
+    <aid-group android:description="@string/card_title" android:category="other">
+        <aid-filter android:name="F222222222"/>
+    </aid-group>
+<!-- END_INCLUDE(CardEmulationXML) -->
+</host-apdu-service>
diff --git a/samples/browseable/CardEmulation/src/com.example.android.cardemulation/AccountStorage.java b/samples/browseable/CardEmulation/src/com.example.android.cardemulation/AccountStorage.java
new file mode 100644
index 0000000..e02d480
--- /dev/null
+++ b/samples/browseable/CardEmulation/src/com.example.android.cardemulation/AccountStorage.java
@@ -0,0 +1,58 @@
+/*
+ * 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.cardemulation;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.preference.PreferenceManager;
+import android.util.Log;
+
+/**
+ * Utility class for persisting account numbers to disk.
+ *
+ * <p>The default SharedPreferences instance is used as the backing storage. Values are cached
+ * in memory for performance.
+ *
+ * <p>This class is thread-safe.
+ */
+public class AccountStorage {
+    private static final String PREF_ACCOUNT_NUMBER = "account_number";
+    private static final String DEFAULT_ACCOUNT_NUMBER = "00000000";
+    private static final String TAG = "AccountStorage";
+    private static String sAccount = null;
+    private static final Object sAccountLock = new Object();
+
+    public static void SetAccount(Context c, String s) {
+        synchronized(sAccountLock) {
+            Log.i(TAG, "Setting account number: " + s);
+            SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(c);
+            prefs.edit().putString(PREF_ACCOUNT_NUMBER, s).commit();
+            sAccount = s;
+        }
+    }
+
+    public static String GetAccount(Context c) {
+        synchronized (sAccountLock) {
+            if (sAccount == null) {
+                SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(c);
+                String account = prefs.getString(PREF_ACCOUNT_NUMBER, DEFAULT_ACCOUNT_NUMBER);
+                sAccount = account;
+            }
+            return sAccount;
+        }
+    }
+}
diff --git a/samples/browseable/CardEmulation/src/com.example.android.cardemulation/CardEmulationFragment.java b/samples/browseable/CardEmulation/src/com.example.android.cardemulation/CardEmulationFragment.java
new file mode 100644
index 0000000..f26efda
--- /dev/null
+++ b/samples/browseable/CardEmulation/src/com.example.android.cardemulation/CardEmulationFragment.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.cardemulation;
+
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.text.Editable;
+import android.text.TextWatcher;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.EditText;
+
+/**
+ * Generic UI for sample discovery.
+ */
+public class CardEmulationFragment extends Fragment {
+
+    public static final String TAG = "CardEmulationFragment";
+
+    /** Called when sample is created. Displays generic UI with welcome text. */
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+    }
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+                             Bundle savedInstanceState) {
+        // Inflate the layout for this fragment
+        View v = inflater.inflate(R.layout.main_fragment, container, false);
+        EditText account = (EditText) v.findViewById(R.id.card_account_field);
+        account.setText(AccountStorage.GetAccount(getActivity()));
+        account.addTextChangedListener(new AccountUpdater());
+        return v;
+    }
+
+
+    private class AccountUpdater implements TextWatcher {
+        @Override
+        public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+            // Not implemented.
+        }
+
+        @Override
+        public void onTextChanged(CharSequence s, int start, int before, int count) {
+            // Not implemented.
+        }
+
+        @Override
+        public void afterTextChanged(Editable s) {
+            String account = s.toString();
+            AccountStorage.SetAccount(getActivity(), account);
+        }
+    }
+}
diff --git a/samples/browseable/CardEmulation/src/com.example.android.cardemulation/CardService.java b/samples/browseable/CardEmulation/src/com.example.android.cardemulation/CardService.java
new file mode 100644
index 0000000..a409d28
--- /dev/null
+++ b/samples/browseable/CardEmulation/src/com.example.android.cardemulation/CardService.java
@@ -0,0 +1,173 @@
+/*
+ * 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.cardemulation;
+
+import android.nfc.cardemulation.HostApduService;
+import android.os.Bundle;
+import com.example.android.common.logger.Log;
+
+import java.util.Arrays;
+
+/**
+ * This is a sample APDU Service which demonstrates how to interface with the card emulation support
+ * added in Android 4.4, KitKat.
+ *
+ * <p>This sample replies to any requests sent with the string "Hello World". In real-world
+ * situations, you would need to modify this code to implement your desired communication
+ * protocol.
+ *
+ * <p>This sample will be invoked for any terminals selecting AIDs of 0xF11111111, 0xF22222222, or
+ * 0xF33333333. See src/main/res/xml/aid_list.xml for more details.
+ *
+ * <p class="note">Note: This is a low-level interface. Unlike the NdefMessage many developers
+ * are familiar with for implementing Android Beam in apps, card emulation only provides a
+ * byte-array based communication channel. It is left to developers to implement higher level
+ * protocol support as needed.
+ */
+public class CardService extends HostApduService {
+    private static final String TAG = "CardService";
+    // AID for our loyalty card service.
+    private static final String SAMPLE_LOYALTY_CARD_AID = "F222222222";
+    // ISO-DEP command HEADER for selecting an AID.
+    // Format: [Class | Instruction | Parameter 1 | Parameter 2]
+    private static final String SELECT_APDU_HEADER = "00A40400";
+    // "OK" status word sent in response to SELECT AID command (0x9000)
+    private static final byte[] SELECT_OK_SW = HexStringToByteArray("9000");
+    // "UNKNOWN" status word sent in response to invalid APDU command (0x0000)
+    private static final byte[] UNKNOWN_CMD_SW = HexStringToByteArray("0000");
+    private static final byte[] SELECT_APDU = BuildSelectApdu(SAMPLE_LOYALTY_CARD_AID);
+
+    /**
+     * Called if the connection to the NFC card is lost, in order to let the application know the
+     * cause for the disconnection (either a lost link, or another AID being selected by the
+     * reader).
+     *
+     * @param reason Either DEACTIVATION_LINK_LOSS or DEACTIVATION_DESELECTED
+     */
+    @Override
+    public void onDeactivated(int reason) { }
+
+    /**
+     * This method will be called when a command APDU has been received from a remote device. A
+     * response APDU can be provided directly by returning a byte-array in this method. In general
+     * response APDUs must be sent as quickly as possible, given the fact that the user is likely
+     * holding his device over an NFC reader when this method is called.
+     *
+     * <p class="note">If there are multiple services that have registered for the same AIDs in
+     * their meta-data entry, you will only get called if the user has explicitly selected your
+     * service, either as a default or just for the next tap.
+     *
+     * <p class="note">This method is running on the main thread of your application. If you
+     * cannot return a response APDU immediately, return null and use the {@link
+     * #sendResponseApdu(byte[])} method later.
+     *
+     * @param commandApdu The APDU that received from the remote device
+     * @param extras A bundle containing extra data. May be null.
+     * @return a byte-array containing the response APDU, or null if no response APDU can be sent
+     * at this point.
+     */
+    // BEGIN_INCLUDE(processCommandApdu)
+    @Override
+    public byte[] processCommandApdu(byte[] commandApdu, Bundle extras) {
+        Log.i(TAG, "Received APDU: " + ByteArrayToHexString(commandApdu));
+        // If the APDU matches the SELECT AID command for this service,
+        // send the loyalty card account number, followed by a SELECT_OK status trailer (0x9000).
+        if (Arrays.equals(SELECT_APDU, commandApdu)) {
+            String account = AccountStorage.GetAccount(this);
+            byte[] accountBytes = account.getBytes();
+            Log.i(TAG, "Sending account number: " + account);
+            return ConcatArrays(accountBytes, SELECT_OK_SW);
+        } else {
+            return UNKNOWN_CMD_SW;
+        }
+    }
+    // END_INCLUDE(processCommandApdu)
+
+    /**
+     * Build APDU for SELECT AID command. This command indicates which service a reader is
+     * interested in communicating with. See ISO 7816-4.
+     *
+     * @param aid Application ID (AID) to select
+     * @return APDU for SELECT AID command
+     */
+    public static byte[] BuildSelectApdu(String aid) {
+        // Format: [CLASS | INSTRUCTION | PARAMETER 1 | PARAMETER 2 | LENGTH | DATA]
+        return HexStringToByteArray(SELECT_APDU_HEADER + String.format("%02X",
+                aid.length() / 2) + aid);
+    }
+
+    /**
+     * Utility method to convert a byte array to a hexadecimal string.
+     *
+     * @param bytes Bytes to convert
+     * @return String, containing hexadecimal representation.
+     */
+    public static String ByteArrayToHexString(byte[] bytes) {
+        final char[] hexArray = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
+        char[] hexChars = new char[bytes.length * 2]; // Each byte has two hex characters (nibbles)
+        int v;
+        for (int j = 0; j < bytes.length; j++) {
+            v = bytes[j] & 0xFF; // Cast bytes[j] to int, treating as unsigned value
+            hexChars[j * 2] = hexArray[v >>> 4]; // Select hex character from upper nibble
+            hexChars[j * 2 + 1] = hexArray[v & 0x0F]; // Select hex character from lower nibble
+        }
+        return new String(hexChars);
+    }
+
+    /**
+     * Utility method to convert a hexadecimal string to a byte string.
+     *
+     * <p>Behavior with input strings containing non-hexadecimal characters is undefined.
+     *
+     * @param s String containing hexadecimal characters to convert
+     * @return Byte array generated from input
+     * @throws java.lang.IllegalArgumentException if input length is incorrect
+     */
+    public static byte[] HexStringToByteArray(String s) throws IllegalArgumentException {
+        int len = s.length();
+        if (len % 2 == 1) {
+            throw new IllegalArgumentException("Hex string must have even number of characters");
+        }
+        byte[] data = new byte[len / 2]; // Allocate 1 byte per 2 hex characters
+        for (int i = 0; i < len; i += 2) {
+            // Convert each character into a integer (base-16), then bit-shift into place
+            data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
+                    + Character.digit(s.charAt(i+1), 16));
+        }
+        return data;
+    }
+
+    /**
+     * Utility method to concatenate two byte arrays.
+     * @param first First array
+     * @param rest Any remaining arrays
+     * @return Concatenated copy of input arrays
+     */
+    public static byte[] ConcatArrays(byte[] first, byte[]... rest) {
+        int totalLength = first.length;
+        for (byte[] array : rest) {
+            totalLength += array.length;
+        }
+        byte[] result = Arrays.copyOf(first, totalLength);
+        int offset = first.length;
+        for (byte[] array : rest) {
+            System.arraycopy(array, 0, result, offset, array.length);
+            offset += array.length;
+        }
+        return result;
+    }
+}
diff --git a/samples/browseable/CardEmulation/src/com.example.android.cardemulation/MainActivity.java b/samples/browseable/CardEmulation/src/com.example.android.cardemulation/MainActivity.java
new file mode 100644
index 0000000..0515609
--- /dev/null
+++ b/samples/browseable/CardEmulation/src/com.example.android.cardemulation/MainActivity.java
@@ -0,0 +1,110 @@
+/*
+* Copyright 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.cardemulation;
+
+import android.os.Bundle;
+import android.support.v4.app.FragmentTransaction;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.widget.ViewAnimator;
+
+import com.example.android.common.activities.SampleActivityBase;
+import com.example.android.common.logger.Log;
+import com.example.android.common.logger.LogFragment;
+import com.example.android.common.logger.LogWrapper;
+import com.example.android.common.logger.MessageOnlyLogFilter;
+
+/**
+ * A simple launcher activity containing a summary sample description, sample log and a custom
+ * {@link android.support.v4.app.Fragment} which can display a view.
+ * <p>
+ * For devices with displays with a width of 720dp or greater, the sample log is always visible,
+ * on other devices it's visibility is controlled by an item on the Action Bar.
+ */
+public class MainActivity extends SampleActivityBase {
+
+    public static final String TAG = "MainActivity";
+
+    // Whether the Log Fragment is currently shown
+    private boolean mLogShown;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_main);
+
+        FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
+        CardEmulationFragment fragment = new CardEmulationFragment();
+        transaction.replace(R.id.sample_content_fragment, fragment);
+        transaction.commit();
+    }
+
+    @Override
+    public boolean onCreateOptionsMenu(Menu menu) {
+        getMenuInflater().inflate(R.menu.main, menu);
+        return true;
+    }
+
+    @Override
+    public boolean onPrepareOptionsMenu(Menu menu) {
+        MenuItem logToggle = menu.findItem(R.id.menu_toggle_log);
+        logToggle.setVisible(findViewById(R.id.sample_output) instanceof ViewAnimator);
+        logToggle.setTitle(mLogShown ? R.string.sample_hide_log : R.string.sample_show_log);
+
+        return super.onPrepareOptionsMenu(menu);
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        switch(item.getItemId()) {
+            case R.id.menu_toggle_log:
+                mLogShown = !mLogShown;
+                ViewAnimator output = (ViewAnimator) findViewById(R.id.sample_output);
+                if (mLogShown) {
+                    output.setDisplayedChild(1);
+                } else {
+                    output.setDisplayedChild(0);
+                }
+                supportInvalidateOptionsMenu();
+                return true;
+        }
+        return super.onOptionsItemSelected(item);
+    }
+
+    /** Create a chain of targets that will receive log data */
+    @Override
+    public void initializeLogging() {
+        // Wraps Android's native log framework.
+        LogWrapper logWrapper = new LogWrapper();
+        // Using Log, front-end to the logging chain, emulates android.util.log method signatures.
+        Log.setLogNode(logWrapper);
+
+        // Filter strips out everything except the message text.
+        MessageOnlyLogFilter msgFilter = new MessageOnlyLogFilter();
+        logWrapper.setNext(msgFilter);
+
+        // On screen logging via a fragment with a TextView.
+        LogFragment logFragment = (LogFragment) getSupportFragmentManager()
+                .findFragmentById(R.id.log_fragment);
+        msgFilter.setNext(logFragment.getLogView());
+
+        Log.i(TAG, "Ready");
+    }
+}
diff --git a/samples/browseable/repeatingAlarm/src/com.example.android.common/activities/SampleActivityBase.java b/samples/browseable/CardEmulation/src/com.example.android.common/activities/SampleActivityBase.java
similarity index 100%
copy from samples/browseable/repeatingAlarm/src/com.example.android.common/activities/SampleActivityBase.java
copy to samples/browseable/CardEmulation/src/com.example.android.common/activities/SampleActivityBase.java
diff --git a/samples/browseable/repeatingAlarm/src/com.example.android.common/logger/Log.java b/samples/browseable/CardEmulation/src/com.example.android.common/logger/Log.java
similarity index 100%
copy from samples/browseable/repeatingAlarm/src/com.example.android.common/logger/Log.java
copy to samples/browseable/CardEmulation/src/com.example.android.common/logger/Log.java
diff --git a/samples/browseable/repeatingAlarm/src/com.example.android.common/logger/LogFragment.java b/samples/browseable/CardEmulation/src/com.example.android.common/logger/LogFragment.java
similarity index 100%
copy from samples/browseable/repeatingAlarm/src/com.example.android.common/logger/LogFragment.java
copy to samples/browseable/CardEmulation/src/com.example.android.common/logger/LogFragment.java
diff --git a/samples/browseable/repeatingAlarm/src/com.example.android.common/logger/LogNode.java b/samples/browseable/CardEmulation/src/com.example.android.common/logger/LogNode.java
similarity index 100%
copy from samples/browseable/repeatingAlarm/src/com.example.android.common/logger/LogNode.java
copy to samples/browseable/CardEmulation/src/com.example.android.common/logger/LogNode.java
diff --git a/samples/browseable/repeatingAlarm/src/com.example.android.common/logger/LogView.java b/samples/browseable/CardEmulation/src/com.example.android.common/logger/LogView.java
similarity index 100%
copy from samples/browseable/repeatingAlarm/src/com.example.android.common/logger/LogView.java
copy to samples/browseable/CardEmulation/src/com.example.android.common/logger/LogView.java
diff --git a/samples/browseable/repeatingAlarm/src/com.example.android.common/logger/LogWrapper.java b/samples/browseable/CardEmulation/src/com.example.android.common/logger/LogWrapper.java
similarity index 100%
copy from samples/browseable/repeatingAlarm/src/com.example.android.common/logger/LogWrapper.java
copy to samples/browseable/CardEmulation/src/com.example.android.common/logger/LogWrapper.java
diff --git a/samples/browseable/repeatingAlarm/src/com.example.android.common/logger/MessageOnlyLogFilter.java b/samples/browseable/CardEmulation/src/com.example.android.common/logger/MessageOnlyLogFilter.java
similarity index 100%
copy from samples/browseable/repeatingAlarm/src/com.example.android.common/logger/MessageOnlyLogFilter.java
copy to samples/browseable/CardEmulation/src/com.example.android.common/logger/MessageOnlyLogFilter.java
diff --git a/samples/browseable/CardReader/AndroidManifest.xml b/samples/browseable/CardReader/AndroidManifest.xml
new file mode 100644
index 0000000..a8ebd13
--- /dev/null
+++ b/samples/browseable/CardReader/AndroidManifest.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 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.cardreader"
+    android:versionCode="1"
+    android:versionName="1.0">
+
+    <!-- NFC Reader Mode was added in API 19. -->
+    <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="19" />
+    <uses-permission android:name="android.permission.NFC" />
+    <uses-feature android:name="android.hardware.nfc" android:required="true" />
+
+    <application android:allowBackup="true"
+        android:label="@string/app_name"
+        android:icon="@drawable/ic_launcher"
+        android:theme="@style/AppTheme">
+        <activity android:name=".MainActivity"
+                  android:label="@string/app_name"
+                  android:launchMode="singleTop">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+
+            <!-- NFC-related intent filter. Allows application to handle messages from any
+                 NFC-A devices discovered. Other Android devices are required to support NFC-A.
+                 See: res/xml/nfc_tech_filter.xml -->
+            <intent-filter>
+                <action android:name="android.nfc.action.TECH_DISCOVERED" />
+            </intent-filter>
+            <meta-data
+                android:name="android.nfc.action.TECH_DISCOVERED"
+                android:resource="@xml/nfc_tech_filter" />
+        </activity>
+    </application>
+
+
+</manifest>
diff --git a/samples/browseable/CardReader/_index.jd b/samples/browseable/CardReader/_index.jd
new file mode 100644
index 0000000..9ba051e
--- /dev/null
+++ b/samples/browseable/CardReader/_index.jd
@@ -0,0 +1,20 @@
+
+
+
+page.tags="CardReader"
+sample.group=Connectivity
+@jd:body
+
+<p>
+  This sample demonstrates how to implement a low-level NFC card reader, for
+  reading cards that do not contain NDEF or Android Beam data. This sample is
+  designed to read the virtual loyalty card implemented in the <a href=
+  "{@docRoot}samples/CardEmulation/index.html">CardEmulation</a> sample.
+</p>
+
+<p>
+  In particular, this sample demonstrates how to disable Android Beam, select
+  which AIDs the reader is interested in, and establish communication with the
+  card. See <a href="{@docRoot}guide/topics/connectivity/nfc/hce.html">Host-based
+  Card Emulation</a> for more information on the HCE APIs.
+</p>
diff --git a/samples/browseable/CardReader/res/drawable-hdpi/ic_launcher.png b/samples/browseable/CardReader/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..9114e44
--- /dev/null
+++ b/samples/browseable/CardReader/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/Basic/res/drawable-hdpi/tile.9.png b/samples/browseable/CardReader/res/drawable-hdpi/tile.9.png
similarity index 100%
copy from samples/browseable/Basic/res/drawable-hdpi/tile.9.png
copy to samples/browseable/CardReader/res/drawable-hdpi/tile.9.png
Binary files differ
diff --git a/samples/browseable/CardReader/res/drawable-mdpi/ic_launcher.png b/samples/browseable/CardReader/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..604fbd8
--- /dev/null
+++ b/samples/browseable/CardReader/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/CardReader/res/drawable-xhdpi/ic_launcher.png b/samples/browseable/CardReader/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..9e58d22
--- /dev/null
+++ b/samples/browseable/CardReader/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/CardReader/res/drawable-xxhdpi/card_background.png b/samples/browseable/CardReader/res/drawable-xxhdpi/card_background.png
new file mode 100644
index 0000000..86a7ba7
--- /dev/null
+++ b/samples/browseable/CardReader/res/drawable-xxhdpi/card_background.png
Binary files differ
diff --git a/samples/browseable/CardReader/res/drawable-xxhdpi/ic_launcher.png b/samples/browseable/CardReader/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..c550c04
--- /dev/null
+++ b/samples/browseable/CardReader/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/CardReader/res/layout-w720dp/activity_main.xml b/samples/browseable/CardReader/res/layout-w720dp/activity_main.xml
new file mode 100755
index 0000000..c9a52f6
--- /dev/null
+++ b/samples/browseable/CardReader/res/layout-w720dp/activity_main.xml
@@ -0,0 +1,73 @@
+<!--
+  Copyright 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"
+      android:orientation="horizontal"
+      android:layout_width="match_parent"
+      android:layout_height="match_parent"
+      android:id="@+id/sample_main_layout">
+
+    <LinearLayout
+          android:id="@+id/sample_output"
+          android:layout_width="0px"
+          android:layout_height="match_parent"
+          android:layout_weight="1"
+          android:orientation="vertical">
+
+        <FrameLayout
+              style="@style/Widget.SampleMessageTile"
+              android:layout_width="match_parent"
+              android:layout_height="wrap_content">
+
+            <TextView
+                  style="@style/Widget.SampleMessage"
+                  android:layout_width="match_parent"
+                  android:layout_height="wrap_content"
+                  android:paddingLeft="@dimen/margin_medium"
+                  android:paddingRight="@dimen/margin_medium"
+                  android:paddingTop="@dimen/margin_large"
+                  android:paddingBottom="@dimen/margin_large"
+                  android:text="@string/intro_message" />
+        </FrameLayout>
+
+        <View
+              android:layout_width="match_parent"
+              android:layout_height="1dp"
+              android:background="@android:color/darker_gray" />
+
+        <fragment
+              android:name="com.example.android.common.logger.LogFragment"
+              android:id="@+id/log_fragment"
+              android:layout_width="match_parent"
+              android:layout_height="0px"
+              android:layout_weight="1" />
+
+    </LinearLayout>
+
+    <View
+          android:layout_width="1dp"
+          android:layout_height="match_parent"
+          android:background="@android:color/darker_gray" />
+
+    <FrameLayout
+          android:id="@+id/sample_content_fragment"
+          android:layout_weight="2"
+          android:layout_width="0px"
+          android:layout_height="match_parent" />
+
+</LinearLayout>
+
+
diff --git a/samples/browseable/CardReader/res/layout/activity_main.xml b/samples/browseable/CardReader/res/layout/activity_main.xml
new file mode 100755
index 0000000..1ae4f98
--- /dev/null
+++ b/samples/browseable/CardReader/res/layout/activity_main.xml
@@ -0,0 +1,65 @@
+<!--
+  Copyright 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"
+      android:orientation="vertical"
+      android:layout_width="match_parent"
+      android:layout_height="match_parent"
+      android:id="@+id/sample_main_layout">
+
+    <ViewAnimator
+          android:id="@+id/sample_output"
+          android:layout_width="match_parent"
+          android:layout_height="0px"
+          android:layout_weight="1">
+
+        <ScrollView
+              style="@style/Widget.SampleMessageTile"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent">
+
+            <TextView
+                  style="@style/Widget.SampleMessage"
+                  android:layout_width="match_parent"
+                  android:layout_height="wrap_content"
+                  android:paddingLeft="@dimen/horizontal_page_margin"
+                  android:paddingRight="@dimen/horizontal_page_margin"
+                  android:paddingTop="@dimen/vertical_page_margin"
+                  android:paddingBottom="@dimen/vertical_page_margin"
+                  android:text="@string/intro_message" />
+        </ScrollView>
+
+        <fragment
+              android:name="com.example.android.common.logger.LogFragment"
+              android:id="@+id/log_fragment"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent" />
+
+    </ViewAnimator>
+
+    <View
+          android:layout_width="match_parent"
+          android:layout_height="1dp"
+          android:background="@android:color/darker_gray" />
+
+    <FrameLayout
+          android:id="@+id/sample_content_fragment"
+          android:layout_weight="2"
+          android:layout_width="match_parent"
+          android:layout_height="0px" />
+
+</LinearLayout>
+
diff --git a/samples/browseable/CardReader/res/layout/main_fragment.xml b/samples/browseable/CardReader/res/layout/main_fragment.xml
new file mode 100644
index 0000000..1e3886c
--- /dev/null
+++ b/samples/browseable/CardReader/res/layout/main_fragment.xml
@@ -0,0 +1,64 @@
+<!--
+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="380dp"
+    android:layout_height="242.25dp"
+    android:layout_gravity="center"
+    android:layout_margin="20dp">
+    <ImageView
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:src="@drawable/card_background"
+        />
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:orientation="vertical"
+        android:padding="20dp"
+        android:layout_gravity="center"
+        android:clickable="true">
+        <TextView
+            android:id="@+id/card_title"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/card_title"
+            android:fontFamily="sans-serif-condensed"
+            android:textStyle="bold"
+            android:textSize="32dp"
+            />
+        <TextView
+            android:id="@+id/card_account_label"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/account_number"
+            android:fontFamily="sans-serif"
+            android:textStyle="bold"
+            android:textSize="18dp"
+            android:layout_marginTop="40dp"
+            />
+        <TextView
+            android:id="@+id/card_account_field"
+            android:width="360dp"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:fontFamily="sans-serif-condensed"
+            android:textStyle="bold"
+            android:textSize="42dp"
+            android:singleLine="true"
+            />
+    </LinearLayout>
+</FrameLayout>
\ No newline at end of file
diff --git a/samples/training/bitmapfun/BitmapFun/src/main/res/values/colors.xml b/samples/browseable/CardReader/res/menu/main.xml
similarity index 60%
copy from samples/training/bitmapfun/BitmapFun/src/main/res/values/colors.xml
copy to samples/browseable/CardReader/res/menu/main.xml
index 7e4a4fe..b49c2c5 100644
--- a/samples/training/bitmapfun/BitmapFun/src/main/res/values/colors.xml
+++ b/samples/browseable/CardReader/res/menu/main.xml
@@ -1,23 +1,21 @@
-<?xml version="1.0" encoding="utf-8"?>
 <!--
-  Copyright (C) 2012 The Android Open Source Project
+  Copyright 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
+      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>
-
-    <color name="grid_state_pressed">#BB7dbcd3</color>
-    <color name="grid_state_focused">#777dbcd3</color>
-
-</resources>
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:id="@+id/menu_toggle_log"
+          android:showAsAction="always"
+          android:title="@string/sample_show_log" />
+</menu>
diff --git a/samples/browseable/DoneBar/res/values-sw600dp/dimens.xml b/samples/browseable/CardReader/res/values-sw600dp/template-dimens.xml
similarity index 100%
copy from samples/browseable/DoneBar/res/values-sw600dp/dimens.xml
copy to samples/browseable/CardReader/res/values-sw600dp/template-dimens.xml
diff --git a/samples/browseable/DoneBar/res/values-sw600dp/styles.xml b/samples/browseable/CardReader/res/values-sw600dp/template-styles.xml
similarity index 100%
copy from samples/browseable/DoneBar/res/values-sw600dp/styles.xml
copy to samples/browseable/CardReader/res/values-sw600dp/template-styles.xml
diff --git a/samples/browseable/repeatingAlarm/res/values/base-strings.xml b/samples/browseable/CardReader/res/values/base-strings.xml
similarity index 60%
copy from samples/browseable/repeatingAlarm/res/values/base-strings.xml
copy to samples/browseable/CardReader/res/values/base-strings.xml
index c11b89b..ac12480 100644
--- a/samples/browseable/repeatingAlarm/res/values/base-strings.xml
+++ b/samples/browseable/CardReader/res/values/base-strings.xml
@@ -18,13 +18,17 @@
 
 
 <resources>
-    <string name="app_name">repeatingAlarm</string>
+    <string name="app_name">CardReader</string>
     <string name="intro_message">
         <![CDATA[
         
             
-                Introductory text that explains what the sample is intended to demonstrate. Edit
-                in template-params.xml.
+            This sample demonstrates how to implement a low-level NFC card reader, for reading cards
+            that do not contain NDEF or Android Beam data. This sample is designed to read the virtual
+            loyalty card implemented in the "CardEmulation" sample.\n\n
+
+            In particular, this sample demonstrates how to disable Android Beam, select which AIDs the
+            reader is interested, and establish communication with the card
             
         
         ]]>
diff --git a/samples/training/bitmapfun/BitmapFun/src/main/res/values/colors.xml b/samples/browseable/CardReader/res/values/strings.xml
old mode 100644
new mode 100755
similarity index 67%
copy from samples/training/bitmapfun/BitmapFun/src/main/res/values/colors.xml
copy to samples/browseable/CardReader/res/values/strings.xml
index 7e4a4fe..7b9d9ec
--- a/samples/training/bitmapfun/BitmapFun/src/main/res/values/colors.xml
+++ b/samples/browseable/CardReader/res/values/strings.xml
@@ -1,12 +1,11 @@
-<?xml version="1.0" encoding="utf-8"?>
 <!--
-  Copyright (C) 2012 The Android Open Source Project
+  Copyright 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
+      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,
@@ -14,10 +13,7 @@
   See the License for the specific language governing permissions and
   limitations under the License.
 -->
-
 <resources>
-
-    <color name="grid_state_pressed">#BB7dbcd3</color>
-    <color name="grid_state_focused">#777dbcd3</color>
-
+    <string name="sample_show_log">Show Log</string>
+    <string name="sample_hide_log">Hide Log</string>
 </resources>
diff --git a/samples/browseable/DoneBar/res/values/dimens.xml b/samples/browseable/CardReader/res/values/template-dimens.xml
similarity index 100%
copy from samples/browseable/DoneBar/res/values/dimens.xml
copy to samples/browseable/CardReader/res/values/template-dimens.xml
diff --git a/samples/browseable/TextSwitcher/res/values/styles.xml b/samples/browseable/CardReader/res/values/template-styles.xml
similarity index 100%
copy from samples/browseable/TextSwitcher/res/values/styles.xml
copy to samples/browseable/CardReader/res/values/template-styles.xml
diff --git a/samples/browseable/CardReader/res/xml/nfc_tech_filter.xml b/samples/browseable/CardReader/res/xml/nfc_tech_filter.xml
new file mode 100644
index 0000000..dcfc979
--- /dev/null
+++ b/samples/browseable/CardReader/res/xml/nfc_tech_filter.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- This file is used as part of the filter for incoming NFC TECH_DISCOVERED intents. -->
+<resources xmlns:android="http://schemas.android.com/apk/res/android">
+    <!-- Android's host card emulation feature only supports the IsoDep protocol. -->
+    <tech-list>
+        <tech>android.nfc.tech.IsoDep</tech>
+    </tech-list>
+</resources>
\ No newline at end of file
diff --git a/samples/browseable/CardReader/src/com.example.android.cardreader/CardReaderFragment.java b/samples/browseable/CardReader/src/com.example.android.cardreader/CardReaderFragment.java
new file mode 100644
index 0000000..3f27e9b
--- /dev/null
+++ b/samples/browseable/CardReader/src/com.example.android.cardreader/CardReaderFragment.java
@@ -0,0 +1,109 @@
+/*
+ * 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.cardreader;
+
+import android.app.Activity;
+import android.nfc.NfcAdapter;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import com.example.android.common.logger.Log;
+
+/**
+ * Generic UI for sample discovery.
+ */
+public class CardReaderFragment extends Fragment implements LoyaltyCardReader.AccountCallback {
+
+    public static final String TAG = "CardReaderFragment";
+    // Recommend NfcAdapter flags for reading from other Android devices. Indicates that this
+    // activity is interested in NFC-A devices (including other Android devices), and that the
+    // system should not check for the presence of NDEF-formatted data (e.g. Android Beam).
+    public static int READER_FLAGS =
+            NfcAdapter.FLAG_READER_NFC_A | NfcAdapter.FLAG_READER_SKIP_NDEF_CHECK;
+    public LoyaltyCardReader mLoyaltyCardReader;
+    private TextView mAccountField;
+
+    /** Called when sample is created. Displays generic UI with welcome text. */
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+    }
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+                             Bundle savedInstanceState) {
+        // Inflate the layout for this fragment
+        View v = inflater.inflate(R.layout.main_fragment, container, false);
+        if (v != null) {
+            mAccountField = (TextView) v.findViewById(R.id.card_account_field);
+            mAccountField.setText("Waiting...");
+
+            mLoyaltyCardReader = new LoyaltyCardReader(this);
+
+            // Disable Android Beam and register our card reader callback
+            enableReaderMode();
+        }
+
+        return v;
+    }
+
+    @Override
+    public void onPause() {
+        super.onPause();
+        disableReaderMode();
+    }
+
+    @Override
+    public void onResume() {
+        super.onResume();
+        enableReaderMode();
+    }
+
+    private void enableReaderMode() {
+        Log.i(TAG, "Enabling reader mode");
+        Activity activity = getActivity();
+        NfcAdapter nfc = NfcAdapter.getDefaultAdapter(activity);
+        if (nfc != null) {
+            nfc.enableReaderMode(activity, mLoyaltyCardReader, READER_FLAGS, null);
+        }
+    }
+
+    private void disableReaderMode() {
+        Log.i(TAG, "Disabling reader mode");
+        Activity activity = getActivity();
+        NfcAdapter nfc = NfcAdapter.getDefaultAdapter(activity);
+        if (nfc != null) {
+            nfc.disableReaderMode(activity);
+        }
+    }
+
+    @Override
+    public void onAccountReceived(final String account) {
+        // This callback is run on a background thread, but updates to UI elements must be performed
+        // on the UI thread.
+        getActivity().runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mAccountField.setText(account);
+            }
+        });
+    }
+}
diff --git a/samples/browseable/CardReader/src/com.example.android.cardreader/LoyaltyCardReader.java b/samples/browseable/CardReader/src/com.example.android.cardreader/LoyaltyCardReader.java
new file mode 100644
index 0000000..c29bdfd
--- /dev/null
+++ b/samples/browseable/CardReader/src/com.example.android.cardreader/LoyaltyCardReader.java
@@ -0,0 +1,149 @@
+/*
+ * 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.cardreader;
+
+import android.nfc.NfcAdapter;
+import android.nfc.Tag;
+import android.nfc.tech.IsoDep;
+
+import com.example.android.common.logger.Log;
+
+import java.io.IOException;
+import java.lang.ref.WeakReference;
+import java.util.Arrays;
+
+/**
+ * Callback class, invoked when an NFC card is scanned while the device is running in reader mode.
+ *
+ * Reader mode can be invoked by calling NfcAdapter
+ */
+public class LoyaltyCardReader implements NfcAdapter.ReaderCallback {
+    private static final String TAG = "LoyaltyCardReader";
+    // AID for our loyalty card service.
+    private static final String SAMPLE_LOYALTY_CARD_AID = "F222222222";
+    // ISO-DEP command HEADER for selecting an AID.
+    // Format: [Class | Instruction | Parameter 1 | Parameter 2]
+    private static final String SELECT_APDU_HEADER = "00A40400";
+    // "OK" status word sent in response to SELECT AID command (0x9000)
+    private static final byte[] SELECT_OK_SW = {(byte) 0x90, (byte) 0x00};
+
+    // Weak reference to prevent retain loop. mAccountCallback is responsible for exiting
+    // foreground mode before it becomes invalid (e.g. during onPause() or onStop()).
+    private WeakReference<AccountCallback> mAccountCallback;
+
+    public interface AccountCallback {
+        public void onAccountReceived(String account);
+    }
+
+    public LoyaltyCardReader(AccountCallback accountCallback) {
+        mAccountCallback = new WeakReference<AccountCallback>(accountCallback);
+    }
+
+    /**
+     * Callback when a new tag is discovered by the system.
+     *
+     * <p>Communication with the card should take place here.
+     *
+     * @param tag Discovered tag
+     */
+    @Override
+    public void onTagDiscovered(Tag tag) {
+        Log.i(TAG, "New tag discovered");
+        // Android's Host-based Card Emulation (HCE) feature implements the ISO-DEP (ISO 14443-4)
+        // protocol.
+        //
+        // In order to communicate with a device using HCE, the discovered tag should be processed
+        // using the IsoDep class.
+        IsoDep isoDep = IsoDep.get(tag);
+        if (isoDep != null) {
+            try {
+                // Connect to the remote NFC device
+                isoDep.connect();
+                // Build SELECT AID command for our loyalty card service.
+                // This command tells the remote device which service we wish to communicate with.
+                Log.i(TAG, "Requesting remote AID: " + SAMPLE_LOYALTY_CARD_AID);
+                byte[] command = BuildSelectApdu(SAMPLE_LOYALTY_CARD_AID);
+                // Send command to remote device
+                Log.i(TAG, "Sending: " + ByteArrayToHexString(command));
+                byte[] result = isoDep.transceive(command);
+                // If AID is successfully selected, 0x9000 is returned as the status word (last 2
+                // bytes of the result) by convention. Everything before the status word is
+                // optional payload, which is used here to hold the account number.
+                int resultLength = result.length;
+                byte[] statusWord = {result[resultLength-2], result[resultLength-1]};
+                byte[] payload = Arrays.copyOf(result, resultLength-2);
+                if (Arrays.equals(SELECT_OK_SW, statusWord)) {
+                    // The remote NFC device will immediately respond with its stored account number
+                    String accountNumber = new String(payload, "UTF-8");
+                    Log.i(TAG, "Received: " + accountNumber);
+                    // Inform CardReaderFragment of received account number
+                    mAccountCallback.get().onAccountReceived(accountNumber);
+                }
+            } catch (IOException e) {
+                Log.e(TAG, "Error communicating with card: " + e.toString());
+            }
+        }
+    }
+
+    /**
+     * Build APDU for SELECT AID command. This command indicates which service a reader is
+     * interested in communicating with. See ISO 7816-4.
+     *
+     * @param aid Application ID (AID) to select
+     * @return APDU for SELECT AID command
+     */
+    public static byte[] BuildSelectApdu(String aid) {
+        // Format: [CLASS | INSTRUCTION | PARAMETER 1 | PARAMETER 2 | LENGTH | DATA]
+        return HexStringToByteArray(SELECT_APDU_HEADER + String.format("%02X", aid.length() / 2) + aid);
+    }
+
+    /**
+     * Utility class to convert a byte array to a hexadecimal string.
+     *
+     * @param bytes Bytes to convert
+     * @return String, containing hexadecimal representation.
+     */
+    public static String ByteArrayToHexString(byte[] bytes) {
+        final char[] hexArray = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
+        char[] hexChars = new char[bytes.length * 2];
+        int v;
+        for ( int j = 0; j < bytes.length; j++ ) {
+            v = bytes[j] & 0xFF;
+            hexChars[j * 2] = hexArray[v >>> 4];
+            hexChars[j * 2 + 1] = hexArray[v & 0x0F];
+        }
+        return new String(hexChars);
+    }
+
+    /**
+     * Utility class to convert a hexadecimal string to a byte string.
+     *
+     * <p>Behavior with input strings containing non-hexadecimal characters is undefined.
+     *
+     * @param s String containing hexadecimal characters to convert
+     * @return Byte array generated from input
+     */
+    public static byte[] HexStringToByteArray(String s) {
+        int len = s.length();
+        byte[] data = new byte[len / 2];
+        for (int i = 0; i < len; i += 2) {
+            data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
+                    + Character.digit(s.charAt(i+1), 16));
+        }
+        return data;
+    }
+
+}
diff --git a/samples/browseable/CardReader/src/com.example.android.cardreader/MainActivity.java b/samples/browseable/CardReader/src/com.example.android.cardreader/MainActivity.java
new file mode 100644
index 0000000..e0280e9
--- /dev/null
+++ b/samples/browseable/CardReader/src/com.example.android.cardreader/MainActivity.java
@@ -0,0 +1,110 @@
+/*
+* Copyright 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.cardreader;
+
+import android.os.Bundle;
+import android.support.v4.app.FragmentTransaction;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.widget.ViewAnimator;
+
+import com.example.android.common.activities.SampleActivityBase;
+import com.example.android.common.logger.Log;
+import com.example.android.common.logger.LogFragment;
+import com.example.android.common.logger.LogWrapper;
+import com.example.android.common.logger.MessageOnlyLogFilter;
+
+/**
+ * A simple launcher activity containing a summary sample description, sample log and a custom
+ * {@link android.support.v4.app.Fragment} which can display a view.
+ * <p>
+ * For devices with displays with a width of 720dp or greater, the sample log is always visible,
+ * on other devices it's visibility is controlled by an item on the Action Bar.
+ */
+public class MainActivity extends SampleActivityBase {
+
+    public static final String TAG = "MainActivity";
+
+    // Whether the Log Fragment is currently shown
+    private boolean mLogShown;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_main);
+
+        FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
+        CardReaderFragment fragment = new CardReaderFragment();
+        transaction.replace(R.id.sample_content_fragment, fragment);
+        transaction.commit();
+    }
+
+    @Override
+    public boolean onCreateOptionsMenu(Menu menu) {
+        getMenuInflater().inflate(R.menu.main, menu);
+        return true;
+    }
+
+    @Override
+    public boolean onPrepareOptionsMenu(Menu menu) {
+        MenuItem logToggle = menu.findItem(R.id.menu_toggle_log);
+        logToggle.setVisible(findViewById(R.id.sample_output) instanceof ViewAnimator);
+        logToggle.setTitle(mLogShown ? R.string.sample_hide_log : R.string.sample_show_log);
+
+        return super.onPrepareOptionsMenu(menu);
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        switch(item.getItemId()) {
+            case R.id.menu_toggle_log:
+                mLogShown = !mLogShown;
+                ViewAnimator output = (ViewAnimator) findViewById(R.id.sample_output);
+                if (mLogShown) {
+                    output.setDisplayedChild(1);
+                } else {
+                    output.setDisplayedChild(0);
+                }
+                supportInvalidateOptionsMenu();
+                return true;
+        }
+        return super.onOptionsItemSelected(item);
+    }
+
+    /** Create a chain of targets that will receive log data */
+    @Override
+    public void initializeLogging() {
+        // Wraps Android's native log framework.
+        LogWrapper logWrapper = new LogWrapper();
+        // Using Log, front-end to the logging chain, emulates android.util.log method signatures.
+        Log.setLogNode(logWrapper);
+
+        // Filter strips out everything except the message text.
+        MessageOnlyLogFilter msgFilter = new MessageOnlyLogFilter();
+        logWrapper.setNext(msgFilter);
+
+        // On screen logging via a fragment with a TextView.
+        LogFragment logFragment = (LogFragment) getSupportFragmentManager()
+                .findFragmentById(R.id.log_fragment);
+        msgFilter.setNext(logFragment.getLogView());
+
+        Log.i(TAG, "Ready");
+    }
+}
diff --git a/samples/browseable/repeatingAlarm/src/com.example.android.common/activities/SampleActivityBase.java b/samples/browseable/CardReader/src/com.example.android.common/activities/SampleActivityBase.java
similarity index 100%
copy from samples/browseable/repeatingAlarm/src/com.example.android.common/activities/SampleActivityBase.java
copy to samples/browseable/CardReader/src/com.example.android.common/activities/SampleActivityBase.java
diff --git a/samples/browseable/repeatingAlarm/src/com.example.android.common/logger/Log.java b/samples/browseable/CardReader/src/com.example.android.common/logger/Log.java
similarity index 100%
copy from samples/browseable/repeatingAlarm/src/com.example.android.common/logger/Log.java
copy to samples/browseable/CardReader/src/com.example.android.common/logger/Log.java
diff --git a/samples/browseable/repeatingAlarm/src/com.example.android.common/logger/LogFragment.java b/samples/browseable/CardReader/src/com.example.android.common/logger/LogFragment.java
similarity index 100%
copy from samples/browseable/repeatingAlarm/src/com.example.android.common/logger/LogFragment.java
copy to samples/browseable/CardReader/src/com.example.android.common/logger/LogFragment.java
diff --git a/samples/browseable/repeatingAlarm/src/com.example.android.common/logger/LogNode.java b/samples/browseable/CardReader/src/com.example.android.common/logger/LogNode.java
similarity index 100%
copy from samples/browseable/repeatingAlarm/src/com.example.android.common/logger/LogNode.java
copy to samples/browseable/CardReader/src/com.example.android.common/logger/LogNode.java
diff --git a/samples/browseable/repeatingAlarm/src/com.example.android.common/logger/LogView.java b/samples/browseable/CardReader/src/com.example.android.common/logger/LogView.java
similarity index 100%
copy from samples/browseable/repeatingAlarm/src/com.example.android.common/logger/LogView.java
copy to samples/browseable/CardReader/src/com.example.android.common/logger/LogView.java
diff --git a/samples/browseable/repeatingAlarm/src/com.example.android.common/logger/LogWrapper.java b/samples/browseable/CardReader/src/com.example.android.common/logger/LogWrapper.java
similarity index 100%
copy from samples/browseable/repeatingAlarm/src/com.example.android.common/logger/LogWrapper.java
copy to samples/browseable/CardReader/src/com.example.android.common/logger/LogWrapper.java
diff --git a/samples/browseable/repeatingAlarm/src/com.example.android.common/logger/MessageOnlyLogFilter.java b/samples/browseable/CardReader/src/com.example.android.common/logger/MessageOnlyLogFilter.java
similarity index 100%
copy from samples/browseable/repeatingAlarm/src/com.example.android.common/logger/MessageOnlyLogFilter.java
copy to samples/browseable/CardReader/src/com.example.android.common/logger/MessageOnlyLogFilter.java
diff --git a/samples/browseable/CustomChoiceList/res/values-sw600dp/dimens.xml b/samples/browseable/CustomChoiceList/res/values-sw600dp/template-dimens.xml
similarity index 100%
rename from samples/browseable/CustomChoiceList/res/values-sw600dp/dimens.xml
rename to samples/browseable/CustomChoiceList/res/values-sw600dp/template-dimens.xml
diff --git a/samples/browseable/CustomChoiceList/res/values-sw600dp/styles.xml b/samples/browseable/CustomChoiceList/res/values-sw600dp/template-styles.xml
similarity index 100%
rename from samples/browseable/CustomChoiceList/res/values-sw600dp/styles.xml
rename to samples/browseable/CustomChoiceList/res/values-sw600dp/template-styles.xml
diff --git a/samples/browseable/CustomChoiceList/res/values/dimens.xml b/samples/browseable/CustomChoiceList/res/values/dimens.xml
index 39e710b..c22027e 100644
--- a/samples/browseable/CustomChoiceList/res/values/dimens.xml
+++ b/samples/browseable/CustomChoiceList/res/values/dimens.xml
@@ -16,17 +16,8 @@
 
 <resources>
 
-    <!-- Define standard dimensions to comply with Holo-style grids and rhythm. -->
+    <!-- Meta-dimension that switches on screen size -->
 
-    <dimen name="margin_tiny">4dp</dimen>
-    <dimen name="margin_small">8dp</dimen>
-    <dimen name="margin_medium">16dp</dimen>
-    <dimen name="margin_large">32dp</dimen>
-    <dimen name="margin_huge">64dp</dimen>
-
-    <!-- Semantic definitions -->
-
-    <dimen name="horizontal_page_margin">@dimen/margin_medium</dimen>
-    <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+    <dimen name="page_margin">@dimen/margin_medium</dimen>
 
 </resources>
diff --git a/samples/browseable/CustomChoiceList/res/values/styles.xml b/samples/browseable/CustomChoiceList/res/values/styles.xml
index 404623e..0851a81 100644
--- a/samples/browseable/CustomChoiceList/res/values/styles.xml
+++ b/samples/browseable/CustomChoiceList/res/values/styles.xml
@@ -15,28 +15,14 @@
   -->
 
 <resources>
-
-    <!-- Activity themes -->
-
-    <style name="Theme.Base" parent="android:Theme.Holo.Light" />
-
-    <style name="Theme.Sample" parent="Theme.Base" />
-
-    <style name="AppTheme" parent="Theme.Sample" />
-    <!-- Widget styling -->
-
-    <style name="Widget" />
-
-    <style name="Widget.SampleMessage">
+    <style name="Widget.DescriptionBar">
+        <item name="android:background">#fb3</item>
+        <item name="android:paddingTop">@dimen/margin_medium</item>
+        <item name="android:paddingBottom">@dimen/margin_medium</item>
+        <item name="android:paddingLeft">@dimen/page_margin</item>
+        <item name="android:paddingRight">@dimen/page_margin</item>
         <item name="android:textAppearance">?android:textAppearanceMedium</item>
         <item name="android:lineSpacingMultiplier">1.1</item>
     </style>
 
-    <style name="Widget.SampleMessageTile">
-        <item name="android:background">@drawable/tile</item>
-        <item name="android:shadowColor">#7F000000</item>
-        <item name="android:shadowDy">-3.5</item>
-        <item name="android:shadowRadius">2</item>
-    </style>
-
 </resources>
diff --git a/samples/browseable/AppRestrictions/res/values/dimens.xml b/samples/browseable/CustomChoiceList/res/values/template-dimens.xml
similarity index 100%
copy from samples/browseable/AppRestrictions/res/values/dimens.xml
copy to samples/browseable/CustomChoiceList/res/values/template-dimens.xml
diff --git a/samples/browseable/AppRestrictions/res/values/styles.xml b/samples/browseable/CustomChoiceList/res/values/template-styles.xml
similarity index 100%
copy from samples/browseable/AppRestrictions/res/values/styles.xml
copy to samples/browseable/CustomChoiceList/res/values/template-styles.xml
diff --git a/samples/browseable/CustomNotifications/res/values-sw600dp/dimens.xml b/samples/browseable/CustomNotifications/res/values-sw600dp/template-dimens.xml
similarity index 100%
rename from samples/browseable/CustomNotifications/res/values-sw600dp/dimens.xml
rename to samples/browseable/CustomNotifications/res/values-sw600dp/template-dimens.xml
diff --git a/samples/browseable/CustomNotifications/res/values-sw600dp/styles.xml b/samples/browseable/CustomNotifications/res/values-sw600dp/template-styles.xml
similarity index 100%
rename from samples/browseable/CustomNotifications/res/values-sw600dp/styles.xml
rename to samples/browseable/CustomNotifications/res/values-sw600dp/template-styles.xml
diff --git a/samples/browseable/CustomNotifications/res/values/dimens.xml b/samples/browseable/CustomNotifications/res/values/dimens.xml
index 39e710b..ca1b9e6 100644
--- a/samples/browseable/CustomNotifications/res/values/dimens.xml
+++ b/samples/browseable/CustomNotifications/res/values/dimens.xml
@@ -1,32 +1,20 @@
 <!--
-  Copyright 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.
+  * 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>
-
-    <!-- Define standard dimensions to comply with Holo-style grids and rhythm. -->
-
-    <dimen name="margin_tiny">4dp</dimen>
-    <dimen name="margin_small">8dp</dimen>
-    <dimen name="margin_medium">16dp</dimen>
-    <dimen name="margin_large">32dp</dimen>
-    <dimen name="margin_huge">64dp</dimen>
-
-    <!-- Semantic definitions -->
-
-    <dimen name="horizontal_page_margin">@dimen/margin_medium</dimen>
-    <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
-
+    <!-- Default screen margins, per the Android Design guidelines. -->
+    <dimen name="activity_horizontal_margin">16dp</dimen>
+    <dimen name="activity_vertical_margin">16dp</dimen>
 </resources>
diff --git a/samples/browseable/CustomNotifications/res/values/styles.xml b/samples/browseable/CustomNotifications/res/values/styles.xml
index 404623e..1d3d45b 100644
--- a/samples/browseable/CustomNotifications/res/values/styles.xml
+++ b/samples/browseable/CustomNotifications/res/values/styles.xml
@@ -1,42 +1,22 @@
 <!--
-  Copyright 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.
+  * 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>
 
-    <!-- Activity themes -->
-
-    <style name="Theme.Base" parent="android:Theme.Holo.Light" />
-
-    <style name="Theme.Sample" parent="Theme.Base" />
-
-    <style name="AppTheme" parent="Theme.Sample" />
-    <!-- Widget styling -->
-
-    <style name="Widget" />
-
-    <style name="Widget.SampleMessage">
-        <item name="android:textAppearance">?android:textAppearanceMedium</item>
-        <item name="android:lineSpacingMultiplier">1.1</item>
-    </style>
-
-    <style name="Widget.SampleMessageTile">
-        <item name="android:background">@drawable/tile</item>
-        <item name="android:shadowColor">#7F000000</item>
-        <item name="android:shadowDy">-3.5</item>
-        <item name="android:shadowRadius">2</item>
+    <style name="NotificationContent" parent="@android:style/TextAppearance.Small">
+        <item name="android:textColor">?android:attr/textColorPrimaryInverse</item>
     </style>
 
 </resources>
diff --git a/samples/browseable/BasicNotifications/res/values/dimens.xml b/samples/browseable/CustomNotifications/res/values/template-dimens.xml
similarity index 100%
copy from samples/browseable/BasicNotifications/res/values/dimens.xml
copy to samples/browseable/CustomNotifications/res/values/template-dimens.xml
diff --git a/samples/browseable/BasicNotifications/res/values/styles.xml b/samples/browseable/CustomNotifications/res/values/template-styles.xml
similarity index 100%
copy from samples/browseable/BasicNotifications/res/values/styles.xml
copy to samples/browseable/CustomNotifications/res/values/template-styles.xml
diff --git a/samples/browseable/DisplayingBitmaps/AndroidManifest.xml b/samples/browseable/DisplayingBitmaps/AndroidManifest.xml
new file mode 100644
index 0000000..23db308
--- /dev/null
+++ b/samples/browseable/DisplayingBitmaps/AndroidManifest.xml
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 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.displayingbitmaps"
+    android:versionCode="1"
+    android:versionName="1.0">
+
+    <uses-sdk android:minSdkVersion="7" android:targetSdkVersion="19" />
+
+    <uses-permission android:name="android.permission.INTERNET" />
+    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
+
+    <application android:allowBackup="true"
+        android:label="@string/app_name"
+        android:description="@string/intro_message"
+        android:icon="@drawable/ic_launcher"
+        android:theme="@style/AppThemeDark">
+
+        <activity android:name=".ui.ImageGridActivity"
+                  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=".ui.ImageDetailActivity"
+            android:label="@string/app_name"
+            android:parentActivityName=".ui.ImageGridActivity"
+            android:theme="@style/AppThemeDark.FullScreen" >
+            <meta-data android:name="android.support.PARENT_ACTIVITY"
+                android:value=".ui.ImageGridActivity" />
+        </activity>
+
+    </application>
+
+</manifest>
diff --git a/samples/browseable/DisplayingBitmaps/_index.jd b/samples/browseable/DisplayingBitmaps/_index.jd
new file mode 100644
index 0000000..eb88097
--- /dev/null
+++ b/samples/browseable/DisplayingBitmaps/_index.jd
@@ -0,0 +1,21 @@
+
+
+
+page.tags="DisplayingBitmaps"
+sample.group=UI
+@jd:body
+
+<p>This is a sample application for the 
+<a href="{@docRoot}training/displaying-bitmaps/index.html">Displaying
+Bitmaps Efficiently</a> Android Training class.</p>
+
+<p>
+The sample demonstrates:
+</p>
+<ul>
+<li>Loading large bitmaps efficiently outside the main UI thread.</li>
+<li>Caching bitmaps (both in memory and on disk).</li>
+<li>Managing bitmap memory.</li>
+<li>Displaying bitmaps in UI elements (such as {@link android.support.v4.view.ViewPager ViewPager},
+{@link android.widget.ListView ListView}, and {@link android.widget.GridView GridView}).</li>
+</ul>
\ No newline at end of file
diff --git a/samples/training/bitmapfun/BitmapFun/src/main/res/drawable-hdpi/ic_launcher.png b/samples/browseable/DisplayingBitmaps/res/drawable-hdpi/ic_launcher.png
similarity index 100%
copy from samples/training/bitmapfun/BitmapFun/src/main/res/drawable-hdpi/ic_launcher.png
copy to samples/browseable/DisplayingBitmaps/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/Basic/res/drawable-hdpi/tile.9.png b/samples/browseable/DisplayingBitmaps/res/drawable-hdpi/tile.9.png
similarity index 100%
copy from samples/browseable/Basic/res/drawable-hdpi/tile.9.png
copy to samples/browseable/DisplayingBitmaps/res/drawable-hdpi/tile.9.png
Binary files differ
diff --git a/samples/training/bitmapfun/BitmapFun/src/main/res/drawable-mdpi/ic_launcher.png b/samples/browseable/DisplayingBitmaps/res/drawable-mdpi/ic_launcher.png
similarity index 100%
rename from samples/training/bitmapfun/BitmapFun/src/main/res/drawable-mdpi/ic_launcher.png
rename to samples/browseable/DisplayingBitmaps/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/samples/training/bitmapfun/BitmapFun/src/main/res/drawable-nodpi/empty_photo.png b/samples/browseable/DisplayingBitmaps/res/drawable-nodpi/empty_photo.png
similarity index 100%
rename from samples/training/bitmapfun/BitmapFun/src/main/res/drawable-nodpi/empty_photo.png
rename to samples/browseable/DisplayingBitmaps/res/drawable-nodpi/empty_photo.png
Binary files differ
diff --git a/samples/training/bitmapfun/BitmapFun/src/main/res/drawable-xhdpi/ic_launcher.png b/samples/browseable/DisplayingBitmaps/res/drawable-xhdpi/ic_launcher.png
similarity index 100%
copy from samples/training/bitmapfun/BitmapFun/src/main/res/drawable-xhdpi/ic_launcher.png
copy to samples/browseable/DisplayingBitmaps/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/training/bitmapfun/BitmapFun/src/main/res/drawable-xxhdpi/ic_launcher.png b/samples/browseable/DisplayingBitmaps/res/drawable-xxhdpi/ic_launcher.png
similarity index 100%
rename from samples/training/bitmapfun/BitmapFun/src/main/res/drawable-xxhdpi/ic_launcher.png
rename to samples/browseable/DisplayingBitmaps/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/training/bitmapfun/BitmapFun/src/main/res/drawable/photogrid_list_selector.xml b/samples/browseable/DisplayingBitmaps/res/drawable/photogrid_list_selector.xml
similarity index 99%
rename from samples/training/bitmapfun/BitmapFun/src/main/res/drawable/photogrid_list_selector.xml
rename to samples/browseable/DisplayingBitmaps/res/drawable/photogrid_list_selector.xml
index 19d8670..d331c39 100644
--- a/samples/training/bitmapfun/BitmapFun/src/main/res/drawable/photogrid_list_selector.xml
+++ b/samples/browseable/DisplayingBitmaps/res/drawable/photogrid_list_selector.xml
@@ -21,11 +21,13 @@
             <solid android:color="@color/grid_state_pressed" />
         </shape>
     </item>
+
     <item android:state_focused="true">
         <shape>
             <solid android:color="@color/grid_state_focused" />
         </shape>
     </item>
+
     <item android:drawable="@android:color/transparent" />
 
 </selector>
diff --git a/samples/browseable/Basic/res/layout/activity_main.xml b/samples/browseable/DisplayingBitmaps/res/layout/activity_main.xml
similarity index 100%
copy from samples/browseable/Basic/res/layout/activity_main.xml
copy to samples/browseable/DisplayingBitmaps/res/layout/activity_main.xml
diff --git a/samples/training/bitmapfun/BitmapFun/src/main/res/layout/image_detail_fragment.xml b/samples/browseable/DisplayingBitmaps/res/layout/image_detail_fragment.xml
similarity index 94%
rename from samples/training/bitmapfun/BitmapFun/src/main/res/layout/image_detail_fragment.xml
rename to samples/browseable/DisplayingBitmaps/res/layout/image_detail_fragment.xml
index 6940357..97ac520 100644
--- a/samples/training/bitmapfun/BitmapFun/src/main/res/layout/image_detail_fragment.xml
+++ b/samples/browseable/DisplayingBitmaps/res/layout/image_detail_fragment.xml
@@ -25,7 +25,7 @@
         android:layout_height="wrap_content"
         android:layout_gravity="center" />
 
-    <com.example.android.bitmapfun.ui.RecyclingImageView
+    <com.example.android.displayingbitmaps.ui.RecyclingImageView
         android:id="@+id/imageView"
         android:layout_width="fill_parent"
         android:layout_height="fill_parent"
diff --git a/samples/training/bitmapfun/BitmapFun/src/main/res/layout/image_detail_pager.xml b/samples/browseable/DisplayingBitmaps/res/layout/image_detail_pager.xml
similarity index 100%
rename from samples/training/bitmapfun/BitmapFun/src/main/res/layout/image_detail_pager.xml
rename to samples/browseable/DisplayingBitmaps/res/layout/image_detail_pager.xml
diff --git a/samples/training/bitmapfun/BitmapFun/src/main/res/layout/image_grid_fragment.xml b/samples/browseable/DisplayingBitmaps/res/layout/image_grid_fragment.xml
similarity index 100%
rename from samples/training/bitmapfun/BitmapFun/src/main/res/layout/image_grid_fragment.xml
rename to samples/browseable/DisplayingBitmaps/res/layout/image_grid_fragment.xml
diff --git a/samples/training/bitmapfun/BitmapFun/src/main/res/menu/main_menu.xml b/samples/browseable/DisplayingBitmaps/res/menu/main_menu.xml
similarity index 100%
rename from samples/training/bitmapfun/BitmapFun/src/main/res/menu/main_menu.xml
rename to samples/browseable/DisplayingBitmaps/res/menu/main_menu.xml
diff --git a/samples/training/bitmapfun/BitmapFun/src/main/res/values-large/dimens.xml b/samples/browseable/DisplayingBitmaps/res/values-large/dimens.xml
similarity index 100%
rename from samples/training/bitmapfun/BitmapFun/src/main/res/values-large/dimens.xml
rename to samples/browseable/DisplayingBitmaps/res/values-large/dimens.xml
diff --git a/samples/browseable/AppRestrictions/res/values-sw600dp/dimens.xml b/samples/browseable/DisplayingBitmaps/res/values-sw600dp/template-dimens.xml
similarity index 100%
copy from samples/browseable/AppRestrictions/res/values-sw600dp/dimens.xml
copy to samples/browseable/DisplayingBitmaps/res/values-sw600dp/template-dimens.xml
diff --git a/samples/browseable/AppRestrictions/res/values-sw600dp/styles.xml b/samples/browseable/DisplayingBitmaps/res/values-sw600dp/template-styles.xml
similarity index 100%
copy from samples/browseable/AppRestrictions/res/values-sw600dp/styles.xml
copy to samples/browseable/DisplayingBitmaps/res/values-sw600dp/template-styles.xml
diff --git a/samples/training/bitmapfun/BitmapFun/src/main/res/values-v11/styles.xml b/samples/browseable/DisplayingBitmaps/res/values-v11/styles.xml
similarity index 81%
rename from samples/training/bitmapfun/BitmapFun/src/main/res/values-v11/styles.xml
rename to samples/browseable/DisplayingBitmaps/res/values-v11/styles.xml
index 0c64526..57da0fb 100644
--- a/samples/training/bitmapfun/BitmapFun/src/main/res/values-v11/styles.xml
+++ b/samples/browseable/DisplayingBitmaps/res/values-v11/styles.xml
@@ -17,20 +17,20 @@
 
 <resources>
 
-    <style name="AppTheme" parent="@android:style/Theme.Holo">
+    <style name="AppThemeDark" parent="@android:style/Theme.Holo">
         <item name="android:windowActionBarOverlay">true</item>
         <item name="android:windowBackground">@android:color/black</item>
         <item name="android:actionBarStyle">@style/TranslucentDarkActionBar</item>
     </style>
 
-    <style name="AppTheme.FullScreen" />
+    <style name="AppThemeDark.FullScreen" />
 
     <style name="TranslucentDarkActionBar" parent="@android:style/Widget.Holo.ActionBar">
         <item name="android:background">#99000000</item>
     </style>
 
-    <style name="PhotoGridLayout">
-        <item name="android:drawSelectorOnTop">true</item>
-    </style>
+    <!--<style name="PhotoGridLayout">-->
+        <!--<item name="android:drawSelectorOnTop">true</item>-->
+    <!--</style>-->
 
 </resources>
\ No newline at end of file
diff --git a/samples/training/bitmapfun/BitmapFun/src/main/res/values-xlarge/dimens.xml b/samples/browseable/DisplayingBitmaps/res/values-xlarge/dimens.xml
similarity index 100%
rename from samples/training/bitmapfun/BitmapFun/src/main/res/values-xlarge/dimens.xml
rename to samples/browseable/DisplayingBitmaps/res/values-xlarge/dimens.xml
diff --git a/samples/browseable/DisplayingBitmaps/res/values/base-strings.xml b/samples/browseable/DisplayingBitmaps/res/values/base-strings.xml
new file mode 100644
index 0000000..a6a8390
--- /dev/null
+++ b/samples/browseable/DisplayingBitmaps/res/values/base-strings.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 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">DisplayingBitmaps</string>
+    <string name="intro_message">
+        <![CDATA[
+        
+            
+            This is a sample application for the Android Training class
+            &quot;Displaying Bitmaps Efficiently&quot;
+            (http://developer.android.com/training/displaying-bitmaps/).\n\n
+
+            It demonstrates how to load large bitmaps efficiently off the main UI thread, caching
+            bitmaps (both in memory and on disk), managing bitmap memory and displaying bitmaps
+            in UI elements such as ViewPager and ListView/GridView.
+            
+        
+        ]]>
+    </string>
+</resources>
diff --git a/samples/training/bitmapfun/BitmapFun/src/main/res/values/colors.xml b/samples/browseable/DisplayingBitmaps/res/values/colors.xml
similarity index 85%
rename from samples/training/bitmapfun/BitmapFun/src/main/res/values/colors.xml
rename to samples/browseable/DisplayingBitmaps/res/values/colors.xml
index 7e4a4fe..521b4b9 100644
--- a/samples/training/bitmapfun/BitmapFun/src/main/res/values/colors.xml
+++ b/samples/browseable/DisplayingBitmaps/res/values/colors.xml
@@ -17,7 +17,7 @@
 
 <resources>
 
-    <color name="grid_state_pressed">#BB7dbcd3</color>
-    <color name="grid_state_focused">#777dbcd3</color>
+    <color name="grid_state_pressed">#1Affffff</color>
+    <color name="grid_state_focused">#80000000</color>
 
 </resources>
diff --git a/samples/training/bitmapfun/BitmapFun/src/main/res/values/dimens.xml b/samples/browseable/DisplayingBitmaps/res/values/dimens.xml
similarity index 92%
rename from samples/training/bitmapfun/BitmapFun/src/main/res/values/dimens.xml
rename to samples/browseable/DisplayingBitmaps/res/values/dimens.xml
index 60d540f..53f61f0 100644
--- a/samples/training/bitmapfun/BitmapFun/src/main/res/values/dimens.xml
+++ b/samples/browseable/DisplayingBitmaps/res/values/dimens.xml
@@ -19,6 +19,5 @@
 
     <dimen name="image_thumbnail_size">100dp</dimen>
     <dimen name="image_thumbnail_spacing">1dp</dimen>
-    <dimen name="image_detail_pager_margin">80dp</dimen>
 
 </resources>
\ No newline at end of file
diff --git a/samples/training/bitmapfun/BitmapFun/src/main/res/values/dimens.xml b/samples/browseable/DisplayingBitmaps/res/values/strings.xml
similarity index 69%
copy from samples/training/bitmapfun/BitmapFun/src/main/res/values/dimens.xml
copy to samples/browseable/DisplayingBitmaps/res/values/strings.xml
index 60d540f..84b6137 100644
--- a/samples/training/bitmapfun/BitmapFun/src/main/res/values/dimens.xml
+++ b/samples/browseable/DisplayingBitmaps/res/values/strings.xml
@@ -17,8 +17,9 @@
 
 <resources>
 
-    <dimen name="image_thumbnail_size">100dp</dimen>
-    <dimen name="image_thumbnail_spacing">1dp</dimen>
-    <dimen name="image_detail_pager_margin">80dp</dimen>
+    <string name="clear_cache_menu">Clear Caches</string>
+    <string name="clear_cache_complete_toast">Caches have been cleared</string>
+    <string name="imageview_description">Image Thumbnail</string>
+    <string name="no_network_connection_toast">No network connection found</string>
 
 </resources>
\ No newline at end of file
diff --git a/samples/training/bitmapfun/BitmapFun/src/main/res/values/styles.xml b/samples/browseable/DisplayingBitmaps/res/values/styles.xml
similarity index 84%
rename from samples/training/bitmapfun/BitmapFun/src/main/res/values/styles.xml
rename to samples/browseable/DisplayingBitmaps/res/values/styles.xml
index 0f1a018..e9aabee 100644
--- a/samples/training/bitmapfun/BitmapFun/src/main/res/values/styles.xml
+++ b/samples/browseable/DisplayingBitmaps/res/values/styles.xml
@@ -17,9 +17,9 @@
 
 <resources>
 
-    <style name="AppTheme" parent="android:Theme" />
+    <style name="AppThemeDark" parent="android:Theme" />
 
-    <style name="AppTheme.FullScreen" parent="@android:style/Theme.Black.NoTitleBar.Fullscreen" />
+    <style name="AppThemeDark.FullScreen" parent="@android:style/Theme.Black.NoTitleBar.Fullscreen" />
 
     <style name="PhotoGridLayout">
         <item name="android:drawSelectorOnTop">true</item>
diff --git a/samples/browseable/AppRestrictions/res/values/dimens.xml b/samples/browseable/DisplayingBitmaps/res/values/template-dimens.xml
similarity index 100%
copy from samples/browseable/AppRestrictions/res/values/dimens.xml
copy to samples/browseable/DisplayingBitmaps/res/values/template-dimens.xml
diff --git a/samples/browseable/AppRestrictions/res/values/styles.xml b/samples/browseable/DisplayingBitmaps/res/values/template-styles.xml
similarity index 100%
copy from samples/browseable/AppRestrictions/res/values/styles.xml
copy to samples/browseable/DisplayingBitmaps/res/values/template-styles.xml
diff --git a/samples/browseable/repeatingAlarm/src/com.example.android.common/logger/Log.java b/samples/browseable/DisplayingBitmaps/src/com.example.android.common.logger/Log.java
similarity index 100%
copy from samples/browseable/repeatingAlarm/src/com.example.android.common/logger/Log.java
copy to samples/browseable/DisplayingBitmaps/src/com.example.android.common.logger/Log.java
diff --git a/samples/browseable/repeatingAlarm/src/com.example.android.common/logger/LogFragment.java b/samples/browseable/DisplayingBitmaps/src/com.example.android.common.logger/LogFragment.java
similarity index 100%
copy from samples/browseable/repeatingAlarm/src/com.example.android.common/logger/LogFragment.java
copy to samples/browseable/DisplayingBitmaps/src/com.example.android.common.logger/LogFragment.java
diff --git a/samples/browseable/repeatingAlarm/src/com.example.android.common/logger/LogNode.java b/samples/browseable/DisplayingBitmaps/src/com.example.android.common.logger/LogNode.java
similarity index 100%
copy from samples/browseable/repeatingAlarm/src/com.example.android.common/logger/LogNode.java
copy to samples/browseable/DisplayingBitmaps/src/com.example.android.common.logger/LogNode.java
diff --git a/samples/browseable/repeatingAlarm/src/com.example.android.common/logger/LogView.java b/samples/browseable/DisplayingBitmaps/src/com.example.android.common.logger/LogView.java
similarity index 100%
copy from samples/browseable/repeatingAlarm/src/com.example.android.common/logger/LogView.java
copy to samples/browseable/DisplayingBitmaps/src/com.example.android.common.logger/LogView.java
diff --git a/samples/browseable/repeatingAlarm/src/com.example.android.common/logger/LogWrapper.java b/samples/browseable/DisplayingBitmaps/src/com.example.android.common.logger/LogWrapper.java
similarity index 100%
copy from samples/browseable/repeatingAlarm/src/com.example.android.common/logger/LogWrapper.java
copy to samples/browseable/DisplayingBitmaps/src/com.example.android.common.logger/LogWrapper.java
diff --git a/samples/browseable/repeatingAlarm/src/com.example.android.common/logger/MessageOnlyLogFilter.java b/samples/browseable/DisplayingBitmaps/src/com.example.android.common.logger/MessageOnlyLogFilter.java
similarity index 100%
copy from samples/browseable/repeatingAlarm/src/com.example.android.common/logger/MessageOnlyLogFilter.java
copy to samples/browseable/DisplayingBitmaps/src/com.example.android.common.logger/MessageOnlyLogFilter.java
diff --git a/samples/training/bitmapfun/BitmapFun/src/main/java/com/example/android/bitmapfun/provider/Images.java b/samples/browseable/DisplayingBitmaps/src/com.example.android.displayingbitmaps/provider/Images.java
similarity index 99%
rename from samples/training/bitmapfun/BitmapFun/src/main/java/com/example/android/bitmapfun/provider/Images.java
rename to samples/browseable/DisplayingBitmaps/src/com.example.android.displayingbitmaps/provider/Images.java
index fcf4496..5a89546 100644
--- a/samples/training/bitmapfun/BitmapFun/src/main/java/com/example/android/bitmapfun/provider/Images.java
+++ b/samples/browseable/DisplayingBitmaps/src/com.example.android.displayingbitmaps/provider/Images.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.example.android.bitmapfun.provider;
+package com.example.android.displayingbitmaps.provider;
 
 /**
  * Some simple test data to use for this sample app.
diff --git a/samples/training/bitmapfun/BitmapFun/src/main/java/com/example/android/bitmapfun/ui/ImageDetailActivity.java b/samples/browseable/DisplayingBitmaps/src/com.example.android.displayingbitmaps/ui/ImageDetailActivity.java
similarity index 94%
rename from samples/training/bitmapfun/BitmapFun/src/main/java/com/example/android/bitmapfun/ui/ImageDetailActivity.java
rename to samples/browseable/DisplayingBitmaps/src/com.example.android.displayingbitmaps/ui/ImageDetailActivity.java
index 05d7b03..c2be1ac 100644
--- a/samples/training/bitmapfun/BitmapFun/src/main/java/com/example/android/bitmapfun/ui/ImageDetailActivity.java
+++ b/samples/browseable/DisplayingBitmaps/src/com.example.android.displayingbitmaps/ui/ImageDetailActivity.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.example.android.bitmapfun.ui;
+package com.example.android.displayingbitmaps.ui;
 
 import android.annotation.TargetApi;
 import android.app.ActionBar;
@@ -34,12 +34,12 @@
 import android.view.WindowManager.LayoutParams;
 import android.widget.Toast;
 
-import com.example.android.bitmapfun.BuildConfig;
-import com.example.android.bitmapfun.R;
-import com.example.android.bitmapfun.provider.Images;
-import com.example.android.bitmapfun.util.ImageCache;
-import com.example.android.bitmapfun.util.ImageFetcher;
-import com.example.android.bitmapfun.util.Utils;
+import com.example.android.displayingbitmaps.BuildConfig;
+import com.example.android.displayingbitmaps.R;
+import com.example.android.displayingbitmaps.provider.Images;
+import com.example.android.displayingbitmaps.util.ImageCache;
+import com.example.android.displayingbitmaps.util.ImageFetcher;
+import com.example.android.displayingbitmaps.util.Utils;
 
 public class ImageDetailActivity extends FragmentActivity implements OnClickListener {
     private static final String IMAGE_CACHE_DIR = "images";
@@ -85,7 +85,7 @@
         mAdapter = new ImagePagerAdapter(getSupportFragmentManager(), Images.imageUrls.length);
         mPager = (ViewPager) findViewById(R.id.pager);
         mPager.setAdapter(mAdapter);
-        mPager.setPageMargin((int) getResources().getDimension(R.dimen.image_detail_pager_margin));
+        mPager.setPageMargin((int) getResources().getDimension(R.dimen.horizontal_page_margin));
         mPager.setOffscreenPageLimit(2);
 
         // Set up activity to go full screen
diff --git a/samples/training/bitmapfun/BitmapFun/src/main/java/com/example/android/bitmapfun/ui/ImageDetailFragment.java b/samples/browseable/DisplayingBitmaps/src/com.example.android.displayingbitmaps/ui/ImageDetailFragment.java
similarity index 92%
rename from samples/training/bitmapfun/BitmapFun/src/main/java/com/example/android/bitmapfun/ui/ImageDetailFragment.java
rename to samples/browseable/DisplayingBitmaps/src/com.example.android.displayingbitmaps/ui/ImageDetailFragment.java
index 9fff8a0..506729a 100644
--- a/samples/training/bitmapfun/BitmapFun/src/main/java/com/example/android/bitmapfun/ui/ImageDetailFragment.java
+++ b/samples/browseable/DisplayingBitmaps/src/com.example.android.displayingbitmaps/ui/ImageDetailFragment.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.example.android.bitmapfun.ui;
+package com.example.android.displayingbitmaps.ui;
 
 import android.os.Bundle;
 import android.support.v4.app.Fragment;
@@ -24,10 +24,10 @@
 import android.view.ViewGroup;
 import android.widget.ImageView;
 
-import com.example.android.bitmapfun.R;
-import com.example.android.bitmapfun.util.ImageFetcher;
-import com.example.android.bitmapfun.util.ImageWorker;
-import com.example.android.bitmapfun.util.Utils;
+import com.example.android.displayingbitmaps.R;
+import com.example.android.displayingbitmaps.util.ImageFetcher;
+import com.example.android.displayingbitmaps.util.ImageWorker;
+import com.example.android.displayingbitmaps.util.Utils;
 
 /**
  * This fragment will populate the children of the ViewPager from {@link ImageDetailActivity}.
diff --git a/samples/training/bitmapfun/BitmapFun/src/main/java/com/example/android/bitmapfun/ui/ImageGridActivity.java b/samples/browseable/DisplayingBitmaps/src/com.example.android.displayingbitmaps/ui/ImageGridActivity.java
similarity index 89%
rename from samples/training/bitmapfun/BitmapFun/src/main/java/com/example/android/bitmapfun/ui/ImageGridActivity.java
rename to samples/browseable/DisplayingBitmaps/src/com.example.android.displayingbitmaps/ui/ImageGridActivity.java
index e7c7d1c..f171955 100644
--- a/samples/training/bitmapfun/BitmapFun/src/main/java/com/example/android/bitmapfun/ui/ImageGridActivity.java
+++ b/samples/browseable/DisplayingBitmaps/src/com.example.android.displayingbitmaps/ui/ImageGridActivity.java
@@ -14,14 +14,14 @@
  * limitations under the License.
  */
 
-package com.example.android.bitmapfun.ui;
+package com.example.android.displayingbitmaps.ui;
 
 import android.os.Bundle;
 import android.support.v4.app.FragmentActivity;
 import android.support.v4.app.FragmentTransaction;
 
-import com.example.android.bitmapfun.BuildConfig;
-import com.example.android.bitmapfun.util.Utils;
+import com.example.android.displayingbitmaps.BuildConfig;
+import com.example.android.displayingbitmaps.util.Utils;
 
 /**
  * Simple FragmentActivity to hold the main {@link ImageGridFragment} and not much else.
diff --git a/samples/training/bitmapfun/BitmapFun/src/main/java/com/example/android/bitmapfun/ui/ImageGridFragment.java b/samples/browseable/DisplayingBitmaps/src/com.example.android.displayingbitmaps/ui/ImageGridFragment.java
similarity index 93%
rename from samples/training/bitmapfun/BitmapFun/src/main/java/com/example/android/bitmapfun/ui/ImageGridFragment.java
rename to samples/browseable/DisplayingBitmaps/src/com.example.android.displayingbitmaps/ui/ImageGridFragment.java
index ba4581a..4eb1f1b 100644
--- a/samples/training/bitmapfun/BitmapFun/src/main/java/com/example/android/bitmapfun/ui/ImageGridFragment.java
+++ b/samples/browseable/DisplayingBitmaps/src/com.example.android.displayingbitmaps/ui/ImageGridFragment.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.example.android.bitmapfun.ui;
+package com.example.android.displayingbitmaps.ui;
 
 import android.annotation.TargetApi;
 import android.app.ActivityOptions;
@@ -23,7 +23,6 @@
 import android.os.Build.VERSION_CODES;
 import android.os.Bundle;
 import android.support.v4.app.Fragment;
-import android.util.Log;
 import android.util.TypedValue;
 import android.view.LayoutInflater;
 import android.view.Menu;
@@ -40,12 +39,13 @@
 import android.widget.ImageView;
 import android.widget.Toast;
 
-import com.example.android.bitmapfun.BuildConfig;
-import com.example.android.bitmapfun.R;
-import com.example.android.bitmapfun.provider.Images;
-import com.example.android.bitmapfun.util.ImageCache.ImageCacheParams;
-import com.example.android.bitmapfun.util.ImageFetcher;
-import com.example.android.bitmapfun.util.Utils;
+import com.example.android.common.logger.Log;
+import com.example.android.displayingbitmaps.BuildConfig;
+import com.example.android.displayingbitmaps.R;
+import com.example.android.displayingbitmaps.provider.Images;
+import com.example.android.displayingbitmaps.util.ImageCache;
+import com.example.android.displayingbitmaps.util.ImageFetcher;
+import com.example.android.displayingbitmaps.util.Utils;
 
 /**
  * The main fragment that powers the ImageGridActivity screen. Fairly straight forward GridView
@@ -78,7 +78,8 @@
 
         mAdapter = new ImageAdapter(getActivity());
 
-        ImageCacheParams cacheParams = new ImageCacheParams(getActivity(), IMAGE_CACHE_DIR);
+        ImageCache.ImageCacheParams cacheParams =
+                new ImageCache.ImageCacheParams(getActivity(), IMAGE_CACHE_DIR);
 
         cacheParams.setMemCacheSizePercent(0.25f); // Set memory cache to 25% of app memory
 
@@ -122,6 +123,7 @@
         // of each view so we get nice square thumbnails.
         mGridView.getViewTreeObserver().addOnGlobalLayoutListener(
                 new ViewTreeObserver.OnGlobalLayoutListener() {
+                    @TargetApi(VERSION_CODES.JELLY_BEAN)
                     @Override
                     public void onGlobalLayout() {
                         if (mAdapter.getNumColumns() == 0) {
@@ -272,6 +274,7 @@
 
         @Override
         public View getView(int position, View convertView, ViewGroup container) {
+            //BEGIN_INCLUDE(load_gridview_item)
             // First check if this is the top row
             if (position < mNumColumns) {
                 if (convertView == null) {
@@ -279,7 +282,7 @@
                 }
                 // Set empty view with height of ActionBar
                 convertView.setLayoutParams(new AbsListView.LayoutParams(
-                        ViewGroup.LayoutParams.MATCH_PARENT, mActionBarHeight));
+                        LayoutParams.MATCH_PARENT, mActionBarHeight));
                 return convertView;
             }
 
@@ -302,6 +305,7 @@
             // setting a placeholder image while the background thread runs
             mImageFetcher.loadImage(Images.imageThumbUrls[position - mNumColumns], imageView);
             return imageView;
+            //END_INCLUDE(load_gridview_item)
         }
 
         /**
diff --git a/samples/training/bitmapfun/BitmapFun/src/main/java/com/example/android/bitmapfun/ui/RecyclingImageView.java b/samples/browseable/DisplayingBitmaps/src/com.example.android.displayingbitmaps/ui/RecyclingImageView.java
similarity index 95%
rename from samples/training/bitmapfun/BitmapFun/src/main/java/com/example/android/bitmapfun/ui/RecyclingImageView.java
rename to samples/browseable/DisplayingBitmaps/src/com.example.android.displayingbitmaps/ui/RecyclingImageView.java
index 1bcc014..1db134c 100644
--- a/samples/training/bitmapfun/BitmapFun/src/main/java/com/example/android/bitmapfun/ui/RecyclingImageView.java
+++ b/samples/browseable/DisplayingBitmaps/src/com.example.android.displayingbitmaps/ui/RecyclingImageView.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.example.android.bitmapfun.ui;
+package com.example.android.displayingbitmaps.ui;
 
 import android.content.Context;
 import android.graphics.drawable.Drawable;
@@ -22,7 +22,7 @@
 import android.util.AttributeSet;
 import android.widget.ImageView;
 
-import com.example.android.bitmapfun.util.RecyclingBitmapDrawable;
+import com.example.android.displayingbitmaps.util.RecyclingBitmapDrawable;
 
 /**
  * Sub-class of ImageView which automatically notifies the drawable when it is
diff --git a/samples/training/bitmapfun/BitmapFun/src/main/java/com/example/android/bitmapfun/util/AsyncTask.java b/samples/browseable/DisplayingBitmaps/src/com.example.android.displayingbitmaps/util/AsyncTask.java
similarity index 96%
rename from samples/training/bitmapfun/BitmapFun/src/main/java/com/example/android/bitmapfun/util/AsyncTask.java
rename to samples/browseable/DisplayingBitmaps/src/com.example.android.displayingbitmaps/util/AsyncTask.java
index 018ce1a..dffade4 100644
--- a/samples/training/bitmapfun/BitmapFun/src/main/java/com/example/android/bitmapfun/util/AsyncTask.java
+++ b/samples/browseable/DisplayingBitmaps/src/com.example.android.displayingbitmaps/util/AsyncTask.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.example.android.bitmapfun.util;
+package com.example.android.displayingbitmaps.util;
 
 import android.annotation.TargetApi;
 import android.os.Handler;
@@ -25,8 +25,8 @@
 import java.util.concurrent.BlockingQueue;
 import java.util.concurrent.Callable;
 import java.util.concurrent.CancellationException;
-import java.util.concurrent.Executor;
 import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Executor;
 import java.util.concurrent.Executors;
 import java.util.concurrent.FutureTask;
 import java.util.concurrent.LinkedBlockingQueue;
@@ -56,12 +56,12 @@
  * perform background operations and publish results on the UI thread without
  * having to manipulate threads and/or handlers.</p>
  *
- * <p>AsyncTask is designed to be a helper class around {@link Thread} and {@link Handler}
+ * <p>AsyncTask is designed to be a helper class around {@link Thread} and {@link android.os.Handler}
  * and does not constitute a generic threading framework. AsyncTasks should ideally be
  * used for short operations (a few seconds at the most.) If you need to keep threads
  * running for long periods of time, it is highly recommended you use the various APIs
- * provided by the <code>java.util.concurrent</code> pacakge such as {@link Executor},
- * {@link ThreadPoolExecutor} and {@link FutureTask}.</p>
+ * provided by the <code>java.util.concurrent</code> pacakge such as {@link java.util.concurrent.Executor},
+ * {@link java.util.concurrent.ThreadPoolExecutor} and {@link java.util.concurrent.FutureTask}.</p>
  *
  * <p>An asynchronous task is defined by a computation that runs on a background thread and
  * whose result is published on the UI thread. An asynchronous task is defined by 3 generic
@@ -213,7 +213,7 @@
             new LinkedBlockingQueue<Runnable>(10);
 
     /**
-     * An {@link Executor} that can be used to execute tasks in parallel.
+     * An {@link java.util.concurrent.Executor} that can be used to execute tasks in parallel.
      */
     public static final Executor THREAD_POOL_EXECUTOR
             = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
@@ -221,7 +221,7 @@
             new ThreadPoolExecutor.DiscardOldestPolicy());
 
     /**
-     * An {@link Executor} that executes tasks one at a time in serial
+     * An {@link java.util.concurrent.Executor} that executes tasks one at a time in serial
      * order.  This serialization is global to a particular process.
      */
     public static final Executor SERIAL_EXECUTOR = Utils.hasHoneycomb() ? new SerialExecutor() :
@@ -499,8 +499,8 @@
      *
      * @return The computed result.
      *
-     * @throws CancellationException If the computation was cancelled.
-     * @throws ExecutionException If the computation threw an exception.
+     * @throws java.util.concurrent.CancellationException If the computation was cancelled.
+     * @throws java.util.concurrent.ExecutionException If the computation threw an exception.
      * @throws InterruptedException If the current thread was interrupted
      *         while waiting.
      */
@@ -517,11 +517,11 @@
      *
      * @return The computed result.
      *
-     * @throws CancellationException If the computation was cancelled.
-     * @throws ExecutionException If the computation threw an exception.
+     * @throws java.util.concurrent.CancellationException If the computation was cancelled.
+     * @throws java.util.concurrent.ExecutionException If the computation threw an exception.
      * @throws InterruptedException If the current thread was interrupted
      *         while waiting.
-     * @throws TimeoutException If the wait timed out.
+     * @throws java.util.concurrent.TimeoutException If the wait timed out.
      */
     public final Result get(long timeout, TimeUnit unit) throws InterruptedException,
             ExecutionException, TimeoutException {
@@ -566,7 +566,7 @@
      *
      * <p>This method is typically used with {@link #THREAD_POOL_EXECUTOR} to
      * allow multiple tasks to run in parallel on a pool of threads managed by
-     * AsyncTask, however you can also use your own {@link Executor} for custom
+     * AsyncTask, however you can also use your own {@link java.util.concurrent.Executor} for custom
      * behavior.
      *
      * <p><em>Warning:</em> Allowing multiple tasks to run in parallel from
diff --git a/samples/training/bitmapfun/BitmapFun/src/main/java/com/example/android/bitmapfun/util/DiskLruCache.java b/samples/browseable/DisplayingBitmaps/src/com.example.android.displayingbitmaps/util/DiskLruCache.java
similarity index 99%
rename from samples/training/bitmapfun/BitmapFun/src/main/java/com/example/android/bitmapfun/util/DiskLruCache.java
rename to samples/browseable/DisplayingBitmaps/src/com.example.android.displayingbitmaps/util/DiskLruCache.java
index 26cdbd7..4c14345 100644
--- a/samples/training/bitmapfun/BitmapFun/src/main/java/com/example/android/bitmapfun/util/DiskLruCache.java
+++ b/samples/browseable/DisplayingBitmaps/src/com.example.android.displayingbitmaps/util/DiskLruCache.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.example.android.bitmapfun.util;
+package com.example.android.displayingbitmaps.util;
 
 import java.io.BufferedInputStream;
 import java.io.BufferedWriter;
@@ -302,7 +302,7 @@
      * @param appVersion
      * @param valueCount the number of values per cache entry. Must be positive.
      * @param maxSize the maximum number of bytes this cache should use to store
-     * @throws IOException if reading or writing the cache directory fails
+     * @throws java.io.IOException if reading or writing the cache directory fails
      */
     public static DiskLruCache open(File directory, int appVersion, int valueCount, long maxSize)
             throws IOException {
diff --git a/samples/training/bitmapfun/BitmapFun/src/main/java/com/example/android/bitmapfun/util/ImageCache.java b/samples/browseable/DisplayingBitmaps/src/com.example.android.displayingbitmaps/util/ImageCache.java
similarity index 94%
rename from samples/training/bitmapfun/BitmapFun/src/main/java/com/example/android/bitmapfun/util/ImageCache.java
rename to samples/browseable/DisplayingBitmaps/src/com.example.android.displayingbitmaps/util/ImageCache.java
index 7021d2c..41da56c 100644
--- a/samples/training/bitmapfun/BitmapFun/src/main/java/com/example/android/bitmapfun/util/ImageCache.java
+++ b/samples/browseable/DisplayingBitmaps/src/com.example.android.displayingbitmaps/util/ImageCache.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.example.android.bitmapfun.util;
+package com.example.android.displayingbitmaps.util;
 
 import android.annotation.TargetApi;
 import android.content.Context;
@@ -30,9 +30,9 @@
 import android.support.v4.app.Fragment;
 import android.support.v4.app.FragmentManager;
 import android.support.v4.util.LruCache;
-import android.util.Log;
 
-import com.example.android.bitmapfun.BuildConfig;
+import com.example.android.common.logger.Log;
+import com.example.android.displayingbitmaps.BuildConfig;
 
 import java.io.File;
 import java.io.FileDescriptor;
@@ -51,9 +51,9 @@
 /**
  * This class handles disk and memory caching of bitmaps in conjunction with the
  * {@link ImageWorker} class and its subclasses. Use
- * {@link ImageCache#getInstance(FragmentManager, ImageCacheParams)} to get an instance of this
+ * {@link ImageCache#getInstance(android.support.v4.app.FragmentManager, ImageCacheParams)} to get an instance of this
  * class, although usually a cache should be added directly to an {@link ImageWorker} by calling
- * {@link ImageWorker#addImageCache(FragmentManager, ImageCacheParams)}.
+ * {@link ImageWorker#addImageCache(android.support.v4.app.FragmentManager, ImageCacheParams)}.
  */
 public class ImageCache {
     private static final String TAG = "ImageCache";
@@ -85,7 +85,7 @@
     /**
      * Create a new ImageCache object using the specified parameters. This should not be
      * called directly by other classes, instead use
-     * {@link ImageCache#getInstance(FragmentManager, ImageCacheParams)} to fetch an ImageCache
+     * {@link ImageCache#getInstance(android.support.v4.app.FragmentManager, ImageCacheParams)} to fetch an ImageCache
      * instance.
      *
      * @param cacheParams The cache parameters to use to initialize the cache
@@ -128,6 +128,7 @@
     private void init(ImageCacheParams cacheParams) {
         mCacheParams = cacheParams;
 
+        //BEGIN_INCLUDE(init_memory_cache)
         // Set up memory cache
         if (mCacheParams.memoryCacheEnabled) {
             if (BuildConfig.DEBUG) {
@@ -157,7 +158,7 @@
                 protected void entryRemoved(boolean evicted, String key,
                         BitmapDrawable oldValue, BitmapDrawable newValue) {
                     if (RecyclingBitmapDrawable.class.isInstance(oldValue)) {
-                        // The removed entry is a recycling drawable, so notify it 
+                        // The removed entry is a recycling drawable, so notify it
                         // that it has been removed from the memory cache
                         ((RecyclingBitmapDrawable) oldValue).setIsCached(false);
                     } else {
@@ -182,6 +183,7 @@
                 }
             };
         }
+        //END_INCLUDE(init_memory_cache)
 
         // By default the disk cache is not initialized here as it should be initialized
         // on a separate thread due to disk access.
@@ -231,6 +233,7 @@
      * @param value The bitmap drawable to store
      */
     public void addBitmapToCache(String data, BitmapDrawable value) {
+        //BEGIN_INCLUDE(add_bitmap_to_cache)
         if (data == null || value == null) {
             return;
         }
@@ -238,7 +241,7 @@
         // Add to memory cache
         if (mMemoryCache != null) {
             if (RecyclingBitmapDrawable.class.isInstance(value)) {
-                // The removed entry is a recycling drawable, so notify it 
+                // The removed entry is a recycling drawable, so notify it
                 // that it has been added into the memory cache
                 ((RecyclingBitmapDrawable) value).setIsCached(true);
             }
@@ -277,6 +280,7 @@
                 }
             }
         }
+        //END_INCLUDE(add_bitmap_to_cache)
     }
 
     /**
@@ -286,6 +290,7 @@
      * @return The bitmap drawable if found in cache, null otherwise
      */
     public BitmapDrawable getBitmapFromMemCache(String data) {
+        //BEGIN_INCLUDE(get_bitmap_from_mem_cache)
         BitmapDrawable memValue = null;
 
         if (mMemoryCache != null) {
@@ -297,6 +302,7 @@
         }
 
         return memValue;
+        //END_INCLUDE(get_bitmap_from_mem_cache)
     }
 
     /**
@@ -306,6 +312,7 @@
      * @return The bitmap if found in cache, null otherwise
      */
     public Bitmap getBitmapFromDiskCache(String data) {
+        //BEGIN_INCLUDE(get_bitmap_from_disk_cache)
         final String key = hashKeyForDisk(data);
         Bitmap bitmap = null;
 
@@ -345,6 +352,7 @@
             }
             return bitmap;
         }
+        //END_INCLUDE(get_bitmap_from_disk_cache)
     }
 
     /**
@@ -352,6 +360,7 @@
      * @return Bitmap that case be used for inBitmap
      */
     protected Bitmap getBitmapFromReusableSet(BitmapFactory.Options options) {
+        //BEGIN_INCLUDE(get_bitmap_from_reusable_set)
         Bitmap bitmap = null;
 
         if (mReusableBitmaps != null && !mReusableBitmaps.isEmpty()) {
@@ -380,6 +389,7 @@
         }
 
         return bitmap;
+        //END_INCLUDE(get_bitmap_from_reusable_set)
     }
 
     /**
@@ -467,8 +477,8 @@
 
         /**
          * Create a set of image cache parameters that can be provided to
-         * {@link ImageCache#getInstance(FragmentManager, ImageCacheParams)} or
-         * {@link ImageWorker#addImageCache(FragmentManager, ImageCacheParams)}.
+         * {@link ImageCache#getInstance(android.support.v4.app.FragmentManager, ImageCacheParams)} or
+         * {@link ImageWorker#addImageCache(android.support.v4.app.FragmentManager, ImageCacheParams)}.
          * @param context A context to use.
          * @param diskCacheDirectoryName A unique subdirectory name that will be appended to the
          *                               application cache directory. Usually "cache" or "images"
@@ -509,7 +519,7 @@
     @TargetApi(VERSION_CODES.KITKAT)
     private static boolean canUseForInBitmap(
             Bitmap candidate, BitmapFactory.Options targetOptions) {
-
+        //BEGIN_INCLUDE(can_use_for_inbitmap)
         if (!Utils.hasKitKat()) {
             // On earlier versions, the dimensions must match exactly and the inSampleSize must be 1
             return candidate.getWidth() == targetOptions.outWidth
@@ -523,6 +533,7 @@
         int height = targetOptions.outHeight / targetOptions.inSampleSize;
         int byteCount = width * height * getBytesPerPixel(candidate.getConfig());
         return byteCount <= candidate.getAllocationByteCount();
+        //END_INCLUDE(can_use_for_inbitmap)
     }
 
     /**
@@ -671,6 +682,7 @@
      *         created.
      */
     private static RetainFragment findOrCreateRetainFragment(FragmentManager fm) {
+        //BEGIN_INCLUDE(find_create_retain_fragment)
         // Check to see if we have retained the worker fragment.
         RetainFragment mRetainFragment = (RetainFragment) fm.findFragmentByTag(TAG);
 
@@ -681,6 +693,7 @@
         }
 
         return mRetainFragment;
+        //END_INCLUDE(find_create_retain_fragment)
     }
 
     /**
diff --git a/samples/training/bitmapfun/BitmapFun/src/main/java/com/example/android/bitmapfun/util/ImageFetcher.java b/samples/browseable/DisplayingBitmaps/src/com.example.android.displayingbitmaps/util/ImageFetcher.java
similarity index 97%
rename from samples/training/bitmapfun/BitmapFun/src/main/java/com/example/android/bitmapfun/util/ImageFetcher.java
rename to samples/browseable/DisplayingBitmaps/src/com.example.android.displayingbitmaps/util/ImageFetcher.java
index 4c92d74..b9ccb68 100644
--- a/samples/training/bitmapfun/BitmapFun/src/main/java/com/example/android/bitmapfun/util/ImageFetcher.java
+++ b/samples/browseable/DisplayingBitmaps/src/com.example.android.displayingbitmaps/util/ImageFetcher.java
@@ -14,18 +14,18 @@
  * limitations under the License.
  */
 
-package com.example.android.bitmapfun.util;
+package com.example.android.displayingbitmaps.util;
 
 import android.content.Context;
 import android.graphics.Bitmap;
 import android.net.ConnectivityManager;
 import android.net.NetworkInfo;
 import android.os.Build;
-import android.util.Log;
 import android.widget.Toast;
 
-import com.example.android.bitmapfun.BuildConfig;
-import com.example.android.bitmapfun.R;
+import com.example.android.common.logger.Log;
+import com.example.android.displayingbitmaps.BuildConfig;
+import com.example.android.displayingbitmaps.R;
 
 import java.io.BufferedInputStream;
 import java.io.BufferedOutputStream;
diff --git a/samples/training/bitmapfun/BitmapFun/src/main/java/com/example/android/bitmapfun/util/ImageResizer.java b/samples/browseable/DisplayingBitmaps/src/com.example.android.displayingbitmaps/util/ImageResizer.java
similarity index 93%
rename from samples/training/bitmapfun/BitmapFun/src/main/java/com/example/android/bitmapfun/util/ImageResizer.java
rename to samples/browseable/DisplayingBitmaps/src/com.example.android.displayingbitmaps/util/ImageResizer.java
index e8ce4e1..be91096 100644
--- a/samples/training/bitmapfun/BitmapFun/src/main/java/com/example/android/bitmapfun/util/ImageResizer.java
+++ b/samples/browseable/DisplayingBitmaps/src/com.example.android.displayingbitmaps/util/ImageResizer.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.example.android.bitmapfun.util;
+package com.example.android.displayingbitmaps.util;
 
 import android.annotation.TargetApi;
 import android.content.Context;
@@ -22,9 +22,9 @@
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
 import android.os.Build;
-import android.util.Log;
 
-import com.example.android.bitmapfun.BuildConfig;
+import com.example.android.common.logger.Log;
+import com.example.android.displayingbitmaps.BuildConfig;
 
 import java.io.FileDescriptor;
 
@@ -115,6 +115,7 @@
     public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId,
             int reqWidth, int reqHeight, ImageCache cache) {
 
+        // BEGIN_INCLUDE (read_bitmap_dimensions)
         // First decode with inJustDecodeBounds=true to check dimensions
         final BitmapFactory.Options options = new BitmapFactory.Options();
         options.inJustDecodeBounds = true;
@@ -122,6 +123,7 @@
 
         // Calculate inSampleSize
         options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
+        // END_INCLUDE (read_bitmap_dimensions)
 
         // If we're running on Honeycomb or newer, try to use inBitmap
         if (Utils.hasHoneycomb()) {
@@ -198,6 +200,7 @@
 
     @TargetApi(Build.VERSION_CODES.HONEYCOMB)
     private static void addInBitmapOptions(BitmapFactory.Options options, ImageCache cache) {
+        //BEGIN_INCLUDE(add_bitmap_options)
         // inBitmap only works with mutable bitmaps so force the decoder to
         // return mutable bitmaps.
         options.inMutable = true;
@@ -210,11 +213,12 @@
                 options.inBitmap = inBitmap;
             }
         }
+        //END_INCLUDE(add_bitmap_options)
     }
 
     /**
-     * Calculate an inSampleSize for use in a {@link BitmapFactory.Options} object when decoding
-     * bitmaps using the decode* methods from {@link BitmapFactory}. This implementation calculates
+     * Calculate an inSampleSize for use in a {@link android.graphics.BitmapFactory.Options} object when decoding
+     * bitmaps using the decode* methods from {@link android.graphics.BitmapFactory}. This implementation calculates
      * the closest inSampleSize that is a power of 2 and will result in the final decoded bitmap
      * having a width and height equal to or larger than the requested width and height.
      *
@@ -226,6 +230,7 @@
      */
     public static int calculateInSampleSize(BitmapFactory.Options options,
             int reqWidth, int reqHeight) {
+        // BEGIN_INCLUDE (calculate_sample_size)
         // Raw height and width of image
         final int height = options.outHeight;
         final int width = options.outWidth;
@@ -260,5 +265,6 @@
             }
         }
         return inSampleSize;
+        // END_INCLUDE (calculate_sample_size)
     }
 }
diff --git a/samples/training/bitmapfun/BitmapFun/src/main/java/com/example/android/bitmapfun/util/ImageWorker.java b/samples/browseable/DisplayingBitmaps/src/com.example.android.displayingbitmaps/util/ImageWorker.java
similarity index 91%
rename from samples/training/bitmapfun/BitmapFun/src/main/java/com/example/android/bitmapfun/util/ImageWorker.java
rename to samples/browseable/DisplayingBitmaps/src/com.example.android.displayingbitmaps/util/ImageWorker.java
index d260660..f44d00d 100644
--- a/samples/training/bitmapfun/BitmapFun/src/main/java/com/example/android/bitmapfun/util/ImageWorker.java
+++ b/samples/browseable/DisplayingBitmaps/src/com.example.android.displayingbitmaps/util/ImageWorker.java
@@ -14,9 +14,7 @@
  * limitations under the License.
  */
 
-package com.example.android.bitmapfun.util;
-
-import com.example.android.bitmapfun.BuildConfig;
+package com.example.android.displayingbitmaps.util;
 
 import android.content.Context;
 import android.content.res.Resources;
@@ -28,9 +26,11 @@
 import android.graphics.drawable.TransitionDrawable;
 import android.support.v4.app.FragmentActivity;
 import android.support.v4.app.FragmentManager;
-import android.util.Log;
 import android.widget.ImageView;
 
+import com.example.android.common.logger.Log;
+import com.example.android.displayingbitmaps.BuildConfig;
+
 import java.lang.ref.WeakReference;
 
 /**
@@ -65,7 +65,7 @@
      * Load an image specified by the data parameter into an ImageView (override
      * {@link ImageWorker#processBitmap(Object)} to define the processing logic). A memory and
      * disk cache will be used if an {@link ImageCache} has been added using
-     * {@link ImageWorker#addImageCache(FragmentManager, ImageCache.ImageCacheParams)}. If the
+     * {@link ImageWorker#addImageCache(android.support.v4.app.FragmentManager, ImageCache.ImageCacheParams)}. If the
      * image is found in the memory cache, it is set immediately, otherwise an {@link AsyncTask}
      * will be created to asynchronously load the bitmap.
      *
@@ -87,7 +87,8 @@
             // Bitmap found in memory cache
             imageView.setImageDrawable(value);
         } else if (cancelPotentialWork(data, imageView)) {
-            final BitmapWorkerTask task = new BitmapWorkerTask(imageView);
+            //BEGIN_INCLUDE(execute_background_task)
+            final BitmapWorkerTask task = new BitmapWorkerTask(data, imageView);
             final AsyncDrawable asyncDrawable =
                     new AsyncDrawable(mResources, mLoadingBitmap, task);
             imageView.setImageDrawable(asyncDrawable);
@@ -95,7 +96,8 @@
             // NOTE: This uses a custom version of AsyncTask that has been pulled from the
             // framework and slightly modified. Refer to the docs at the top of the class
             // for more info on what was changed.
-            task.executeOnExecutor(AsyncTask.DUAL_THREAD_EXECUTOR, data);
+            task.executeOnExecutor(AsyncTask.DUAL_THREAD_EXECUTOR);
+            //END_INCLUDE(execute_background_task)
         }
     }
 
@@ -135,7 +137,7 @@
      * caching.
      * @param activity
      * @param diskCacheDirectoryName See
-     * {@link ImageCache.ImageCacheParams#ImageCacheParams(Context, String)}.
+     * {@link ImageCache.ImageCacheParams#ImageCacheParams(android.content.Context, String)}.
      */
     public void addImageCache(FragmentActivity activity, String diskCacheDirectoryName) {
         mImageCacheParams = new ImageCache.ImageCacheParams(activity, diskCacheDirectoryName);
@@ -161,7 +163,7 @@
      * example, you could resize a large bitmap here, or pull down an image from the network.
      *
      * @param data The data to identify which image to process, as provided by
-     *            {@link ImageWorker#loadImage(Object, ImageView)}
+     *            {@link ImageWorker#loadImage(Object, android.widget.ImageView)}
      * @return The processed bitmap
      */
     protected abstract Bitmap processBitmap(Object data);
@@ -182,7 +184,7 @@
         if (bitmapWorkerTask != null) {
             bitmapWorkerTask.cancel(true);
             if (BuildConfig.DEBUG) {
-                final Object bitmapData = bitmapWorkerTask.data;
+                final Object bitmapData = bitmapWorkerTask.mData;
                 Log.d(TAG, "cancelWork - cancelled work for " + bitmapData);
             }
         }
@@ -195,10 +197,11 @@
      * stopped in that case.
      */
     public static boolean cancelPotentialWork(Object data, ImageView imageView) {
+        //BEGIN_INCLUDE(cancel_potential_work)
         final BitmapWorkerTask bitmapWorkerTask = getBitmapWorkerTask(imageView);
 
         if (bitmapWorkerTask != null) {
-            final Object bitmapData = bitmapWorkerTask.data;
+            final Object bitmapData = bitmapWorkerTask.mData;
             if (bitmapData == null || !bitmapData.equals(data)) {
                 bitmapWorkerTask.cancel(true);
                 if (BuildConfig.DEBUG) {
@@ -210,6 +213,7 @@
             }
         }
         return true;
+        //END_INCLUDE(cancel_potential_work)
     }
 
     /**
@@ -231,11 +235,12 @@
     /**
      * The actual AsyncTask that will asynchronously process the image.
      */
-    private class BitmapWorkerTask extends AsyncTask<Object, Void, BitmapDrawable> {
-        private Object data;
+    private class BitmapWorkerTask extends AsyncTask<Void, Void, BitmapDrawable> {
+        private Object mData;
         private final WeakReference<ImageView> imageViewReference;
 
-        public BitmapWorkerTask(ImageView imageView) {
+        public BitmapWorkerTask(Object data, ImageView imageView) {
+            mData = data;
             imageViewReference = new WeakReference<ImageView>(imageView);
         }
 
@@ -243,13 +248,13 @@
          * Background processing.
          */
         @Override
-        protected BitmapDrawable doInBackground(Object... params) {
+        protected BitmapDrawable doInBackground(Void... params) {
+            //BEGIN_INCLUDE(load_bitmap_in_background)
             if (BuildConfig.DEBUG) {
                 Log.d(TAG, "doInBackground - starting work");
             }
 
-            data = params[0];
-            final String dataString = String.valueOf(data);
+            final String dataString = String.valueOf(mData);
             Bitmap bitmap = null;
             BitmapDrawable drawable = null;
 
@@ -277,7 +282,7 @@
             // process method (as implemented by a subclass)
             if (bitmap == null && !isCancelled() && getAttachedImageView() != null
                     && !mExitTasksEarly) {
-                bitmap = processBitmap(params[0]);
+                bitmap = processBitmap(mData);
             }
 
             // If the bitmap was processed and the image cache is available, then add the processed
@@ -304,6 +309,7 @@
             }
 
             return drawable;
+            //END_INCLUDE(load_bitmap_in_background)
         }
 
         /**
@@ -311,6 +317,7 @@
          */
         @Override
         protected void onPostExecute(BitmapDrawable value) {
+            //BEGIN_INCLUDE(complete_background_work)
             // if cancel was called on this task or the "exit early" flag is set then we're done
             if (isCancelled() || mExitTasksEarly) {
                 value = null;
@@ -323,6 +330,7 @@
                 }
                 setImageDrawable(imageView, value);
             }
+            //END_INCLUDE(complete_background_work)
         }
 
         @Override
diff --git a/samples/training/bitmapfun/BitmapFun/src/main/java/com/example/android/bitmapfun/util/RecyclingBitmapDrawable.java b/samples/browseable/DisplayingBitmaps/src/com.example.android.displayingbitmaps/util/RecyclingBitmapDrawable.java
similarity index 82%
rename from samples/training/bitmapfun/BitmapFun/src/main/java/com/example/android/bitmapfun/util/RecyclingBitmapDrawable.java
rename to samples/browseable/DisplayingBitmaps/src/com.example.android.displayingbitmaps/util/RecyclingBitmapDrawable.java
index 2aae97f..5534a6a 100644
--- a/samples/training/bitmapfun/BitmapFun/src/main/java/com/example/android/bitmapfun/util/RecyclingBitmapDrawable.java
+++ b/samples/browseable/DisplayingBitmaps/src/com.example.android.displayingbitmaps/util/RecyclingBitmapDrawable.java
@@ -14,23 +14,23 @@
  * limitations under the License.
  */
 
-package com.example.android.bitmapfun.util;
+package com.example.android.displayingbitmaps.util;
 
 import android.content.res.Resources;
 import android.graphics.Bitmap;
 import android.graphics.drawable.BitmapDrawable;
-import android.util.Log;
 
-import com.example.android.bitmapfun.BuildConfig;
+import com.example.android.common.logger.Log;
+import com.example.android.displayingbitmaps.BuildConfig;
 
 /**
  * A BitmapDrawable that keeps track of whether it is being displayed or cached.
  * When the drawable is no longer being displayed or cached,
- * {@link Bitmap#recycle() recycle()} will be called on this drawable's bitmap.
+ * {@link android.graphics.Bitmap#recycle() recycle()} will be called on this drawable's bitmap.
  */
 public class RecyclingBitmapDrawable extends BitmapDrawable {
 
-    static final String LOG_TAG = "CountingBitmapDrawable";
+    static final String TAG = "CountingBitmapDrawable";
 
     private int mCacheRefCount = 0;
     private int mDisplayRefCount = 0;
@@ -49,6 +49,7 @@
      * @param isDisplayed - Whether the drawable is being displayed or not
      */
     public void setIsDisplayed(boolean isDisplayed) {
+        //BEGIN_INCLUDE(set_is_displayed)
         synchronized (this) {
             if (isDisplayed) {
                 mDisplayRefCount++;
@@ -60,6 +61,7 @@
 
         // Check to see if recycle() can be called
         checkState();
+        //END_INCLUDE(set_is_displayed)
     }
 
     /**
@@ -69,6 +71,7 @@
      * @param isCached - Whether the drawable is being cached or not
      */
     public void setIsCached(boolean isCached) {
+        //BEGIN_INCLUDE(set_is_cached)
         synchronized (this) {
             if (isCached) {
                 mCacheRefCount++;
@@ -79,20 +82,23 @@
 
         // Check to see if recycle() can be called
         checkState();
+        //END_INCLUDE(set_is_cached)
     }
 
     private synchronized void checkState() {
+        //BEGIN_INCLUDE(check_state)
         // If the drawable cache and display ref counts = 0, and this drawable
         // has been displayed, then recycle
         if (mCacheRefCount <= 0 && mDisplayRefCount <= 0 && mHasBeenDisplayed
                 && hasValidBitmap()) {
             if (BuildConfig.DEBUG) {
-                Log.d(LOG_TAG, "No longer being used or cached so recycling. "
+                Log.d(TAG, "No longer being used or cached so recycling. "
                         + toString());
             }
 
             getBitmap().recycle();
         }
+        //END_INCLUDE(check_state)
     }
 
     private synchronized boolean hasValidBitmap() {
diff --git a/samples/training/bitmapfun/BitmapFun/src/main/java/com/example/android/bitmapfun/util/Utils.java b/samples/browseable/DisplayingBitmaps/src/com.example.android.displayingbitmaps/util/Utils.java
similarity index 79%
rename from samples/training/bitmapfun/BitmapFun/src/main/java/com/example/android/bitmapfun/util/Utils.java
rename to samples/browseable/DisplayingBitmaps/src/com.example.android.displayingbitmaps/util/Utils.java
index 31dc342..505d0ef 100644
--- a/samples/training/bitmapfun/BitmapFun/src/main/java/com/example/android/bitmapfun/util/Utils.java
+++ b/samples/browseable/DisplayingBitmaps/src/com.example.android.displayingbitmaps/util/Utils.java
@@ -14,15 +14,15 @@
  * limitations under the License.
  */
 
-package com.example.android.bitmapfun.util;
+package com.example.android.displayingbitmaps.util;
 
 import android.annotation.TargetApi;
 import android.os.Build;
 import android.os.Build.VERSION_CODES;
 import android.os.StrictMode;
 
-import com.example.android.bitmapfun.ui.ImageDetailActivity;
-import com.example.android.bitmapfun.ui.ImageGridActivity;
+import com.example.android.displayingbitmaps.ui.ImageDetailActivity;
+import com.example.android.displayingbitmaps.ui.ImageGridActivity;
 
 /**
  * Class containing some static utility methods.
@@ -57,26 +57,26 @@
     public static boolean hasFroyo() {
         // Can use static final constants like FROYO, declared in later versions
         // of the OS since they are inlined at compile time. This is guaranteed behavior.
-        return Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO;
+        return Build.VERSION.SDK_INT >= VERSION_CODES.FROYO;
     }
 
     public static boolean hasGingerbread() {
-        return Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD;
+        return Build.VERSION.SDK_INT >= VERSION_CODES.GINGERBREAD;
     }
 
     public static boolean hasHoneycomb() {
-        return Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB;
+        return Build.VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB;
     }
 
     public static boolean hasHoneycombMR1() {
-        return Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR1;
+        return Build.VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB_MR1;
     }
 
     public static boolean hasJellyBean() {
-        return Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN;
+        return Build.VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN;
     }
 
     public static boolean hasKitKat() {
-        return Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
+        return Build.VERSION.SDK_INT >= VERSION_CODES.KITKAT;
     }
 }
diff --git a/samples/browseable/DoneBar/res/values-sw600dp/dimens.xml b/samples/browseable/DoneBar/res/values-sw600dp/template-dimens.xml
similarity index 100%
rename from samples/browseable/DoneBar/res/values-sw600dp/dimens.xml
rename to samples/browseable/DoneBar/res/values-sw600dp/template-dimens.xml
diff --git a/samples/browseable/DoneBar/res/values-sw600dp/styles.xml b/samples/browseable/DoneBar/res/values-sw600dp/template-styles.xml
similarity index 100%
rename from samples/browseable/DoneBar/res/values-sw600dp/styles.xml
rename to samples/browseable/DoneBar/res/values-sw600dp/template-styles.xml
diff --git a/samples/browseable/DoneBar/res/values/dimens.xml b/samples/browseable/DoneBar/res/values/template-dimens.xml
similarity index 100%
rename from samples/browseable/DoneBar/res/values/dimens.xml
rename to samples/browseable/DoneBar/res/values/template-dimens.xml
diff --git a/samples/browseable/DoneBar/res/values/styles.xml b/samples/browseable/DoneBar/res/values/template-styles.xml
similarity index 100%
rename from samples/browseable/DoneBar/res/values/styles.xml
rename to samples/browseable/DoneBar/res/values/template-styles.xml
diff --git a/samples/browseable/HorizontalPaging/res/values-sw600dp/dimens.xml b/samples/browseable/HorizontalPaging/res/values-sw600dp/template-dimens.xml
similarity index 100%
rename from samples/browseable/HorizontalPaging/res/values-sw600dp/dimens.xml
rename to samples/browseable/HorizontalPaging/res/values-sw600dp/template-dimens.xml
diff --git a/samples/browseable/HorizontalPaging/res/values-sw600dp/styles.xml b/samples/browseable/HorizontalPaging/res/values-sw600dp/template-styles.xml
similarity index 100%
rename from samples/browseable/HorizontalPaging/res/values-sw600dp/styles.xml
rename to samples/browseable/HorizontalPaging/res/values-sw600dp/template-styles.xml
diff --git a/samples/browseable/HorizontalPaging/res/values/dimens.xml b/samples/browseable/HorizontalPaging/res/values/dimens.xml
index 39e710b..47c8224 100644
--- a/samples/browseable/HorizontalPaging/res/values/dimens.xml
+++ b/samples/browseable/HorizontalPaging/res/values/dimens.xml
@@ -1,32 +1,5 @@
-<!--
-  Copyright 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>
-
-    <!-- Define standard dimensions to comply with Holo-style grids and rhythm. -->
-
-    <dimen name="margin_tiny">4dp</dimen>
-    <dimen name="margin_small">8dp</dimen>
-    <dimen name="margin_medium">16dp</dimen>
-    <dimen name="margin_large">32dp</dimen>
-    <dimen name="margin_huge">64dp</dimen>
-
-    <!-- Semantic definitions -->
-
-    <dimen name="horizontal_page_margin">@dimen/margin_medium</dimen>
-    <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
-
+    <!-- Default screen margins, per the Android Design guidelines. -->
+    <dimen name="activity_horizontal_margin">16dp</dimen>
+    <dimen name="activity_vertical_margin">16dp</dimen>
 </resources>
diff --git a/samples/browseable/BasicNetworking/res/values/dimens.xml b/samples/browseable/HorizontalPaging/res/values/template-dimens.xml
similarity index 100%
copy from samples/browseable/BasicNetworking/res/values/dimens.xml
copy to samples/browseable/HorizontalPaging/res/values/template-dimens.xml
diff --git a/samples/browseable/HorizontalPaging/res/values/styles.xml b/samples/browseable/HorizontalPaging/res/values/template-styles.xml
similarity index 100%
rename from samples/browseable/HorizontalPaging/res/values/styles.xml
rename to samples/browseable/HorizontalPaging/res/values/template-styles.xml
diff --git a/samples/browseable/ImmersiveMode/res/values-sw600dp/dimens.xml b/samples/browseable/ImmersiveMode/res/values-sw600dp/template-dimens.xml
similarity index 100%
rename from samples/browseable/ImmersiveMode/res/values-sw600dp/dimens.xml
rename to samples/browseable/ImmersiveMode/res/values-sw600dp/template-dimens.xml
diff --git a/samples/browseable/ImmersiveMode/res/values-sw600dp/styles.xml b/samples/browseable/ImmersiveMode/res/values-sw600dp/template-styles.xml
similarity index 100%
rename from samples/browseable/ImmersiveMode/res/values-sw600dp/styles.xml
rename to samples/browseable/ImmersiveMode/res/values-sw600dp/template-styles.xml
diff --git a/samples/browseable/ImmersiveMode/res/values/dimens.xml b/samples/browseable/ImmersiveMode/res/values/template-dimens.xml
similarity index 100%
rename from samples/browseable/ImmersiveMode/res/values/dimens.xml
rename to samples/browseable/ImmersiveMode/res/values/template-dimens.xml
diff --git a/samples/browseable/ImmersiveMode/res/values/styles.xml b/samples/browseable/ImmersiveMode/res/values/template-styles.xml
similarity index 100%
rename from samples/browseable/ImmersiveMode/res/values/styles.xml
rename to samples/browseable/ImmersiveMode/res/values/template-styles.xml
diff --git a/samples/browseable/Basic/res/drawable-hdpi/tile.9.png b/samples/browseable/MediaRecorder/res/drawable-hdpi/tile.9.png
similarity index 100%
copy from samples/browseable/Basic/res/drawable-hdpi/tile.9.png
copy to samples/browseable/MediaRecorder/res/drawable-hdpi/tile.9.png
Binary files differ
diff --git a/samples/browseable/Basic/res/layout/activity_main.xml b/samples/browseable/MediaRecorder/res/layout/activity_main.xml
similarity index 100%
copy from samples/browseable/Basic/res/layout/activity_main.xml
copy to samples/browseable/MediaRecorder/res/layout/activity_main.xml
diff --git a/samples/browseable/DoneBar/res/values-sw600dp/dimens.xml b/samples/browseable/MediaRecorder/res/values-sw600dp/template-dimens.xml
similarity index 100%
copy from samples/browseable/DoneBar/res/values-sw600dp/dimens.xml
copy to samples/browseable/MediaRecorder/res/values-sw600dp/template-dimens.xml
diff --git a/samples/browseable/DoneBar/res/values-sw600dp/styles.xml b/samples/browseable/MediaRecorder/res/values-sw600dp/template-styles.xml
similarity index 100%
copy from samples/browseable/DoneBar/res/values-sw600dp/styles.xml
copy to samples/browseable/MediaRecorder/res/values-sw600dp/template-styles.xml
diff --git a/samples/browseable/repeatingAlarm/res/values/base-strings.xml b/samples/browseable/MediaRecorder/res/values/base-strings.xml
similarity index 70%
copy from samples/browseable/repeatingAlarm/res/values/base-strings.xml
copy to samples/browseable/MediaRecorder/res/values/base-strings.xml
index c11b89b..f9ade8c 100644
--- a/samples/browseable/repeatingAlarm/res/values/base-strings.xml
+++ b/samples/browseable/MediaRecorder/res/values/base-strings.xml
@@ -18,13 +18,14 @@
 
 
 <resources>
-    <string name="app_name">repeatingAlarm</string>
+    <string name="app_name">MediaRecorder</string>
     <string name="intro_message">
         <![CDATA[
         
             
-                Introductory text that explains what the sample is intended to demonstrate. Edit
-                in template-params.xml.
+            This sample uses the camera/camcorder as the A/V source for the MediaRecorder API.
+            A TextureView is used as the camera preview which limits the code to API 14+. This
+            can be easily replaced with a SurfaceView to run on older devices.
             
         
         ]]>
diff --git a/samples/browseable/DoneBar/res/values/dimens.xml b/samples/browseable/MediaRecorder/res/values/template-dimens.xml
similarity index 100%
copy from samples/browseable/DoneBar/res/values/dimens.xml
copy to samples/browseable/MediaRecorder/res/values/template-dimens.xml
diff --git a/samples/browseable/TextSwitcher/res/values/styles.xml b/samples/browseable/MediaRecorder/res/values/template-styles.xml
similarity index 100%
copy from samples/browseable/TextSwitcher/res/values/styles.xml
copy to samples/browseable/MediaRecorder/res/values/template-styles.xml
diff --git a/samples/browseable/MediaRecorder/src/com.example.android.common.media/CameraHelper.java b/samples/browseable/MediaRecorder/src/com.example.android.common.media/CameraHelper.java
new file mode 100644
index 0000000..1fa8416
--- /dev/null
+++ b/samples/browseable/MediaRecorder/src/com.example.android.common.media/CameraHelper.java
@@ -0,0 +1,182 @@
+/*
+ * 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.common.media;
+
+import android.annotation.TargetApi;
+import android.hardware.Camera;
+import android.os.Build;
+import android.os.Environment;
+import android.util.Log;
+
+import java.io.File;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * Camera related utilities.
+ */
+public class CameraHelper {
+
+    public static final int MEDIA_TYPE_IMAGE = 1;
+    public static final int MEDIA_TYPE_VIDEO = 2;
+
+    /**
+     * Iterate over supported camera preview sizes to see which one best fits the
+     * dimensions of the given view while maintaining the aspect ratio. If none can,
+     * be lenient with the aspect ratio.
+     *
+     * @param sizes Supported camera preview sizes.
+     * @param w The width of the view.
+     * @param h The height of the view.
+     * @return Best match camera preview size to fit in the view.
+     */
+    public static  Camera.Size getOptimalPreviewSize(List<Camera.Size> sizes, int w, int h) {
+        // Use a very small tolerance because we want an exact match.
+        final double ASPECT_TOLERANCE = 0.1;
+        double targetRatio = (double) w / h;
+        if (sizes == null)
+            return null;
+
+        Camera.Size optimalSize = null;
+
+        // Start with max value and refine as we iterate over available preview sizes. This is the
+        // minimum difference between view and camera height.
+        double minDiff = Double.MAX_VALUE;
+
+        // Target view height
+        int targetHeight = h;
+
+        // Try to find a preview size that matches aspect ratio and the target view size.
+        // Iterate over all available sizes and pick the largest size that can fit in the view and
+        // still maintain the aspect ratio.
+        for (Camera.Size size : sizes) {
+            double ratio = (double) size.width / size.height;
+            if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE)
+                continue;
+            if (Math.abs(size.height - targetHeight) < minDiff) {
+                optimalSize = size;
+                minDiff = Math.abs(size.height - targetHeight);
+            }
+        }
+
+        // Cannot find preview size that matches the aspect ratio, ignore the requirement
+        if (optimalSize == null) {
+            minDiff = Double.MAX_VALUE;
+            for (Camera.Size size : sizes) {
+                if (Math.abs(size.height - targetHeight) < minDiff) {
+                    optimalSize = size;
+                    minDiff = Math.abs(size.height - targetHeight);
+                }
+            }
+        }
+        return optimalSize;
+    }
+
+    /**
+     * @return the default camera on the device. Return null if there is no camera on the device.
+     */
+    public static Camera getDefaultCameraInstance() {
+        return Camera.open();
+    }
+
+
+    /**
+     * @return the default rear/back facing camera on the device. Returns null if camera is not
+     * available.
+     */
+    public static Camera getDefaultBackFacingCameraInstance() {
+        return getDefaultCamera(Camera.CameraInfo.CAMERA_FACING_BACK);
+    }
+
+    /**
+     * @return the default front facing camera on the device. Returns null if camera is not
+     * available.
+     */
+    public static Camera getDefaultFrontFacingCameraInstance() {
+        return getDefaultCamera(Camera.CameraInfo.CAMERA_FACING_FRONT);
+    }
+
+
+    /**
+     *
+     * @param position Physical position of the camera i.e Camera.CameraInfo.CAMERA_FACING_FRONT
+     *                 or Camera.CameraInfo.CAMERA_FACING_BACK.
+     * @return the default camera on the device. Returns null if camera is not available.
+     */
+    @TargetApi(Build.VERSION_CODES.GINGERBREAD)
+    private static Camera getDefaultCamera(int position) {
+        // Find the total number of cameras available
+        int  mNumberOfCameras = Camera.getNumberOfCameras();
+
+        // Find the ID of the back-facing ("default") camera
+        Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
+        for (int i = 0; i < mNumberOfCameras; i++) {
+            Camera.getCameraInfo(i, cameraInfo);
+            if (cameraInfo.facing == position) {
+                return Camera.open(i);
+
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * Creates a media file in the {@code Environment.DIRECTORY_PICTURES} directory. The directory
+     * is persistent and available to other applications like gallery.
+     *
+     * @param type Media type. Can be video or image.
+     * @return A file object pointing to the newly created file.
+     */
+    public  static File getOutputMediaFile(int type){
+        // To be safe, you should check that the SDCard is mounted
+        // using Environment.getExternalStorageState() before doing this.
+        if (!Environment.getExternalStorageState().equalsIgnoreCase(Environment.MEDIA_MOUNTED)) {
+            return  null;
+        }
+
+        File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(
+                Environment.DIRECTORY_PICTURES), "CameraSample");
+        // This location works best if you want the created images to be shared
+        // between applications and persist after your app has been uninstalled.
+
+        // Create the storage directory if it does not exist
+        if (! mediaStorageDir.exists()){
+            if (! mediaStorageDir.mkdirs()) {
+                Log.d("CameraSample", "failed to create directory");
+                return null;
+            }
+        }
+
+        // Create a media file name
+        String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
+        File mediaFile;
+        if (type == MEDIA_TYPE_IMAGE){
+            mediaFile = new File(mediaStorageDir.getPath() + File.separator +
+                    "IMG_"+ timeStamp + ".jpg");
+        } else if(type == MEDIA_TYPE_VIDEO) {
+            mediaFile = new File(mediaStorageDir.getPath() + File.separator +
+                    "VID_"+ timeStamp + ".mp4");
+        } else {
+            return null;
+        }
+
+        return mediaFile;
+    }
+
+}
diff --git a/samples/browseable/MediaRecorder/src/com.example.android.common.media/MediaCodecWrapper.java b/samples/browseable/MediaRecorder/src/com.example.android.common.media/MediaCodecWrapper.java
new file mode 100644
index 0000000..a511221
--- /dev/null
+++ b/samples/browseable/MediaRecorder/src/com.example.android.common.media/MediaCodecWrapper.java
@@ -0,0 +1,386 @@
+/*
+ * 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.common.media;
+
+import android.media.*;
+import android.os.Handler;
+import android.os.Looper;
+import android.view.Surface;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayDeque;
+import java.util.Queue;
+
+/**
+ * Simplifies the MediaCodec interface by wrapping around the buffer processing operations.
+ */
+public class MediaCodecWrapper {
+
+    // Handler to use for {@code OutputSampleListener} and {code OutputFormatChangedListener}
+    // callbacks
+    private Handler mHandler;
+
+
+    // Callback when media output format changes.
+    public interface OutputFormatChangedListener {
+        void outputFormatChanged(MediaCodecWrapper sender, MediaFormat newFormat);
+    }
+
+    private OutputFormatChangedListener mOutputFormatChangedListener = null;
+
+    /**
+     * Callback for decodes frames. Observers can register a listener for optional stream
+     * of decoded data
+     */
+    public interface OutputSampleListener {
+        void outputSample(MediaCodecWrapper sender, MediaCodec.BufferInfo info, ByteBuffer buffer);
+    }
+
+    /**
+     * The {@link MediaCodec} that is managed by this class.
+     */
+    private MediaCodec mDecoder;
+
+    // References to the internal buffers managed by the codec. The codec
+    // refers to these buffers by index, never by reference so it's up to us
+    // to keep track of which buffer is which.
+    private ByteBuffer[] mInputBuffers;
+    private ByteBuffer[] mOutputBuffers;
+
+    // Indices of the input buffers that are currently available for writing. We'll
+    // consume these in the order they were dequeued from the codec.
+    private Queue<Integer> mAvailableInputBuffers;
+
+    // Indices of the output buffers that currently hold valid data, in the order
+    // they were produced by the codec.
+    private Queue<Integer> mAvailableOutputBuffers;
+
+    // Information about each output buffer, by index. Each entry in this array
+    // is valid if and only if its index is currently contained in mAvailableOutputBuffers.
+    private MediaCodec.BufferInfo[] mOutputBufferInfo;
+
+    // An (optional) stream that will receive decoded data.
+    private OutputSampleListener mOutputSampleListener;
+
+    private MediaCodecWrapper(MediaCodec codec) {
+        mDecoder = codec;
+        codec.start();
+        mInputBuffers = codec.getInputBuffers();
+        mOutputBuffers = codec.getOutputBuffers();
+        mOutputBufferInfo = new MediaCodec.BufferInfo[mOutputBuffers.length];
+        mAvailableInputBuffers = new ArrayDeque<Integer>(mOutputBuffers.length);
+        mAvailableOutputBuffers = new ArrayDeque<Integer>(mInputBuffers.length);
+    }
+
+    /**
+     * Releases resources and ends the encoding/decoding session.
+     */
+    public void stopAndRelease() {
+        mDecoder.stop();
+        mDecoder.release();
+        mDecoder = null;
+        mHandler = null;
+    }
+
+    /**
+     * Getter for the registered {@link OutputFormatChangedListener}
+     */
+    public OutputFormatChangedListener getOutputFormatChangedListener() {
+        return mOutputFormatChangedListener;
+    }
+
+    /**
+     *
+     * @param outputFormatChangedListener the listener for callback.
+     * @param handler message handler for posting the callback.
+     */
+    public void setOutputFormatChangedListener(final OutputFormatChangedListener
+            outputFormatChangedListener, Handler handler) {
+        mOutputFormatChangedListener = outputFormatChangedListener;
+
+        // Making sure we don't block ourselves due to a bad implementation of the callback by
+        // using a handler provided by client.
+        Looper looper;
+        mHandler = handler;
+        if (outputFormatChangedListener != null && mHandler == null) {
+            if ((looper = Looper.myLooper()) != null) {
+                mHandler = new Handler();
+            } else {
+                throw new IllegalArgumentException(
+                        "Looper doesn't exist in the calling thread");
+            }
+        }
+    }
+
+    /**
+     * Constructs the {@link MediaCodecWrapper} wrapper object around the video codec.
+     * The codec is created using the encapsulated information in the
+     * {@link MediaFormat} object.
+     *
+     * @param trackFormat The format of the media object to be decoded.
+     * @param surface Surface to render the decoded frames.
+     * @return
+     */
+    public static MediaCodecWrapper fromVideoFormat(final MediaFormat trackFormat,
+            Surface surface) {
+        MediaCodecWrapper result = null;
+        MediaCodec videoCodec = null;
+
+        // BEGIN_INCLUDE(create_codec)
+        final String mimeType = trackFormat.getString(MediaFormat.KEY_MIME);
+
+        // Check to see if this is actually a video mime type. If it is, then create
+        // a codec that can decode this mime type.
+        if (mimeType.contains("video/")) {
+            videoCodec = MediaCodec.createDecoderByType(mimeType);
+            videoCodec.configure(trackFormat, surface, null,  0);
+
+        }
+
+        // If codec creation was successful, then create a wrapper object around the
+        // newly created codec.
+        if (videoCodec != null) {
+            result = new MediaCodecWrapper(videoCodec);
+        }
+        // END_INCLUDE(create_codec)
+
+        return result;
+    }
+
+
+    /**
+     * Write a media sample to the decoder.
+     *
+     * A "sample" here refers to a single atomic access unit in the media stream. The definition
+     * of "access unit" is dependent on the type of encoding used, but it typically refers to
+     * a single frame of video or a few seconds of audio. {@link android.media.MediaExtractor}
+     * extracts data from a stream one sample at a time.
+     *
+     * @param input A ByteBuffer containing the input data for one sample. The buffer must be set
+     * up for reading, with its position set to the beginning of the sample data and its limit
+     * set to the end of the sample data.
+     *
+     * @param presentationTimeUs  The time, relative to the beginning of the media stream,
+     * at which this buffer should be rendered.
+     *
+     * @param flags Flags to pass to the decoder. See {@link MediaCodec#queueInputBuffer(int,
+     * int, int, long, int)}
+     *
+     * @throws MediaCodec.CryptoException
+     */
+    public boolean writeSample(final ByteBuffer input,
+            final MediaCodec.CryptoInfo crypto,
+            final long presentationTimeUs,
+            final int flags) throws MediaCodec.CryptoException, WriteException {
+        boolean result = false;
+        int size = input.remaining();
+
+        // check if we have dequed input buffers available from the codec
+        if (size > 0 &&  !mAvailableInputBuffers.isEmpty()) {
+            int index = mAvailableInputBuffers.remove();
+            ByteBuffer buffer = mInputBuffers[index];
+
+            // we can't write our sample to a lesser capacity input buffer.
+            if (size > buffer.capacity()) {
+                throw new MediaCodecWrapper.WriteException(String.format(
+                        "Insufficient capacity in MediaCodec buffer: "
+                            + "tried to write %d, buffer capacity is %d.",
+                        input.remaining(),
+                        buffer.capacity()));
+            }
+
+            buffer.clear();
+            buffer.put(input);
+
+            // Submit the buffer to the codec for decoding. The presentationTimeUs
+            // indicates the position (play time) for the current sample.
+            if (crypto == null) {
+                mDecoder.queueInputBuffer(index, 0, size, presentationTimeUs, flags);
+            } else {
+                mDecoder.queueSecureInputBuffer(index, 0, crypto, presentationTimeUs, flags);
+            }
+            result = true;
+        }
+        return result;
+    }
+
+    static MediaCodec.CryptoInfo cryptoInfo= new MediaCodec.CryptoInfo();
+
+    /**
+     * Write a media sample to the decoder.
+     *
+     * A "sample" here refers to a single atomic access unit in the media stream. The definition
+     * of "access unit" is dependent on the type of encoding used, but it typically refers to
+     * a single frame of video or a few seconds of audio. {@link android.media.MediaExtractor}
+     * extracts data from a stream one sample at a time.
+     *
+     * @param extractor  Instance of {@link android.media.MediaExtractor} wrapping the media.
+     *
+     * @param presentationTimeUs The time, relative to the beginning of the media stream,
+     * at which this buffer should be rendered.
+     *
+     * @param flags  Flags to pass to the decoder. See {@link MediaCodec#queueInputBuffer(int,
+     * int, int, long, int)}
+     *
+     * @throws MediaCodec.CryptoException
+     */
+    public boolean writeSample(final MediaExtractor extractor,
+            final boolean isSecure,
+            final long presentationTimeUs,
+            int flags) {
+        boolean result = false;
+        boolean isEos = false;
+
+        if (!mAvailableInputBuffers.isEmpty()) {
+            int index = mAvailableInputBuffers.remove();
+            ByteBuffer buffer = mInputBuffers[index];
+
+            // reads the sample from the file using extractor into the buffer
+            int size = extractor.readSampleData(buffer, 0);
+            if (size <= 0) {
+                flags |= MediaCodec.BUFFER_FLAG_END_OF_STREAM;
+            }
+
+            // Submit the buffer to the codec for decoding. The presentationTimeUs
+            // indicates the position (play time) for the current sample.
+            if (!isSecure) {
+                mDecoder.queueInputBuffer(index, 0, size, presentationTimeUs, flags);
+            } else {
+                extractor.getSampleCryptoInfo(cryptoInfo);
+                mDecoder.queueSecureInputBuffer(index, 0, cryptoInfo, presentationTimeUs, flags);
+            }
+
+            result = true;
+        }
+        return result;
+    }
+
+    /**
+     * Performs a peek() operation in the queue to extract media info for the buffer ready to be
+     * released i.e. the head element of the queue.
+     *
+     * @param out_bufferInfo An output var to hold the buffer info.
+     *
+     * @return True, if the peek was successful.
+     */
+    public boolean peekSample(MediaCodec.BufferInfo out_bufferInfo) {
+        // dequeue available buffers and synchronize our data structures with the codec.
+        update();
+        boolean result = false;
+        if (!mAvailableOutputBuffers.isEmpty()) {
+            int index = mAvailableOutputBuffers.peek();
+            MediaCodec.BufferInfo info = mOutputBufferInfo[index];
+            // metadata of the sample
+            out_bufferInfo.set(
+                    info.offset,
+                    info.size,
+                    info.presentationTimeUs,
+                    info.flags);
+            result = true;
+        }
+        return result;
+    }
+
+    /**
+     * Processes, releases and optionally renders the output buffer available at the head of the
+     * queue. All observers are notified with a callback. See {@link
+     * OutputSampleListener#outputSample(MediaCodecWrapper, android.media.MediaCodec.BufferInfo,
+     * java.nio.ByteBuffer)}
+     *
+     * @param render True, if the buffer is to be rendered on the {@link Surface} configured
+     *
+     */
+    public void popSample(boolean render) {
+        // dequeue available buffers and synchronize our data structures with the codec.
+        update();
+        if (!mAvailableOutputBuffers.isEmpty()) {
+            int index = mAvailableOutputBuffers.remove();
+
+            if (render && mOutputSampleListener != null) {
+                ByteBuffer buffer = mOutputBuffers[index];
+                MediaCodec.BufferInfo info = mOutputBufferInfo[index];
+                mOutputSampleListener.outputSample(this, info, buffer);
+            }
+
+            // releases the buffer back to the codec
+            mDecoder.releaseOutputBuffer(index, render);
+        }
+    }
+
+    /**
+     * Synchronize this object's state with the internal state of the wrapped
+     * MediaCodec.
+     */
+    private void update() {
+        // BEGIN_INCLUDE(update_codec_state)
+        int index;
+
+        // Get valid input buffers from the codec to fill later in the same order they were
+        // made available by the codec.
+        while ((index = mDecoder.dequeueInputBuffer(0)) != MediaCodec.INFO_TRY_AGAIN_LATER) {
+            mAvailableInputBuffers.add(index);
+        }
+
+
+        // Likewise with output buffers. If the output buffers have changed, start using the
+        // new set of output buffers. If the output format has changed, notify listeners.
+        MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
+        while ((index = mDecoder.dequeueOutputBuffer(info, 0)) !=  MediaCodec.INFO_TRY_AGAIN_LATER) {
+            switch (index) {
+                case MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED:
+                    mOutputBuffers = mDecoder.getOutputBuffers();
+                    mOutputBufferInfo = new MediaCodec.BufferInfo[mOutputBuffers.length];
+                    mAvailableOutputBuffers.clear();
+                    break;
+                case MediaCodec.INFO_OUTPUT_FORMAT_CHANGED:
+                    if (mOutputFormatChangedListener != null) {
+                        mHandler.post(new Runnable() {
+                            @Override
+                            public void run() {
+                                mOutputFormatChangedListener
+                                        .outputFormatChanged(MediaCodecWrapper.this,
+                                                mDecoder.getOutputFormat());
+
+                            }
+                        });
+                    }
+                    break;
+                default:
+                    // Making sure the index is valid before adding to output buffers. We've already
+                    // handled INFO_TRY_AGAIN_LATER, INFO_OUTPUT_FORMAT_CHANGED &
+                    // INFO_OUTPUT_BUFFERS_CHANGED i.e all the other possible return codes but
+                    // asserting index value anyways for future-proofing the code.
+                    if(index >= 0) {
+                        mOutputBufferInfo[index] = info;
+                        mAvailableOutputBuffers.add(index);
+                    } else {
+                        throw new IllegalStateException("Unknown status from dequeueOutputBuffer");
+                    }
+                    break;
+            }
+
+        }
+        // END_INCLUDE(update_codec_state)
+
+    }
+
+    private class WriteException extends Throwable {
+        private WriteException(final String detailMessage) {
+            super(detailMessage);
+        }
+    }
+}
diff --git a/samples/browseable/MediaRouter/AndroidManifest.xml b/samples/browseable/MediaRouter/AndroidManifest.xml
new file mode 100644
index 0000000..0b5bec4
--- /dev/null
+++ b/samples/browseable/MediaRouter/AndroidManifest.xml
@@ -0,0 +1,75 @@
+<?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.
+-->
+
+<!-- Declare the contents of this Android application.  The namespace
+     attribute brings in the Android platform namespace, and the package
+     supplies a unique name for the application.  When writing your
+     own application, the package name must be changed from "com.example.*"
+     to come from a domain that you own or have control over. -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="com.example.android.mediarouter">
+    <!-- Permission for INTERNET is required for streaming video content
+         from the web, it's not required otherwise. -->
+    <uses-permission android:name="android.permission.INTERNET" />
+    <!-- Permission for SYSTEM_ALERT_WINDOW is only required for emulating
+         remote display using system alert window. -->
+    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
+
+    <uses-sdk android:targetSdkVersion="19"
+        android:minSdkVersion="7"/>
+
+    <!-- The smallest screen this app works on is a phone.  The app will
+         scale its UI to larger screens but doesn't make good use of them
+         so allow the compatibility mode button to be shown (mostly because
+         this is just convenient for testing). -->
+    <supports-screens android:requiresSmallestWidthDp="320"
+                      android:compatibleWidthLimitDp="480" />
+
+    <application android:label="@string/app_name"
+                 android:icon="@drawable/ic_launcher"
+                 android:hardwareAccelerated="true">
+
+        <receiver android:name=".player.SampleMediaButtonReceiver">
+            <intent-filter>
+                <action android:name="android.intent.action.MEDIA_BUTTON" />
+            </intent-filter>
+        </receiver>
+        <!-- MediaRouter Support Samples -->
+
+        <activity android:name=".player.MainActivity"
+                  android:label="@string/app_name"
+                  android:theme="@style/Theme.AppCompat.Light">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.DEFAULT" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="com.example.android.supportv7.SAMPLE_CODE" />
+            </intent-filter>
+        </activity>
+
+        <service android:name=".provider.SampleMediaRouteProviderService"
+                 android:label="@string/sample_media_route_provider_service"
+                 android:process=":mrp">
+            <intent-filter>
+                <action android:name="android.media.MediaRouteProviderService" />
+            </intent-filter>
+        </service>
+
+    </application>
+</manifest>
diff --git a/samples/browseable/MediaRouter/_index.jd b/samples/browseable/MediaRouter/_index.jd
new file mode 100644
index 0000000..5ca9467
--- /dev/null
+++ b/samples/browseable/MediaRouter/_index.jd
@@ -0,0 +1,10 @@
+
+
+
+page.tags="MediaRouter"
+sample.group=Media
+@jd:body
+
+<p>
+This sample demonstrates how to create a custom media route provider.
+</p>
\ No newline at end of file
diff --git a/samples/browseable/MediaRouter/res/drawable-hdpi/ic_action_pause.png b/samples/browseable/MediaRouter/res/drawable-hdpi/ic_action_pause.png
new file mode 100644
index 0000000..d30ba3c
--- /dev/null
+++ b/samples/browseable/MediaRouter/res/drawable-hdpi/ic_action_pause.png
Binary files differ
diff --git a/samples/browseable/MediaRouter/res/drawable-hdpi/ic_action_play.png b/samples/browseable/MediaRouter/res/drawable-hdpi/ic_action_play.png
new file mode 100644
index 0000000..869f001
--- /dev/null
+++ b/samples/browseable/MediaRouter/res/drawable-hdpi/ic_action_play.png
Binary files differ
diff --git a/samples/browseable/MediaRouter/res/drawable-hdpi/ic_action_stop.png b/samples/browseable/MediaRouter/res/drawable-hdpi/ic_action_stop.png
new file mode 100644
index 0000000..2b6c0f4
--- /dev/null
+++ b/samples/browseable/MediaRouter/res/drawable-hdpi/ic_action_stop.png
Binary files differ
diff --git a/samples/browseable/MediaRouter/res/drawable-hdpi/ic_launcher.png b/samples/browseable/MediaRouter/res/drawable-hdpi/ic_launcher.png
new file mode 100755
index 0000000..d340114
--- /dev/null
+++ b/samples/browseable/MediaRouter/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/MediaRouter/res/drawable-hdpi/ic_media_pause.png b/samples/browseable/MediaRouter/res/drawable-hdpi/ic_media_pause.png
new file mode 100644
index 0000000..1d465a4
--- /dev/null
+++ b/samples/browseable/MediaRouter/res/drawable-hdpi/ic_media_pause.png
Binary files differ
diff --git a/samples/browseable/MediaRouter/res/drawable-hdpi/ic_media_play.png b/samples/browseable/MediaRouter/res/drawable-hdpi/ic_media_play.png
new file mode 100644
index 0000000..2746d17
--- /dev/null
+++ b/samples/browseable/MediaRouter/res/drawable-hdpi/ic_media_play.png
Binary files differ
diff --git a/samples/browseable/MediaRouter/res/drawable-hdpi/ic_media_stop.png b/samples/browseable/MediaRouter/res/drawable-hdpi/ic_media_stop.png
new file mode 100644
index 0000000..a0ff136
--- /dev/null
+++ b/samples/browseable/MediaRouter/res/drawable-hdpi/ic_media_stop.png
Binary files differ
diff --git a/samples/browseable/MediaRouter/res/drawable-hdpi/ic_menu_add.png b/samples/browseable/MediaRouter/res/drawable-hdpi/ic_menu_add.png
new file mode 100644
index 0000000..444e8a5
--- /dev/null
+++ b/samples/browseable/MediaRouter/res/drawable-hdpi/ic_menu_add.png
Binary files differ
diff --git a/samples/browseable/MediaRouter/res/drawable-hdpi/ic_menu_delete.png b/samples/browseable/MediaRouter/res/drawable-hdpi/ic_menu_delete.png
new file mode 100644
index 0000000..24d8f6a
--- /dev/null
+++ b/samples/browseable/MediaRouter/res/drawable-hdpi/ic_menu_delete.png
Binary files differ
diff --git a/samples/browseable/Basic/res/drawable-hdpi/tile.9.png b/samples/browseable/MediaRouter/res/drawable-hdpi/tile.9.png
similarity index 100%
copy from samples/browseable/Basic/res/drawable-hdpi/tile.9.png
copy to samples/browseable/MediaRouter/res/drawable-hdpi/tile.9.png
Binary files differ
diff --git a/samples/browseable/MediaRouter/res/drawable-mdpi/ic_action_pause.png b/samples/browseable/MediaRouter/res/drawable-mdpi/ic_action_pause.png
new file mode 100644
index 0000000..2c96c7b
--- /dev/null
+++ b/samples/browseable/MediaRouter/res/drawable-mdpi/ic_action_pause.png
Binary files differ
diff --git a/samples/browseable/MediaRouter/res/drawable-mdpi/ic_action_play.png b/samples/browseable/MediaRouter/res/drawable-mdpi/ic_action_play.png
new file mode 100644
index 0000000..5f3bf86
--- /dev/null
+++ b/samples/browseable/MediaRouter/res/drawable-mdpi/ic_action_play.png
Binary files differ
diff --git a/samples/browseable/MediaRouter/res/drawable-mdpi/ic_action_stop.png b/samples/browseable/MediaRouter/res/drawable-mdpi/ic_action_stop.png
new file mode 100644
index 0000000..ddaf37a
--- /dev/null
+++ b/samples/browseable/MediaRouter/res/drawable-mdpi/ic_action_stop.png
Binary files differ
diff --git a/samples/browseable/MediaRouter/res/drawable-mdpi/ic_launcher.png b/samples/browseable/MediaRouter/res/drawable-mdpi/ic_launcher.png
new file mode 100755
index 0000000..6af9981
--- /dev/null
+++ b/samples/browseable/MediaRouter/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/MediaRouter/res/drawable-mdpi/ic_media_pause.png b/samples/browseable/MediaRouter/res/drawable-mdpi/ic_media_pause.png
new file mode 100644
index 0000000..3e6b2a1
--- /dev/null
+++ b/samples/browseable/MediaRouter/res/drawable-mdpi/ic_media_pause.png
Binary files differ
diff --git a/samples/browseable/MediaRouter/res/drawable-mdpi/ic_media_play.png b/samples/browseable/MediaRouter/res/drawable-mdpi/ic_media_play.png
new file mode 100644
index 0000000..7966bbc
--- /dev/null
+++ b/samples/browseable/MediaRouter/res/drawable-mdpi/ic_media_play.png
Binary files differ
diff --git a/samples/browseable/MediaRouter/res/drawable-mdpi/ic_media_stop.png b/samples/browseable/MediaRouter/res/drawable-mdpi/ic_media_stop.png
new file mode 100644
index 0000000..8ea7efe
--- /dev/null
+++ b/samples/browseable/MediaRouter/res/drawable-mdpi/ic_media_stop.png
Binary files differ
diff --git a/samples/browseable/MediaRouter/res/drawable-mdpi/ic_menu_add.png b/samples/browseable/MediaRouter/res/drawable-mdpi/ic_menu_add.png
new file mode 100644
index 0000000..361c7c4
--- /dev/null
+++ b/samples/browseable/MediaRouter/res/drawable-mdpi/ic_menu_add.png
Binary files differ
diff --git a/samples/browseable/MediaRouter/res/drawable-mdpi/ic_menu_delete.png b/samples/browseable/MediaRouter/res/drawable-mdpi/ic_menu_delete.png
new file mode 100644
index 0000000..e2c8700
--- /dev/null
+++ b/samples/browseable/MediaRouter/res/drawable-mdpi/ic_menu_delete.png
Binary files differ
diff --git a/samples/browseable/MediaRouter/res/drawable-xhdpi/ic_action_pause.png b/samples/browseable/MediaRouter/res/drawable-xhdpi/ic_action_pause.png
new file mode 100644
index 0000000..504389a
--- /dev/null
+++ b/samples/browseable/MediaRouter/res/drawable-xhdpi/ic_action_pause.png
Binary files differ
diff --git a/samples/browseable/MediaRouter/res/drawable-xhdpi/ic_action_play.png b/samples/browseable/MediaRouter/res/drawable-xhdpi/ic_action_play.png
new file mode 100644
index 0000000..7f709bb
--- /dev/null
+++ b/samples/browseable/MediaRouter/res/drawable-xhdpi/ic_action_play.png
Binary files differ
diff --git a/samples/browseable/MediaRouter/res/drawable-xhdpi/ic_action_stop.png b/samples/browseable/MediaRouter/res/drawable-xhdpi/ic_action_stop.png
new file mode 100644
index 0000000..2b07de4
--- /dev/null
+++ b/samples/browseable/MediaRouter/res/drawable-xhdpi/ic_action_stop.png
Binary files differ
diff --git a/samples/browseable/MediaRouter/res/drawable-xhdpi/ic_launcher.png b/samples/browseable/MediaRouter/res/drawable-xhdpi/ic_launcher.png
new file mode 100755
index 0000000..16bd612
--- /dev/null
+++ b/samples/browseable/MediaRouter/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/MediaRouter/res/drawable-xxhdpi/ic_action_pause.png b/samples/browseable/MediaRouter/res/drawable-xxhdpi/ic_action_pause.png
new file mode 100644
index 0000000..c3b376a
--- /dev/null
+++ b/samples/browseable/MediaRouter/res/drawable-xxhdpi/ic_action_pause.png
Binary files differ
diff --git a/samples/browseable/MediaRouter/res/drawable-xxhdpi/ic_action_play.png b/samples/browseable/MediaRouter/res/drawable-xxhdpi/ic_action_play.png
new file mode 100644
index 0000000..df59947
--- /dev/null
+++ b/samples/browseable/MediaRouter/res/drawable-xxhdpi/ic_action_play.png
Binary files differ
diff --git a/samples/browseable/MediaRouter/res/drawable-xxhdpi/ic_action_stop.png b/samples/browseable/MediaRouter/res/drawable-xxhdpi/ic_action_stop.png
new file mode 100644
index 0000000..f42d525
--- /dev/null
+++ b/samples/browseable/MediaRouter/res/drawable-xxhdpi/ic_action_stop.png
Binary files differ
diff --git a/samples/browseable/MediaRouter/res/drawable-xxhdpi/ic_launcher.png b/samples/browseable/MediaRouter/res/drawable-xxhdpi/ic_launcher.png
new file mode 100755
index 0000000..4b1d920
--- /dev/null
+++ b/samples/browseable/MediaRouter/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/MediaRouter/res/drawable-xxhdpi/ic_suggestions_add.png b/samples/browseable/MediaRouter/res/drawable-xxhdpi/ic_suggestions_add.png
new file mode 100644
index 0000000..b880d40
--- /dev/null
+++ b/samples/browseable/MediaRouter/res/drawable-xxhdpi/ic_suggestions_add.png
Binary files differ
diff --git a/samples/browseable/MediaRouter/res/drawable-xxhdpi/ic_suggestions_delete.png b/samples/browseable/MediaRouter/res/drawable-xxhdpi/ic_suggestions_delete.png
new file mode 100644
index 0000000..f9e2702
--- /dev/null
+++ b/samples/browseable/MediaRouter/res/drawable-xxhdpi/ic_suggestions_delete.png
Binary files differ
diff --git a/samples/browseable/MediaRouter/res/drawable/list_background.xml b/samples/browseable/MediaRouter/res/drawable/list_background.xml
new file mode 100644
index 0000000..be7240b
--- /dev/null
+++ b/samples/browseable/MediaRouter/res/drawable/list_background.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_pressed="true"
+          android:drawable="@color/list_highlight_color" />
+    <item
+          android:drawable="@android:color/transparent" />
+</selector>
diff --git a/samples/browseable/MediaRouter/res/layout-land/grid_layout_2.xml b/samples/browseable/MediaRouter/res/layout-land/grid_layout_2.xml
new file mode 100644
index 0000000..da16123
--- /dev/null
+++ b/samples/browseable/MediaRouter/res/layout-land/grid_layout_2.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 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.
+-->
+
+<android.support.v7.widget.GridLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:useDefaultMargins="true"
+    android:alignmentMode="alignBounds"
+    android:rowOrderPreserved="false"
+    android:columnCount="4"
+    >
+    <TextView
+        android:text="Email setup"
+        android:textSize="32dip"
+        android:layout_columnSpan="4"
+        android:layout_gravity="center_horizontal"
+    />
+    <TextView
+        android:text="You can configure email in a few simple steps:"
+        android:textSize="16dip"
+        android:layout_columnSpan="4"
+        android:layout_gravity="left"
+    />
+    <TextView
+        android:text="Email address:"
+        android:layout_gravity="right"
+    />
+    <EditText
+        android:ems="10"
+    />
+    <TextView
+        android:text="Password:"
+        android:layout_column="0"
+        android:layout_gravity="right"
+    />
+    <EditText
+        android:ems="8"
+    />
+    <Button
+        android:text="Manual setup"
+        android:layout_row="5"
+        android:layout_column="3"
+    />
+    <Button
+        android:text="Next"
+        android:layout_column="3"
+        android:layout_gravity="fill_horizontal"
+    />
+</android.support.v7.widget.GridLayout>
diff --git a/samples/browseable/Basic/res/layout/activity_main.xml b/samples/browseable/MediaRouter/res/layout/activity_main.xml
similarity index 100%
copy from samples/browseable/Basic/res/layout/activity_main.xml
copy to samples/browseable/MediaRouter/res/layout/activity_main.xml
diff --git a/samples/browseable/MediaRouter/res/layout/media_item.xml b/samples/browseable/MediaRouter/res/layout/media_item.xml
new file mode 100644
index 0000000..3a14861
--- /dev/null
+++ b/samples/browseable/MediaRouter/res/layout/media_item.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012 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.
+-->
+
+<!-- Layout for list item in Library or Playlist view. Displays ImageButton
+     instead of radio button to the right of the item. -->
+
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:orientation="horizontal"
+        android:clickable="true"
+        android:background="@drawable/list_background"
+        android:gravity="center_vertical">
+
+    <ImageButton android:id="@+id/item_action"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:minWidth="48dp"
+        android:minHeight="48dp"
+        android:layout_alignParentRight="true"
+        android:layout_centerVertical="true"
+        android:background="@null"/>
+
+    <TextView android:id="@+id/item_text"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:textAppearance="?android:attr/textAppearanceMedium"
+        android:layout_centerVertical="true"
+        android:layout_toLeftOf="@id/item_action"
+        android:layout_gravity="left"
+        android:gravity="left"/>
+</RelativeLayout>
diff --git a/samples/browseable/MediaRouter/res/layout/overlay_display_window.xml b/samples/browseable/MediaRouter/res/layout/overlay_display_window.xml
new file mode 100644
index 0000000..36b4a0d
--- /dev/null
+++ b/samples/browseable/MediaRouter/res/layout/overlay_display_window.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012 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:background="#000000">
+    <TextureView android:id="@+id/overlay_display_window_texture"
+               android:layout_width="0px"
+               android:layout_height="0px" />
+    <TextView android:id="@+id/overlay_display_window_title"
+               android:layout_width="wrap_content"
+               android:layout_height="wrap_content"
+               android:layout_gravity="top|center_horizontal" />
+</FrameLayout>
diff --git a/samples/browseable/MediaRouter/res/layout/sample_media_router.xml b/samples/browseable/MediaRouter/res/layout/sample_media_router.xml
new file mode 100644
index 0000000..1618418
--- /dev/null
+++ b/samples/browseable/MediaRouter/res/layout/sample_media_router.xml
@@ -0,0 +1,138 @@
+<?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.
+-->
+
+<!-- See corresponding Java code MainActivity.java. -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:orientation="vertical">
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        android:layout_weight="1"
+        android:orientation="vertical">
+        <!-- Tabs for media library, playlist and statistics -->
+        <TabHost android:id="@+id/tabHost"
+            android:layout_width="fill_parent"
+            android:layout_height="fill_parent"
+            android:layout_weight="1">
+            <LinearLayout
+                android:orientation="vertical"
+                android:layout_width="fill_parent"
+                android:layout_height="fill_parent">
+                <TabWidget android:id="@android:id/tabs"
+                    android:layout_width="fill_parent"
+                    android:layout_height="wrap_content" />
+
+                <FrameLayout android:id="@android:id/tabcontent"
+                    android:layout_width="fill_parent"
+                    android:layout_height="wrap_content">
+                    <LinearLayout android:id="@+id/tab1"
+                        android:layout_width="fill_parent"
+                        android:layout_height="wrap_content"
+                        android:orientation="vertical">
+                        <ListView android:id="@+id/media"
+                                  android:listSelector="@drawable/list_background"
+                            android:layout_width="match_parent"
+                            android:layout_height="wrap_content"
+                            android:layout_weight="1" />
+                    </LinearLayout>
+
+                    <LinearLayout android:id="@+id/tab2"
+                        android:layout_width="fill_parent"
+                        android:layout_height="fill_parent"
+                        android:orientation="vertical">
+                        <ListView android:id="@+id/playlist"
+                            android:layout_width="match_parent"
+                            android:layout_height="wrap_content"
+                            android:layout_weight="1"/>
+                    </LinearLayout>
+
+                    <LinearLayout android:id="@+id/tab3"
+                        android:layout_width="fill_parent"
+                        android:layout_height="fill_parent"
+                        android:orientation="vertical">
+                        <TextView android:id="@+id/info"
+                            android:layout_width="match_parent"
+                            android:layout_height="wrap_content"
+                            android:layout_weight="1"
+                            android:textAppearance="?android:attr/textAppearanceMedium"/>
+                    </LinearLayout>
+                </FrameLayout>
+            </LinearLayout>
+        </TabHost>
+
+        <!-- Control buttons for the currently selected route. -->
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_weight="0">
+
+            <SeekBar android:id="@+id/seekbar"
+                 android:layout_width="fill_parent"
+                 android:layout_height="wrap_content"
+                 style="?android:attr/progressBarStyleHorizontal"
+                 android:max="100"
+                 android:progress="0"
+                 android:layout_gravity="center"
+                 android:layout_weight="1"/>
+
+            <ImageButton android:id="@+id/pause_resume_button"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_weight="0"
+                android:layout_gravity="right"
+                android:minWidth="48dp"
+                android:minHeight="48dp"
+                android:background="@null"
+                android:src="@drawable/ic_action_pause" />
+
+            <ImageButton android:id="@+id/stop_button"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_weight="0"
+                android:layout_gravity="right"
+                android:minWidth="48dp"
+                android:minHeight="48dp"
+                android:background="@null"
+                android:src="@drawable/ic_action_stop" />
+        </LinearLayout>
+
+    </LinearLayout>
+
+    <!-- Some content for visual interest in the case where no presentation is showing. -->
+    <FrameLayout android:id="@+id/player"
+        android:background="#ff000000"
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        android:layout_weight="1">
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:gravity="center">
+            <SurfaceView android:id="@+id/surface_view"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"/>
+        </LinearLayout>
+        <TextView
+            android:textColor="#ffaaaaaa"
+            android:text="@string/sample_media_route_activity_local"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="top|center_horizontal" />
+    </FrameLayout>
+</LinearLayout>
diff --git a/samples/browseable/MediaRouter/res/layout/sample_media_router_presentation.xml b/samples/browseable/MediaRouter/res/layout/sample_media_router_presentation.xml
new file mode 100644
index 0000000..f029627
--- /dev/null
+++ b/samples/browseable/MediaRouter/res/layout/sample_media_router_presentation.xml
@@ -0,0 +1,38 @@
+<?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.
+-->
+
+<!-- The content that we show on secondary displays.
+     See corresponding Java code PresentationWithMediaRouterActivity.java. -->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:background="#ff000000">
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:gravity="center">
+        <SurfaceView android:id="@+id/surface_view"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"/>
+    </LinearLayout>
+    <TextView
+        android:textColor="#ffaaaaaa"
+        android:text="@string/sample_media_route_activity_presentation"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="top|center_horizontal" />
+</FrameLayout>
diff --git a/samples/browseable/MediaRouter/res/menu/sample_media_router_menu.xml b/samples/browseable/MediaRouter/res/menu/sample_media_router_menu.xml
new file mode 100644
index 0000000..8057fa8
--- /dev/null
+++ b/samples/browseable/MediaRouter/res/menu/sample_media_router_menu.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 Google Inc.
+
+     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"
+        xmlns:app="http://schemas.android.com/apk/res-auto">
+    <item android:id="@+id/media_route_menu_item"
+        android:title="@string/media_route_menu_title"
+        app:showAsAction="always"
+        app:actionProviderClass="android.support.v7.app.MediaRouteActionProvider"/>
+</menu>
diff --git a/samples/browseable/BasicMediaRouter/res/values-sw600dp/dimens.xml b/samples/browseable/MediaRouter/res/values-sw600dp/template-dimens.xml
similarity index 100%
copy from samples/browseable/BasicMediaRouter/res/values-sw600dp/dimens.xml
copy to samples/browseable/MediaRouter/res/values-sw600dp/template-dimens.xml
diff --git a/samples/browseable/BasicMediaRouter/res/values-sw600dp/styles.xml b/samples/browseable/MediaRouter/res/values-sw600dp/template-styles.xml
similarity index 100%
copy from samples/browseable/BasicMediaRouter/res/values-sw600dp/styles.xml
copy to samples/browseable/MediaRouter/res/values-sw600dp/template-styles.xml
diff --git a/samples/browseable/MediaRouter/res/values/arrays.xml b/samples/browseable/MediaRouter/res/values/arrays.xml
new file mode 100644
index 0000000..8d658eb
--- /dev/null
+++ b/samples/browseable/MediaRouter/res/values/arrays.xml
@@ -0,0 +1,31 @@
+<?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-array name="media_names">
+        <item>Big Buck Bunny</item>
+        <item>Elephants Dream</item>
+        <item>Sintel</item>
+        <item>Tears of Steel</item>
+    </string-array>
+
+    <string-array name="media_uris">
+        <item>http://archive.org/download/BigBuckBunny_328/BigBuckBunny_512kb.mp4</item>
+        <item>http://archive.org/download/ElephantsDream_277/elephant_dreams_640_512kb.mp4</item>
+        <item>http://archive.org/download/Sintel/sintel-2048-stereo_512kb.mp4</item>
+        <item>http://archive.org/download/Tears-of-Steel/tears_of_steel_720p.mp4</item>
+    </string-array>
+</resources>
diff --git a/samples/browseable/repeatingAlarm/res/values/base-strings.xml b/samples/browseable/MediaRouter/res/values/base-strings.xml
similarity index 77%
copy from samples/browseable/repeatingAlarm/res/values/base-strings.xml
copy to samples/browseable/MediaRouter/res/values/base-strings.xml
index c11b89b..8b494cc 100644
--- a/samples/browseable/repeatingAlarm/res/values/base-strings.xml
+++ b/samples/browseable/MediaRouter/res/values/base-strings.xml
@@ -18,14 +18,11 @@
 
 
 <resources>
-    <string name="app_name">repeatingAlarm</string>
+    <string name="app_name">MediaRouter</string>
     <string name="intro_message">
         <![CDATA[
         
-            
-                Introductory text that explains what the sample is intended to demonstrate. Edit
-                in template-params.xml.
-            
+            Demonstrates how to create a custom media route provider.
         
         ]]>
     </string>
diff --git a/samples/browseable/MediaRouter/res/values/colors.xml b/samples/browseable/MediaRouter/res/values/colors.xml
new file mode 100644
index 0000000..13cf3b5
--- /dev/null
+++ b/samples/browseable/MediaRouter/res/values/colors.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 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>
+    <drawable name="blue">#770000ff</drawable>
+    <color name="list_highlight_color">#ccc</color>
+</resources>
diff --git a/samples/browseable/MediaRouter/res/values/strings.xml b/samples/browseable/MediaRouter/res/values/strings.xml
new file mode 100644
index 0000000..c750ce1
--- /dev/null
+++ b/samples/browseable/MediaRouter/res/values/strings.xml
@@ -0,0 +1,40 @@
+<?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="sample_media_router_text">This activity demonstrates how to
+            use MediaRouter from the support library.  Select a route from the action bar.</string>
+    <string name="media_route_menu_title">Play on...</string>
+
+    <string name="library_tab_text">Library</string>
+    <string name="playlist_tab_text">Playlist</string>
+    <string name="statistics_tab_text">Statistics</string>
+
+    <string name="sample_media_route_provider_service">Media Route Provider Service Support Library Sample</string>
+    <string name="fixed_volume_route_name">Fixed Volume Remote Playback Route</string>
+    <string name="variable_volume_basic_route_name">Variable Volume (Basic) Remote Playback Route</string>
+    <string name="variable_volume_queuing_route_name">Variable Volume (Queuing) Remote Playback Route</string>
+    <string name="variable_volume_session_route_name">Variable Volume (Session) Remote Playback Route</string>
+    <string name="sample_route_description">Sample route</string>
+
+    <string name="sample_media_route_provider_remote">Remote Playback (Simulated)</string>
+    <string name="sample_media_route_activity_local">Local Playback</string>
+    <string name="sample_media_route_activity_presentation">Local Playback on Presentation Display</string>
+    <string name="playlist_item_added_text">Added to playlist!</string>
+    <string name="playlist_item_removed_text">Removed from playlist</string>
+
+</resources>
diff --git a/samples/browseable/BasicMediaRouter/res/values/dimens.xml b/samples/browseable/MediaRouter/res/values/template-dimens.xml
similarity index 100%
copy from samples/browseable/BasicMediaRouter/res/values/dimens.xml
copy to samples/browseable/MediaRouter/res/values/template-dimens.xml
diff --git a/samples/browseable/TextSwitcher/res/values/styles.xml b/samples/browseable/MediaRouter/res/values/template-styles.xml
similarity index 100%
copy from samples/browseable/TextSwitcher/res/values/styles.xml
copy to samples/browseable/MediaRouter/res/values/template-styles.xml
diff --git a/samples/browseable/repeatingAlarm/src/com.example.android.common/logger/Log.java b/samples/browseable/MediaRouter/src/com.example.android.common.logger/Log.java
similarity index 100%
copy from samples/browseable/repeatingAlarm/src/com.example.android.common/logger/Log.java
copy to samples/browseable/MediaRouter/src/com.example.android.common.logger/Log.java
diff --git a/samples/browseable/repeatingAlarm/src/com.example.android.common/logger/LogFragment.java b/samples/browseable/MediaRouter/src/com.example.android.common.logger/LogFragment.java
similarity index 100%
copy from samples/browseable/repeatingAlarm/src/com.example.android.common/logger/LogFragment.java
copy to samples/browseable/MediaRouter/src/com.example.android.common.logger/LogFragment.java
diff --git a/samples/browseable/repeatingAlarm/src/com.example.android.common/logger/LogNode.java b/samples/browseable/MediaRouter/src/com.example.android.common.logger/LogNode.java
similarity index 100%
copy from samples/browseable/repeatingAlarm/src/com.example.android.common/logger/LogNode.java
copy to samples/browseable/MediaRouter/src/com.example.android.common.logger/LogNode.java
diff --git a/samples/browseable/repeatingAlarm/src/com.example.android.common/logger/LogView.java b/samples/browseable/MediaRouter/src/com.example.android.common.logger/LogView.java
similarity index 100%
copy from samples/browseable/repeatingAlarm/src/com.example.android.common/logger/LogView.java
copy to samples/browseable/MediaRouter/src/com.example.android.common.logger/LogView.java
diff --git a/samples/browseable/repeatingAlarm/src/com.example.android.common/logger/LogWrapper.java b/samples/browseable/MediaRouter/src/com.example.android.common.logger/LogWrapper.java
similarity index 100%
copy from samples/browseable/repeatingAlarm/src/com.example.android.common/logger/LogWrapper.java
copy to samples/browseable/MediaRouter/src/com.example.android.common.logger/LogWrapper.java
diff --git a/samples/browseable/repeatingAlarm/src/com.example.android.common/logger/MessageOnlyLogFilter.java b/samples/browseable/MediaRouter/src/com.example.android.common.logger/MessageOnlyLogFilter.java
similarity index 100%
copy from samples/browseable/repeatingAlarm/src/com.example.android.common/logger/MessageOnlyLogFilter.java
copy to samples/browseable/MediaRouter/src/com.example.android.common.logger/MessageOnlyLogFilter.java
diff --git a/samples/browseable/MediaRouter/src/com.example.android.mediarouter/player/LocalPlayer.java b/samples/browseable/MediaRouter/src/com.example.android.mediarouter/player/LocalPlayer.java
new file mode 100644
index 0000000..86f5100
--- /dev/null
+++ b/samples/browseable/MediaRouter/src/com.example.android.mediarouter/player/LocalPlayer.java
@@ -0,0 +1,630 @@
+/*
+ * 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.mediarouter.player;
+
+import android.app.Activity;
+import android.app.Presentation;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.media.MediaPlayer;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.SystemClock;
+import android.support.v7.media.MediaItemStatus;
+import android.support.v7.media.MediaRouter.RouteInfo;
+import android.util.Log;
+import android.view.Display;
+import android.view.Gravity;
+import android.view.Surface;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.widget.FrameLayout;
+
+import com.example.android.mediarouter.R;
+
+import java.io.IOException;
+
+/**
+ * Handles playback of a single media item using MediaPlayer.
+ */
+public abstract class LocalPlayer extends Player implements
+        MediaPlayer.OnPreparedListener,
+        MediaPlayer.OnCompletionListener,
+        MediaPlayer.OnErrorListener,
+        MediaPlayer.OnSeekCompleteListener {
+    private static final String TAG = "LocalPlayer";
+    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
+    private static final int STATE_IDLE = 0;
+    private static final int STATE_PLAY_PENDING = 1;
+    private static final int STATE_READY = 2;
+    private static final int STATE_PLAYING = 3;
+    private static final int STATE_PAUSED = 4;
+
+    private final Context mContext;
+    private final Handler mHandler = new Handler();
+    private MediaPlayer mMediaPlayer;
+    private int mState = STATE_IDLE;
+    private int mSeekToPos;
+    private int mVideoWidth;
+    private int mVideoHeight;
+    private Surface mSurface;
+    private SurfaceHolder mSurfaceHolder;
+
+    public LocalPlayer(Context context) {
+        mContext = context;
+
+        // reset media player
+        reset();
+    }
+
+    @Override
+    public boolean isRemotePlayback() {
+        return false;
+    }
+
+    @Override
+    public boolean isQueuingSupported() {
+        return false;
+    }
+
+    @Override
+    public void connect(RouteInfo route) {
+        if (DEBUG) {
+            Log.d(TAG, "connecting to: " + route);
+        }
+    }
+
+    @Override
+    public void release() {
+        if (DEBUG) {
+            Log.d(TAG, "releasing");
+        }
+        // release media player
+        if (mMediaPlayer != null) {
+            mMediaPlayer.stop();
+            mMediaPlayer.release();
+            mMediaPlayer = null;
+        }
+    }
+
+    // Player
+    @Override
+    public void play(final PlaylistItem item) {
+        if (DEBUG) {
+            Log.d(TAG, "play: item=" + item);
+        }
+        reset();
+        mSeekToPos = (int)item.getPosition();
+        try {
+            mMediaPlayer.setDataSource(mContext, item.getUri());
+            mMediaPlayer.prepareAsync();
+        } catch (IllegalStateException e) {
+            Log.e(TAG, "MediaPlayer throws IllegalStateException, uri=" + item.getUri());
+        } catch (IOException e) {
+            Log.e(TAG, "MediaPlayer throws IOException, uri=" + item.getUri());
+        } catch (IllegalArgumentException e) {
+            Log.e(TAG, "MediaPlayer throws IllegalArgumentException, uri=" + item.getUri());
+        } catch (SecurityException e) {
+            Log.e(TAG, "MediaPlayer throws SecurityException, uri=" + item.getUri());
+        }
+        if (item.getState() == MediaItemStatus.PLAYBACK_STATE_PLAYING) {
+            resume();
+        } else {
+            pause();
+        }
+    }
+
+    @Override
+    public void seek(final PlaylistItem item) {
+        if (DEBUG) {
+            Log.d(TAG, "seek: item=" + item);
+        }
+        int pos = (int)item.getPosition();
+        if (mState == STATE_PLAYING || mState == STATE_PAUSED) {
+            mMediaPlayer.seekTo(pos);
+            mSeekToPos = pos;
+        } else if (mState == STATE_IDLE || mState == STATE_PLAY_PENDING) {
+            // Seek before onPrepared() arrives,
+            // need to performed delayed seek in onPrepared()
+            mSeekToPos = pos;
+        }
+    }
+
+    @Override
+    public void getStatus(final PlaylistItem item, final boolean update) {
+        if (mState == STATE_PLAYING || mState == STATE_PAUSED) {
+            // use mSeekToPos if we're currently seeking (mSeekToPos is reset
+            // when seeking is completed)
+            item.setDuration(mMediaPlayer.getDuration());
+            item.setPosition(mSeekToPos > 0 ?
+                    mSeekToPos : mMediaPlayer.getCurrentPosition());
+            item.setTimestamp(SystemClock.elapsedRealtime());
+        }
+        if (update && mCallback != null) {
+            mCallback.onPlaylistReady();
+        }
+    }
+
+    @Override
+    public void pause() {
+        if (DEBUG) {
+            Log.d(TAG, "pause");
+        }
+        if (mState == STATE_PLAYING) {
+            mMediaPlayer.pause();
+            mState = STATE_PAUSED;
+        }
+    }
+
+    @Override
+    public void resume() {
+        if (DEBUG) {
+            Log.d(TAG, "resume");
+        }
+        if (mState == STATE_READY || mState == STATE_PAUSED) {
+            mMediaPlayer.start();
+            mState = STATE_PLAYING;
+        } else if (mState == STATE_IDLE){
+            mState = STATE_PLAY_PENDING;
+        }
+    }
+
+    @Override
+    public void stop() {
+        if (DEBUG) {
+            Log.d(TAG, "stop");
+        }
+        if (mState == STATE_PLAYING || mState == STATE_PAUSED) {
+            mMediaPlayer.stop();
+            mState = STATE_IDLE;
+        }
+    }
+
+    @Override
+    public void enqueue(final PlaylistItem item) {
+        throw new UnsupportedOperationException("LocalPlayer doesn't support enqueue!");
+    }
+
+    @Override
+    public PlaylistItem remove(String iid) {
+        throw new UnsupportedOperationException("LocalPlayer doesn't support remove!");
+    }
+
+    //MediaPlayer Listeners
+    @Override
+    public void onPrepared(MediaPlayer mp) {
+        if (DEBUG) {
+            Log.d(TAG, "onPrepared");
+        }
+        mHandler.post(new Runnable() {
+            @Override
+            public void run() {
+                if (mState == STATE_IDLE) {
+                    mState = STATE_READY;
+                    updateVideoRect();
+                } else if (mState == STATE_PLAY_PENDING) {
+                    mState = STATE_PLAYING;
+                    updateVideoRect();
+                    if (mSeekToPos > 0) {
+                        if (DEBUG) {
+                            Log.d(TAG, "seek to initial pos: " + mSeekToPos);
+                        }
+                        mMediaPlayer.seekTo(mSeekToPos);
+                    }
+                    mMediaPlayer.start();
+                }
+                if (mCallback != null) {
+                    mCallback.onPlaylistChanged();
+                }
+            }
+        });
+    }
+
+    @Override
+    public void onCompletion(MediaPlayer mp) {
+        if (DEBUG) {
+            Log.d(TAG, "onCompletion");
+        }
+        mHandler.post(new Runnable() {
+            @Override
+            public void run() {
+                if (mCallback != null) {
+                    mCallback.onCompletion();
+                }
+            }
+        });
+    }
+
+    @Override
+    public boolean onError(MediaPlayer mp, int what, int extra) {
+        if (DEBUG) {
+            Log.d(TAG, "onError");
+        }
+        mHandler.post(new Runnable() {
+            @Override
+            public void run() {
+                if (mCallback != null) {
+                    mCallback.onError();
+                }
+            }
+        });
+        // return true so that onCompletion is not called
+        return true;
+    }
+
+    @Override
+    public void onSeekComplete(MediaPlayer mp) {
+        if (DEBUG) {
+            Log.d(TAG, "onSeekComplete");
+        }
+        mHandler.post(new Runnable() {
+            @Override
+            public void run() {
+                mSeekToPos = 0;
+                if (mCallback != null) {
+                    mCallback.onPlaylistChanged();
+                }
+            }
+        });
+    }
+
+    protected Context getContext() { return mContext; }
+    protected MediaPlayer getMediaPlayer() { return mMediaPlayer; }
+    protected int getVideoWidth() { return mVideoWidth; }
+    protected int getVideoHeight() { return mVideoHeight; }
+    protected void setSurface(Surface surface) {
+        mSurface = surface;
+        mSurfaceHolder = null;
+        updateSurface();
+    }
+
+    protected void setSurface(SurfaceHolder surfaceHolder) {
+        mSurface = null;
+        mSurfaceHolder = surfaceHolder;
+        updateSurface();
+    }
+
+    protected void removeSurface(SurfaceHolder surfaceHolder) {
+        if (surfaceHolder == mSurfaceHolder) {
+            setSurface((SurfaceHolder)null);
+        }
+    }
+
+    protected void updateSurface() {
+        if (mMediaPlayer == null) {
+            // just return if media player is already gone
+            return;
+        }
+        if (mSurface != null) {
+            // The setSurface API does not exist until V14+.
+            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
+                ICSMediaPlayer.setSurface(mMediaPlayer, mSurface);
+            } else {
+                throw new UnsupportedOperationException("MediaPlayer does not support "
+                        + "setSurface() on this version of the platform.");
+            }
+        } else if (mSurfaceHolder != null) {
+            mMediaPlayer.setDisplay(mSurfaceHolder);
+        } else {
+            mMediaPlayer.setDisplay(null);
+        }
+    }
+
+    protected abstract void updateSize();
+
+    private void reset() {
+        if (mMediaPlayer != null) {
+            mMediaPlayer.stop();
+            mMediaPlayer.release();
+            mMediaPlayer = null;
+        }
+        mMediaPlayer = new MediaPlayer();
+        mMediaPlayer.setOnPreparedListener(this);
+        mMediaPlayer.setOnCompletionListener(this);
+        mMediaPlayer.setOnErrorListener(this);
+        mMediaPlayer.setOnSeekCompleteListener(this);
+        updateSurface();
+        mState = STATE_IDLE;
+        mSeekToPos = 0;
+    }
+
+    private void updateVideoRect() {
+        if (mState != STATE_IDLE && mState != STATE_PLAY_PENDING) {
+            int width = mMediaPlayer.getVideoWidth();
+            int height = mMediaPlayer.getVideoHeight();
+            if (width > 0 && height > 0) {
+                mVideoWidth = width;
+                mVideoHeight = height;
+                updateSize();
+            } else {
+                Log.e(TAG, "video rect is 0x0!");
+                mVideoWidth = mVideoHeight = 0;
+            }
+        }
+    }
+
+    private static final class ICSMediaPlayer {
+        public static final void setSurface(MediaPlayer player, Surface surface) {
+            player.setSurface(surface);
+        }
+    }
+
+    /**
+     * Handles playback of a single media item using MediaPlayer in SurfaceView
+     */
+    public static class SurfaceViewPlayer extends LocalPlayer implements
+            SurfaceHolder.Callback {
+        private static final String TAG = "SurfaceViewPlayer";
+        private RouteInfo mRoute;
+        private final SurfaceView mSurfaceView;
+        private final FrameLayout mLayout;
+        private DemoPresentation mPresentation;
+
+        public SurfaceViewPlayer(Context context) {
+            super(context);
+
+            mLayout = (FrameLayout)((Activity)context).findViewById(R.id.player);
+            mSurfaceView = (SurfaceView)((Activity)context).findViewById(R.id.surface_view);
+
+            // add surface holder callback
+            SurfaceHolder holder = mSurfaceView.getHolder();
+            holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
+            holder.addCallback(this);
+        }
+
+        @Override
+        public void connect(RouteInfo route) {
+            super.connect(route);
+            mRoute = route;
+        }
+
+        @Override
+        public void release() {
+            super.release();
+
+            // dismiss presentation display
+            if (mPresentation != null) {
+                Log.i(TAG, "Dismissing presentation because the activity is no longer visible.");
+                mPresentation.dismiss();
+                mPresentation = null;
+            }
+
+            // remove surface holder callback
+            SurfaceHolder holder = mSurfaceView.getHolder();
+            holder.removeCallback(this);
+
+            // hide the surface view when SurfaceViewPlayer is destroyed
+            mSurfaceView.setVisibility(View.GONE);
+            mLayout.setVisibility(View.GONE);
+        }
+
+        @Override
+        public void updatePresentation() {
+            // Get the current route and its presentation display.
+            Display presentationDisplay = mRoute != null ? mRoute.getPresentationDisplay() : null;
+
+            // Dismiss the current presentation if the display has changed.
+            if (mPresentation != null && mPresentation.getDisplay() != presentationDisplay) {
+                Log.i(TAG, "Dismissing presentation because the current route no longer "
+                        + "has a presentation display.");
+                mPresentation.dismiss();
+                mPresentation = null;
+            }
+
+            // Show a new presentation if needed.
+            if (mPresentation == null && presentationDisplay != null) {
+                Log.i(TAG, "Showing presentation on display: " + presentationDisplay);
+                mPresentation = new DemoPresentation(getContext(), presentationDisplay);
+                mPresentation.setOnDismissListener(mOnDismissListener);
+                try {
+                    mPresentation.show();
+                } catch (WindowManager.InvalidDisplayException ex) {
+                    Log.w(TAG, "Couldn't show presentation!  Display was removed in "
+                              + "the meantime.", ex);
+                    mPresentation = null;
+                }
+            }
+
+            updateContents();
+        }
+
+        // SurfaceHolder.Callback
+        @Override
+        public void surfaceChanged(SurfaceHolder holder, int format,
+                int width, int height) {
+            if (DEBUG) {
+                Log.d(TAG, "surfaceChanged: " + width + "x" + height);
+            }
+            setSurface(holder);
+        }
+
+        @Override
+        public void surfaceCreated(SurfaceHolder holder) {
+            if (DEBUG) {
+                Log.d(TAG, "surfaceCreated");
+            }
+            setSurface(holder);
+            updateSize();
+        }
+
+        @Override
+        public void surfaceDestroyed(SurfaceHolder holder) {
+            if (DEBUG) {
+                Log.d(TAG, "surfaceDestroyed");
+            }
+            removeSurface(holder);
+        }
+
+        @Override
+        protected void updateSize() {
+            int width = getVideoWidth();
+            int height = getVideoHeight();
+            if (width > 0 && height > 0) {
+                if (mPresentation == null) {
+                    int surfaceWidth = mLayout.getWidth();
+                    int surfaceHeight = mLayout.getHeight();
+
+                    // Calculate the new size of mSurfaceView, so that video is centered
+                    // inside the framelayout with proper letterboxing/pillarboxing
+                    ViewGroup.LayoutParams lp = mSurfaceView.getLayoutParams();
+                    if (surfaceWidth * height < surfaceHeight * width) {
+                        // Black bars on top&bottom, mSurfaceView has full layout width,
+                        // while height is derived from video's aspect ratio
+                        lp.width = surfaceWidth;
+                        lp.height = surfaceWidth * height / width;
+                    } else {
+                        // Black bars on left&right, mSurfaceView has full layout height,
+                        // while width is derived from video's aspect ratio
+                        lp.width = surfaceHeight * width / height;
+                        lp.height = surfaceHeight;
+                    }
+                    Log.i(TAG, "video rect is " + lp.width + "x" + lp.height);
+                    mSurfaceView.setLayoutParams(lp);
+                } else {
+                    mPresentation.updateSize(width, height);
+                }
+            }
+        }
+
+        private void updateContents() {
+            // Show either the content in the main activity or the content in the presentation
+            if (mPresentation != null) {
+                mLayout.setVisibility(View.GONE);
+                mSurfaceView.setVisibility(View.GONE);
+            } else {
+                mLayout.setVisibility(View.VISIBLE);
+                mSurfaceView.setVisibility(View.VISIBLE);
+            }
+        }
+
+        // Listens for when presentations are dismissed.
+        private final DialogInterface.OnDismissListener mOnDismissListener =
+                new DialogInterface.OnDismissListener() {
+            @Override
+            public void onDismiss(DialogInterface dialog) {
+                if (dialog == mPresentation) {
+                    Log.i(TAG, "Presentation dismissed.");
+                    mPresentation = null;
+                    updateContents();
+                }
+            }
+        };
+
+        // Presentation
+        private final class DemoPresentation extends Presentation {
+            private SurfaceView mPresentationSurfaceView;
+
+            public DemoPresentation(Context context, Display display) {
+                super(context, display);
+            }
+
+            @Override
+            protected void onCreate(Bundle savedInstanceState) {
+                // Be sure to call the super class.
+                super.onCreate(savedInstanceState);
+
+                // Inflate the layout.
+                setContentView(R.layout.sample_media_router_presentation);
+
+                // Set up the surface view.
+                mPresentationSurfaceView = (SurfaceView)findViewById(R.id.surface_view);
+                SurfaceHolder holder = mPresentationSurfaceView.getHolder();
+                holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
+                holder.addCallback(SurfaceViewPlayer.this);
+                Log.i(TAG, "Presentation created");
+            }
+
+            public void updateSize(int width, int height) {
+                int surfaceHeight = getWindow().getDecorView().getHeight();
+                int surfaceWidth = getWindow().getDecorView().getWidth();
+                ViewGroup.LayoutParams lp = mPresentationSurfaceView.getLayoutParams();
+                if (surfaceWidth * height < surfaceHeight * width) {
+                    lp.width = surfaceWidth;
+                    lp.height = surfaceWidth * height / width;
+                } else {
+                    lp.width = surfaceHeight * width / height;
+                    lp.height = surfaceHeight;
+                }
+                Log.i(TAG, "Presentation video rect is " + lp.width + "x" + lp.height);
+                mPresentationSurfaceView.setLayoutParams(lp);
+            }
+        }
+    }
+
+    /**
+     * Handles playback of a single media item using MediaPlayer in
+     * OverlayDisplayWindow.
+     */
+    public static class OverlayPlayer extends LocalPlayer implements
+            OverlayDisplayWindow.OverlayWindowListener {
+        private static final String TAG = "OverlayPlayer";
+        private final OverlayDisplayWindow mOverlay;
+
+        public OverlayPlayer(Context context) {
+            super(context);
+
+            mOverlay = OverlayDisplayWindow.create(getContext(),
+                    getContext().getResources().getString(
+                            R.string.sample_media_route_provider_remote),
+                    1024, 768, Gravity.CENTER);
+
+            mOverlay.setOverlayWindowListener(this);
+        }
+
+        @Override
+        public void connect(RouteInfo route) {
+            super.connect(route);
+            mOverlay.show();
+        }
+
+        @Override
+        public void release() {
+            super.release();
+            mOverlay.dismiss();
+        }
+
+        @Override
+        protected void updateSize() {
+            int width = getVideoWidth();
+            int height = getVideoHeight();
+            if (width > 0 && height > 0) {
+                mOverlay.updateAspectRatio(width, height);
+            }
+        }
+
+        // OverlayDisplayWindow.OverlayWindowListener
+        @Override
+        public void onWindowCreated(Surface surface) {
+            setSurface(surface);
+        }
+
+        @Override
+        public void onWindowCreated(SurfaceHolder surfaceHolder) {
+            setSurface(surfaceHolder);
+        }
+
+        @Override
+        public void onWindowDestroyed() {
+            setSurface((SurfaceHolder)null);
+        }
+    }
+}
diff --git a/samples/browseable/MediaRouter/src/com.example.android.mediarouter/player/MainActivity.java b/samples/browseable/MediaRouter/src/com.example.android.mediarouter/player/MainActivity.java
new file mode 100644
index 0000000..ad283dd
--- /dev/null
+++ b/samples/browseable/MediaRouter/src/com.example.android.mediarouter/player/MainActivity.java
@@ -0,0 +1,724 @@
+/*
+ * 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.mediarouter.player;
+
+import android.app.PendingIntent;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.media.AudioManager;
+import android.media.AudioManager.OnAudioFocusChangeListener;
+import android.media.RemoteControlClient;
+import android.net.Uri;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.Environment;
+import android.os.Handler;
+import android.os.SystemClock;
+import android.support.v4.app.FragmentManager;
+import android.support.v4.view.MenuItemCompat;
+import android.support.v7.app.ActionBarActivity;
+import android.support.v7.app.MediaRouteActionProvider;
+import android.support.v7.app.MediaRouteDiscoveryFragment;
+import android.support.v7.media.MediaControlIntent;
+import android.support.v7.media.MediaItemStatus;
+import android.support.v7.media.MediaRouteSelector;
+import android.support.v7.media.MediaRouter;
+import android.support.v7.media.MediaRouter.Callback;
+import android.support.v7.media.MediaRouter.ProviderInfo;
+import android.support.v7.media.MediaRouter.RouteInfo;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.AdapterView.OnItemClickListener;
+import android.widget.ArrayAdapter;
+import android.widget.ImageButton;
+import android.widget.ListView;
+import android.widget.SeekBar;
+import android.widget.SeekBar.OnSeekBarChangeListener;
+import android.widget.TabHost;
+import android.widget.TabHost.OnTabChangeListener;
+import android.widget.TabHost.TabSpec;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import com.example.android.mediarouter.R;
+import com.example.android.mediarouter.provider.SampleMediaRouteProvider;
+
+import java.io.File;
+
+/**
+ * <h3>Media Router Support Activity</h3>
+ * <p/>
+ * <p>
+ * This demonstrates how to use the {@link MediaRouter} API to build an
+ * application that allows the user to send content to various rendering
+ * targets.
+ * </p>
+ */
+public class MainActivity extends ActionBarActivity {
+    private static final String TAG = "MainActivity";
+    private static final String DISCOVERY_FRAGMENT_TAG = "DiscoveryFragment";
+
+    private MediaRouter mMediaRouter;
+    private MediaRouteSelector mSelector;
+    private LibraryAdapter mLibraryItems;
+    private PlaylistAdapter mPlayListItems;
+    private TextView mInfoTextView;
+    private ListView mLibraryView;
+    private ListView mPlayListView;
+    private ImageButton mPauseResumeButton;
+    private ImageButton mStopButton;
+    private SeekBar mSeekBar;
+    private boolean mPaused;
+    private boolean mNeedResume;
+    private boolean mSeeking;
+
+    private RemoteControlClient mRemoteControlClient;
+    private ComponentName mEventReceiver;
+    private AudioManager mAudioManager;
+    private PendingIntent mMediaPendingIntent;
+
+    private final Handler mHandler = new Handler();
+    private final Runnable mUpdateSeekRunnable = new Runnable() {
+        @Override
+        public void run() {
+            updateProgress();
+            // update UI every 1 second
+            mHandler.postDelayed(this, 1000);
+        }
+    };
+
+    private final SessionManager mSessionManager = new SessionManager("app");
+    private Player mPlayer;
+
+    private final MediaRouter.Callback mMediaRouterCB = new MediaRouter.Callback() {
+        // Return a custom callback that will simply log all of the route events
+        // for demonstration purposes.
+        @Override
+        public void onRouteAdded(MediaRouter router, RouteInfo route) {
+            Log.d(TAG, "onRouteAdded: route=" + route);
+        }
+
+        @Override
+        public void onRouteChanged(MediaRouter router, RouteInfo route) {
+            Log.d(TAG, "onRouteChanged: route=" + route);
+        }
+
+        @Override
+        public void onRouteRemoved(MediaRouter router, RouteInfo route) {
+            Log.d(TAG, "onRouteRemoved: route=" + route);
+        }
+
+        @Override
+        public void onRouteSelected(MediaRouter router, RouteInfo route) {
+            Log.d(TAG, "onRouteSelected: route=" + route);
+
+            mPlayer = Player.create(MainActivity.this, route);
+            mPlayer.updatePresentation();
+            mSessionManager.setPlayer(mPlayer);
+            mSessionManager.unsuspend();
+
+            registerRemoteControlClient();
+            updateUi();
+        }
+
+        @Override
+        public void onRouteUnselected(MediaRouter router, RouteInfo route) {
+            Log.d(TAG, "onRouteUnselected: route=" + route);
+            unregisterRemoteControlClient();
+
+            PlaylistItem item = getCheckedPlaylistItem();
+            if (item != null) {
+                long pos = item.getPosition() +
+                        (mPaused ? 0 : (SystemClock.elapsedRealtime() - item.getTimestamp()));
+                mSessionManager.suspend(pos);
+            }
+            mPlayer.updatePresentation();
+            mPlayer.release();
+        }
+
+        @Override
+        public void onRouteVolumeChanged(MediaRouter router, RouteInfo route) {
+            Log.d(TAG, "onRouteVolumeChanged: route=" + route);
+        }
+
+        @Override
+        public void onRoutePresentationDisplayChanged(MediaRouter router, RouteInfo route) {
+            Log.d(TAG, "onRoutePresentationDisplayChanged: route=" + route);
+            mPlayer.updatePresentation();
+        }
+
+        @Override
+        public void onProviderAdded(MediaRouter router, ProviderInfo provider) {
+            Log.d(TAG, "onRouteProviderAdded: provider=" + provider);
+        }
+
+        @Override
+        public void onProviderRemoved(MediaRouter router, ProviderInfo provider) {
+            Log.d(TAG, "onRouteProviderRemoved: provider=" + provider);
+        }
+
+        @Override
+        public void onProviderChanged(MediaRouter router, ProviderInfo provider) {
+            Log.d(TAG, "onRouteProviderChanged: provider=" + provider);
+        }
+    };
+
+    private final OnAudioFocusChangeListener mAfChangeListener = new OnAudioFocusChangeListener() {
+        @Override
+        public void onAudioFocusChange(int focusChange) {
+            if (focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT) {
+                Log.d(TAG, "onAudioFocusChange: LOSS_TRANSIENT");
+            } else if (focusChange == AudioManager.AUDIOFOCUS_GAIN) {
+                Log.d(TAG, "onAudioFocusChange: AUDIOFOCUS_GAIN");
+            } else if (focusChange == AudioManager.AUDIOFOCUS_LOSS) {
+                Log.d(TAG, "onAudioFocusChange: AUDIOFOCUS_LOSS");
+            }
+        }
+    };
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        // Be sure to call the super class.
+        super.onCreate(savedInstanceState);
+        if (savedInstanceState != null) {
+            mPlayer = (Player) savedInstanceState.getSerializable("mPlayer");
+        }
+
+        // Get the media router service.
+        mMediaRouter = MediaRouter.getInstance(this);
+
+        // Create a route selector for the type of routes that we care about.
+        mSelector =
+                new MediaRouteSelector.Builder().addControlCategory(MediaControlIntent
+                        .CATEGORY_LIVE_AUDIO).addControlCategory(MediaControlIntent
+                        .CATEGORY_LIVE_VIDEO).addControlCategory(MediaControlIntent
+                        .CATEGORY_REMOTE_PLAYBACK).addControlCategory(SampleMediaRouteProvider
+                        .CATEGORY_SAMPLE_ROUTE).build();
+
+        // Add a fragment to take care of media route discovery.
+        // This fragment automatically adds or removes a callback whenever the activity
+        // is started or stopped.
+        FragmentManager fm = getSupportFragmentManager();
+        DiscoveryFragment fragment =
+                (DiscoveryFragment) fm.findFragmentByTag(DISCOVERY_FRAGMENT_TAG);
+        if (fragment == null) {
+            fragment = new DiscoveryFragment(mMediaRouterCB);
+            fragment.setRouteSelector(mSelector);
+            fm.beginTransaction().add(fragment, DISCOVERY_FRAGMENT_TAG).commit();
+        } else {
+            fragment.setCallback(mMediaRouterCB);
+            fragment.setRouteSelector(mSelector);
+        }
+
+        // Populate an array adapter with streaming media items.
+        String[] mediaNames = getResources().getStringArray(R.array.media_names);
+        String[] mediaUris = getResources().getStringArray(R.array.media_uris);
+        mLibraryItems = new LibraryAdapter();
+        for (int i = 0; i < mediaNames.length; i++) {
+            mLibraryItems.add(new MediaItem(
+                    "[streaming] " + mediaNames[i], Uri.parse(mediaUris[i]), "video/mp4"));
+        }
+
+        // Scan local external storage directory for media files.
+        File externalDir = Environment.getExternalStorageDirectory();
+        if (externalDir != null) {
+            File list[] = externalDir.listFiles();
+            if (list != null) {
+                for (int i = 0; i < list.length; i++) {
+                    String filename = list[i].getName();
+                    if (filename.matches(".*\\.(m4v|mp4)")) {
+                        mLibraryItems.add(new MediaItem(
+                                "[local] " + filename, Uri.fromFile(list[i]), "video/mp4"));
+                    }
+                }
+            }
+        }
+
+        mPlayListItems = new PlaylistAdapter();
+
+        // Initialize the layout.
+        setContentView(R.layout.sample_media_router);
+
+        TabHost tabHost = (TabHost) findViewById(R.id.tabHost);
+        tabHost.setup();
+        String tabName = getResources().getString(R.string.library_tab_text);
+        TabSpec spec1 = tabHost.newTabSpec(tabName);
+        spec1.setContent(R.id.tab1);
+        spec1.setIndicator(tabName);
+
+        tabName = getResources().getString(R.string.playlist_tab_text);
+        TabSpec spec2 = tabHost.newTabSpec(tabName);
+        spec2.setIndicator(tabName);
+        spec2.setContent(R.id.tab2);
+
+        tabName = getResources().getString(R.string.statistics_tab_text);
+        TabSpec spec3 = tabHost.newTabSpec(tabName);
+        spec3.setIndicator(tabName);
+        spec3.setContent(R.id.tab3);
+
+        tabHost.addTab(spec1);
+        tabHost.addTab(spec2);
+        tabHost.addTab(spec3);
+        tabHost.setOnTabChangedListener(new OnTabChangeListener() {
+            @Override
+            public void onTabChanged(String arg0) {
+                updateUi();
+            }
+        });
+
+        mLibraryView = (ListView) findViewById(R.id.media);
+        mLibraryView.setAdapter(mLibraryItems);
+        mLibraryView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
+        mLibraryView.setOnItemClickListener(new OnItemClickListener() {
+            @Override
+            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+                updateButtons();
+            }
+        });
+
+        mPlayListView = (ListView) findViewById(R.id.playlist);
+        mPlayListView.setAdapter(mPlayListItems);
+        mPlayListView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
+        mPlayListView.setOnItemClickListener(new OnItemClickListener() {
+            @Override
+            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+                updateButtons();
+            }
+        });
+
+        mInfoTextView = (TextView) findViewById(R.id.info);
+
+        mPauseResumeButton = (ImageButton) findViewById(R.id.pause_resume_button);
+        mPauseResumeButton.setOnClickListener(new OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                mPaused = !mPaused;
+                if (mPaused) {
+                    mSessionManager.pause();
+                } else {
+                    mSessionManager.resume();
+                }
+            }
+        });
+
+        mStopButton = (ImageButton) findViewById(R.id.stop_button);
+        mStopButton.setOnClickListener(new OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                mPaused = false;
+                mSessionManager.stop();
+            }
+        });
+
+        mSeekBar = (SeekBar) findViewById(R.id.seekbar);
+        mSeekBar.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
+            @Override
+            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
+                PlaylistItem item = getCheckedPlaylistItem();
+                if (fromUser && item != null && item.getDuration() > 0) {
+                    long pos = progress * item.getDuration() / 100;
+                    mSessionManager.seek(item.getItemId(), pos);
+                    item.setPosition(pos);
+                    item.setTimestamp(SystemClock.elapsedRealtime());
+                }
+            }
+
+            @Override
+            public void onStartTrackingTouch(SeekBar seekBar) {
+                mSeeking = true;
+            }
+
+            @Override
+            public void onStopTrackingTouch(SeekBar seekBar) {
+                mSeeking = false;
+                updateUi();
+            }
+        });
+
+        // Schedule Ui update
+        mHandler.postDelayed(mUpdateSeekRunnable, 1000);
+
+        // Build the PendingIntent for the remote control client
+        mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
+        mEventReceiver =
+                new ComponentName(getPackageName(), SampleMediaButtonReceiver.class.getName());
+        Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
+        mediaButtonIntent.setComponent(mEventReceiver);
+        mMediaPendingIntent = PendingIntent.getBroadcast(this, 0, mediaButtonIntent, 0);
+
+        // Create and register the remote control client
+        registerRemoteControlClient();
+
+        // Set up playback manager and player
+        mPlayer = Player.create(MainActivity.this, mMediaRouter.getSelectedRoute());
+        mSessionManager.setPlayer(mPlayer);
+        mSessionManager.setCallback(new SessionManager.Callback() {
+            @Override
+            public void onStatusChanged() {
+                updateUi();
+            }
+
+            @Override
+            public void onItemChanged(PlaylistItem item) {
+            }
+        });
+
+        updateUi();
+    }
+
+    private void registerRemoteControlClient() {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
+            // Create the RCC and register with AudioManager and MediaRouter
+            mAudioManager.requestAudioFocus(mAfChangeListener, AudioManager.STREAM_MUSIC,
+                    AudioManager.AUDIOFOCUS_GAIN);
+            mAudioManager.registerMediaButtonEventReceiver(mEventReceiver);
+            mRemoteControlClient = new RemoteControlClient(mMediaPendingIntent);
+            mAudioManager.registerRemoteControlClient(mRemoteControlClient);
+            mMediaRouter.addRemoteControlClient(mRemoteControlClient);
+            SampleMediaButtonReceiver.setActivity(MainActivity.this);
+            mRemoteControlClient.setTransportControlFlags(RemoteControlClient
+                    .FLAG_KEY_MEDIA_PLAY_PAUSE);
+            mRemoteControlClient.setPlaybackState(RemoteControlClient.PLAYSTATE_PLAYING);
+        }
+    }
+
+    private void unregisterRemoteControlClient() {
+        // Unregister the RCC with AudioManager and MediaRouter
+        if (mRemoteControlClient != null) {
+            mRemoteControlClient.setTransportControlFlags(0);
+            mAudioManager.abandonAudioFocus(mAfChangeListener);
+            mAudioManager.unregisterMediaButtonEventReceiver(mEventReceiver);
+            mAudioManager.unregisterRemoteControlClient(mRemoteControlClient);
+            mMediaRouter.removeRemoteControlClient(mRemoteControlClient);
+            SampleMediaButtonReceiver.setActivity(null);
+            mRemoteControlClient = null;
+        }
+    }
+
+    public boolean handleMediaKey(KeyEvent event) {
+        if (event.getAction() == KeyEvent.ACTION_DOWN && event.getRepeatCount() == 0) {
+            switch (event.getKeyCode()) {
+                case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE: {
+                    Log.d(TAG, "Received Play/Pause event from RemoteControlClient");
+                    mPaused = !mPaused;
+                    if (mPaused) {
+                        mSessionManager.pause();
+                    } else {
+                        mSessionManager.resume();
+                    }
+                    return true;
+                }
+                case KeyEvent.KEYCODE_MEDIA_PLAY: {
+                    Log.d(TAG, "Received Play event from RemoteControlClient");
+                    if (mPaused) {
+                        mPaused = false;
+                        mSessionManager.resume();
+                    }
+                    return true;
+                }
+                case KeyEvent.KEYCODE_MEDIA_PAUSE: {
+                    Log.d(TAG, "Received Pause event from RemoteControlClient");
+                    if (!mPaused) {
+                        mPaused = true;
+                        mSessionManager.pause();
+                    }
+                    return true;
+                }
+                case KeyEvent.KEYCODE_MEDIA_STOP: {
+                    Log.d(TAG, "Received Stop event from RemoteControlClient");
+                    mPaused = false;
+                    mSessionManager.stop();
+                    return true;
+                }
+                default:
+                    break;
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public boolean onKeyDown(int keyCode, KeyEvent event) {
+        return handleMediaKey(event) || super.onKeyDown(keyCode, event);
+    }
+
+    @Override
+    public boolean onKeyUp(int keyCode, KeyEvent event) {
+        return handleMediaKey(event) || super.onKeyUp(keyCode, event);
+    }
+
+    @Override
+    public void onStart() {
+        // Be sure to call the super class.
+        super.onStart();
+    }
+
+    @Override
+    public void onPause() {
+        // pause media player for local playback case only
+        if (!mPlayer.isRemotePlayback() && !mPaused) {
+            mNeedResume = true;
+            mSessionManager.pause();
+        }
+        super.onPause();
+    }
+
+    @Override
+    public void onResume() {
+        // resume media player for local playback case only
+        if (!mPlayer.isRemotePlayback() && mNeedResume) {
+            mSessionManager.resume();
+            mNeedResume = false;
+        }
+        super.onResume();
+    }
+
+    @Override
+    public void onDestroy() {
+        // Unregister the remote control client
+        unregisterRemoteControlClient();
+
+        mPaused = false;
+        mSessionManager.stop();
+        mPlayer.release();
+        super.onDestroy();
+    }
+
+    @Override
+    public boolean onCreateOptionsMenu(Menu menu) {
+        // Be sure to call the super class.
+        super.onCreateOptionsMenu(menu);
+
+        // Inflate the menu and configure the media router action provider.
+        getMenuInflater().inflate(R.menu.sample_media_router_menu, menu);
+
+        MenuItem mediaRouteMenuItem = menu.findItem(R.id.media_route_menu_item);
+        MediaRouteActionProvider mediaRouteActionProvider =
+                (MediaRouteActionProvider) MenuItemCompat.getActionProvider(mediaRouteMenuItem);
+        mediaRouteActionProvider.setRouteSelector(mSelector);
+
+        // Return true to show the menu.
+        return true;
+    }
+
+    private void updateProgress() {
+        // Estimate content position from last status time and elapsed time.
+        // (Note this might be slightly out of sync with remote side, however
+        // it avoids frequent polling the MRP.)
+        int progress = 0;
+        PlaylistItem item = getCheckedPlaylistItem();
+        if (item != null) {
+            int state = item.getState();
+            long duration = item.getDuration();
+            if (duration <= 0) {
+                if (state == MediaItemStatus.PLAYBACK_STATE_PLAYING ||
+                        state == MediaItemStatus.PLAYBACK_STATE_PAUSED) {
+                    mSessionManager.updateStatus();
+                }
+            } else {
+                long position = item.getPosition();
+                long timeDelta =
+                        mPaused ? 0 : (SystemClock.elapsedRealtime() - item.getTimestamp());
+                progress = (int) (100.0 * (position + timeDelta) / duration);
+            }
+        }
+        mSeekBar.setProgress(progress);
+    }
+
+    private void updateUi() {
+        updatePlaylist();
+        updateRouteDescription();
+        updateButtons();
+    }
+
+    private void updatePlaylist() {
+        mPlayListItems.clear();
+        for (PlaylistItem item : mSessionManager.getPlaylist()) {
+            mPlayListItems.add(item);
+        }
+        mPlayListView.invalidate();
+    }
+
+
+    private void updateRouteDescription() {
+        RouteInfo route = mMediaRouter.getSelectedRoute();
+        mInfoTextView.setText(
+                "Currently selected route:" + "\nName: " + route.getName() + "\nProvider: " +
+                        route.getProvider().getPackageName() + "\nDescription: " +
+                        route.getDescription() + "\nStatistics: " +
+                        mSessionManager.getStatistics());
+    }
+
+    private void updateButtons() {
+        MediaRouter.RouteInfo route = mMediaRouter.getSelectedRoute();
+        // show pause or resume icon depending on current state
+        mPauseResumeButton.setImageResource(
+                mPaused ? R.drawable.ic_action_play : R.drawable.ic_action_pause);
+        // disable pause/resume/stop if no session
+        mPauseResumeButton.setEnabled(mSessionManager.hasSession());
+        mStopButton.setEnabled(mSessionManager.hasSession());
+        // only enable seek bar when duration is known
+        PlaylistItem item = getCheckedPlaylistItem();
+        mSeekBar.setEnabled(item != null && item.getDuration() > 0);
+        if (mRemoteControlClient != null) {
+            mRemoteControlClient.setPlaybackState(mPaused ? RemoteControlClient.PLAYSTATE_PAUSED :
+                    RemoteControlClient.PLAYSTATE_PLAYING);
+        }
+    }
+
+    private PlaylistItem getCheckedPlaylistItem() {
+        int count = mPlayListView.getCount();
+        int index = mPlayListView.getCheckedItemPosition();
+        if (count > 0) {
+            if (index < 0 || index >= count) {
+                index = 0;
+                mPlayListView.setItemChecked(0, true);
+            }
+            return mPlayListItems.getItem(index);
+        }
+        return null;
+    }
+
+    public static final class DiscoveryFragment extends MediaRouteDiscoveryFragment {
+        private static final String TAG = "DiscoveryFragment";
+        private Callback mCallback;
+
+        public DiscoveryFragment() {
+            mCallback = null;
+        }
+
+        public DiscoveryFragment(Callback cb) {
+            mCallback = cb;
+        }
+
+        public void setCallback(Callback cb) {
+            mCallback = cb;
+        }
+
+        @Override
+        public Callback onCreateCallback() {
+            return mCallback;
+        }
+
+        @Override
+        public int onPrepareCallbackFlags() {
+            // Add the CALLBACK_FLAG_UNFILTERED_EVENTS flag to ensure that we will
+            // observe and log all route events including those that are for routes
+            // that do not match our selector.  This is only for demonstration purposes
+            // and should not be needed by most applications.
+            return super.onPrepareCallbackFlags() | MediaRouter.CALLBACK_FLAG_UNFILTERED_EVENTS;
+        }
+    }
+
+    private static final class MediaItem {
+        public final String mName;
+        public final Uri mUri;
+        public final String mMime;
+
+        public MediaItem(String name, Uri uri, String mime) {
+            mName = name;
+            mUri = uri;
+            mMime = mime;
+        }
+
+        @Override
+        public String toString() {
+            return mName;
+        }
+    }
+
+    private final class LibraryAdapter extends ArrayAdapter<MediaItem> {
+        public LibraryAdapter() {
+            super(MainActivity.this, R.layout.media_item);
+        }
+
+        @Override
+        public View getView(int position, View convertView, ViewGroup parent) {
+            final View v;
+            if (convertView == null) {
+                v = getLayoutInflater().inflate(R.layout.media_item, null);
+            } else {
+                v = convertView;
+            }
+
+            final MediaItem item = getItem(position);
+
+            TextView tv = (TextView) v.findViewById(R.id.item_text);
+            tv.setText(item.mName);
+
+            ImageButton b = (ImageButton) v.findViewById(R.id.item_action);
+            b.setImageResource(R.drawable.ic_suggestions_add);
+            b.setTag(item);
+            b.setOnClickListener(new OnClickListener() {
+                @Override
+                public void onClick(View v) {
+                    if (item != null) {
+                        mSessionManager.add(item.mUri, item.mMime);
+                        Toast.makeText(MainActivity.this, R.string.playlist_item_added_text,
+                                Toast.LENGTH_SHORT).show();
+                    }
+                }
+            });
+
+            return v;
+        }
+    }
+
+    private final class PlaylistAdapter extends ArrayAdapter<PlaylistItem> {
+        public PlaylistAdapter() {
+            super(MainActivity.this, R.layout.media_item);
+        }
+
+        @Override
+        public View getView(int position, View convertView, ViewGroup parent) {
+            final View v;
+            if (convertView == null) {
+                v = getLayoutInflater().inflate(R.layout.media_item, null);
+            } else {
+                v = convertView;
+            }
+
+            final PlaylistItem item = getItem(position);
+
+            TextView tv = (TextView) v.findViewById(R.id.item_text);
+            tv.setText(item.toString());
+
+            ImageButton b = (ImageButton) v.findViewById(R.id.item_action);
+            b.setImageResource(R.drawable.ic_suggestions_delete);
+            b.setTag(item);
+            b.setOnClickListener(new OnClickListener() {
+                @Override
+                public void onClick(View v) {
+                    if (item != null) {
+                        mSessionManager.remove(item.getItemId());
+                        Toast.makeText(MainActivity.this, R.string.playlist_item_removed_text,
+                                Toast.LENGTH_SHORT).show();
+                    }
+                }
+            });
+
+            return v;
+        }
+    }
+}
diff --git a/samples/browseable/MediaRouter/src/com.example.android.mediarouter/player/OverlayDisplayWindow.java b/samples/browseable/MediaRouter/src/com.example.android.mediarouter/player/OverlayDisplayWindow.java
new file mode 100644
index 0000000..5834830
--- /dev/null
+++ b/samples/browseable/MediaRouter/src/com.example.android.mediarouter/player/OverlayDisplayWindow.java
@@ -0,0 +1,463 @@
+/*
+ * Copyright (C) 2012 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.mediarouter.player;
+
+import android.content.Context;
+import android.graphics.SurfaceTexture;
+import android.hardware.display.DisplayManager;
+import android.os.Build;
+import android.util.DisplayMetrics;
+import android.util.Log;
+import android.view.Display;
+import android.view.GestureDetector;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.ScaleGestureDetector;
+import android.view.Surface;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
+import android.view.TextureView;
+import android.view.TextureView.SurfaceTextureListener;
+import android.view.View;
+import android.view.WindowManager;
+import android.widget.TextView;
+
+import com.example.android.mediarouter.R;
+
+/**
+ * Manages an overlay display window, used for simulating remote playback.
+ */
+public abstract class OverlayDisplayWindow {
+    private static final String TAG = "OverlayDisplayWindow";
+    private static final boolean DEBUG = false;
+
+    private static final float WINDOW_ALPHA = 0.8f;
+    private static final float INITIAL_SCALE = 0.5f;
+    private static final float MIN_SCALE = 0.3f;
+    private static final float MAX_SCALE = 1.0f;
+
+    protected final Context mContext;
+    protected final String mName;
+    protected final int mWidth;
+    protected final int mHeight;
+    protected final int mGravity;
+    protected OverlayWindowListener mListener;
+
+    protected OverlayDisplayWindow(Context context, String name,
+            int width, int height, int gravity) {
+        mContext = context;
+        mName = name;
+        mWidth = width;
+        mHeight = height;
+        mGravity = gravity;
+    }
+
+    public static OverlayDisplayWindow create(Context context, String name,
+            int width, int height, int gravity) {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
+            return new JellybeanMr1Impl(context, name, width, height, gravity);
+        } else {
+            return new LegacyImpl(context, name, width, height, gravity);
+        }
+    }
+
+    public void setOverlayWindowListener(OverlayWindowListener listener) {
+        mListener = listener;
+    }
+
+    public Context getContext() {
+        return mContext;
+    }
+
+    public abstract void show();
+
+    public abstract void dismiss();
+
+    public abstract void updateAspectRatio(int width, int height);
+
+    // Watches for significant changes in the overlay display window lifecycle.
+    public interface OverlayWindowListener {
+        public void onWindowCreated(Surface surface);
+        public void onWindowCreated(SurfaceHolder surfaceHolder);
+        public void onWindowDestroyed();
+    }
+
+    /**
+     * Implementation for older versions.
+     */
+    private static final class LegacyImpl extends OverlayDisplayWindow {
+        private final WindowManager mWindowManager;
+
+        private boolean mWindowVisible;
+        private SurfaceView mSurfaceView;
+
+        public LegacyImpl(Context context, String name,
+                int width, int height, int gravity) {
+            super(context, name, width, height, gravity);
+
+            mWindowManager = (WindowManager)context.getSystemService(
+                    Context.WINDOW_SERVICE);
+        }
+
+        @Override
+        public void show() {
+            if (!mWindowVisible) {
+                mSurfaceView = new SurfaceView(mContext);
+
+                Display display = mWindowManager.getDefaultDisplay();
+
+                WindowManager.LayoutParams params = new WindowManager.LayoutParams(
+                        WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
+                params.flags |= WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
+                        | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
+                        | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+                        | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
+                        | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
+                params.alpha = WINDOW_ALPHA;
+                params.gravity = Gravity.LEFT | Gravity.BOTTOM;
+                params.setTitle(mName);
+
+                int width = (int)(display.getWidth() * INITIAL_SCALE);
+                int height = (int)(display.getHeight() * INITIAL_SCALE);
+                if (mWidth > mHeight) {
+                    height = mHeight * width / mWidth;
+                } else {
+                    width = mWidth * height / mHeight;
+                }
+                params.width = width;
+                params.height = height;
+
+                mWindowManager.addView(mSurfaceView, params);
+                mWindowVisible = true;
+
+                SurfaceHolder holder = mSurfaceView.getHolder();
+                holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
+                mListener.onWindowCreated(holder);
+            }
+        }
+
+        @Override
+        public void dismiss() {
+            if (mWindowVisible) {
+                mListener.onWindowDestroyed();
+
+                mWindowManager.removeView(mSurfaceView);
+                mWindowVisible = false;
+            }
+        }
+
+        @Override
+        public void updateAspectRatio(int width, int height) {
+        }
+    }
+
+    /**
+     * Implementation for API version 17+.
+     */
+    private static final class JellybeanMr1Impl extends OverlayDisplayWindow {
+        // When true, disables support for moving and resizing the overlay.
+        // The window is made non-touchable, which makes it possible to
+        // directly interact with the content underneath.
+        private static final boolean DISABLE_MOVE_AND_RESIZE = false;
+
+        private final DisplayManager mDisplayManager;
+        private final WindowManager mWindowManager;
+
+        private final Display mDefaultDisplay;
+        private final DisplayMetrics mDefaultDisplayMetrics = new DisplayMetrics();
+
+        private View mWindowContent;
+        private WindowManager.LayoutParams mWindowParams;
+        private TextureView mTextureView;
+        private TextView mNameTextView;
+
+        private GestureDetector mGestureDetector;
+        private ScaleGestureDetector mScaleGestureDetector;
+
+        private boolean mWindowVisible;
+        private int mWindowX;
+        private int mWindowY;
+        private float mWindowScale;
+
+        private float mLiveTranslationX;
+        private float mLiveTranslationY;
+        private float mLiveScale = 1.0f;
+
+        public JellybeanMr1Impl(Context context, String name,
+                int width, int height, int gravity) {
+            super(context, name, width, height, gravity);
+
+            mDisplayManager = (DisplayManager)context.getSystemService(
+                    Context.DISPLAY_SERVICE);
+            mWindowManager = (WindowManager)context.getSystemService(
+                    Context.WINDOW_SERVICE);
+
+            mDefaultDisplay = mWindowManager.getDefaultDisplay();
+            updateDefaultDisplayInfo();
+
+            createWindow();
+        }
+
+        @Override
+        public void show() {
+            if (!mWindowVisible) {
+                mDisplayManager.registerDisplayListener(mDisplayListener, null);
+                if (!updateDefaultDisplayInfo()) {
+                    mDisplayManager.unregisterDisplayListener(mDisplayListener);
+                    return;
+                }
+
+                clearLiveState();
+                updateWindowParams();
+                mWindowManager.addView(mWindowContent, mWindowParams);
+                mWindowVisible = true;
+            }
+        }
+
+        @Override
+        public void dismiss() {
+            if (mWindowVisible) {
+                mDisplayManager.unregisterDisplayListener(mDisplayListener);
+                mWindowManager.removeView(mWindowContent);
+                mWindowVisible = false;
+            }
+        }
+
+        @Override
+        public void updateAspectRatio(int width, int height) {
+            if (mWidth * height < mHeight * width) {
+                mTextureView.getLayoutParams().width = mWidth;
+                mTextureView.getLayoutParams().height = mWidth * height / width;
+            } else {
+                mTextureView.getLayoutParams().width = mHeight * width / height;
+                mTextureView.getLayoutParams().height = mHeight;
+            }
+            relayout();
+        }
+
+        private void relayout() {
+            if (mWindowVisible) {
+                updateWindowParams();
+                mWindowManager.updateViewLayout(mWindowContent, mWindowParams);
+            }
+        }
+
+        private boolean updateDefaultDisplayInfo() {
+            mDefaultDisplay.getMetrics(mDefaultDisplayMetrics);
+            return true;
+        }
+
+        private void createWindow() {
+            LayoutInflater inflater = LayoutInflater.from(mContext);
+
+            mWindowContent = inflater.inflate(
+                    R.layout.overlay_display_window, null);
+            mWindowContent.setOnTouchListener(mOnTouchListener);
+
+            mTextureView = (TextureView)mWindowContent.findViewById(
+                    R.id.overlay_display_window_texture);
+            mTextureView.setPivotX(0);
+            mTextureView.setPivotY(0);
+            mTextureView.getLayoutParams().width = mWidth;
+            mTextureView.getLayoutParams().height = mHeight;
+            mTextureView.setOpaque(false);
+            mTextureView.setSurfaceTextureListener(mSurfaceTextureListener);
+
+            mNameTextView = (TextView)mWindowContent.findViewById(
+                    R.id.overlay_display_window_title);
+            mNameTextView.setText(mName);
+
+            mWindowParams = new WindowManager.LayoutParams(
+                    WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
+            mWindowParams.flags |= WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
+                    | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
+                    | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+                    | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
+                    | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
+            if (DISABLE_MOVE_AND_RESIZE) {
+                mWindowParams.flags |= WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
+            }
+            mWindowParams.alpha = WINDOW_ALPHA;
+            mWindowParams.gravity = Gravity.TOP | Gravity.LEFT;
+            mWindowParams.setTitle(mName);
+
+            mGestureDetector = new GestureDetector(mContext, mOnGestureListener);
+            mScaleGestureDetector = new ScaleGestureDetector(mContext, mOnScaleGestureListener);
+
+            // Set the initial position and scale.
+            // The position and scale will be clamped when the display is first shown.
+            mWindowX = (mGravity & Gravity.LEFT) == Gravity.LEFT ?
+                    0 : mDefaultDisplayMetrics.widthPixels;
+            mWindowY = (mGravity & Gravity.TOP) == Gravity.TOP ?
+                    0 : mDefaultDisplayMetrics.heightPixels;
+            Log.d(TAG, mDefaultDisplayMetrics.toString());
+            mWindowScale = INITIAL_SCALE;
+
+            // calculate and save initial settings
+            updateWindowParams();
+            saveWindowParams();
+        }
+
+        private void updateWindowParams() {
+            float scale = mWindowScale * mLiveScale;
+            scale = Math.min(scale, (float)mDefaultDisplayMetrics.widthPixels / mWidth);
+            scale = Math.min(scale, (float)mDefaultDisplayMetrics.heightPixels / mHeight);
+            scale = Math.max(MIN_SCALE, Math.min(MAX_SCALE, scale));
+
+            float offsetScale = (scale / mWindowScale - 1.0f) * 0.5f;
+            int width = (int)(mWidth * scale);
+            int height = (int)(mHeight * scale);
+            int x = (int)(mWindowX + mLiveTranslationX - width * offsetScale);
+            int y = (int)(mWindowY + mLiveTranslationY - height * offsetScale);
+            x = Math.max(0, Math.min(x, mDefaultDisplayMetrics.widthPixels - width));
+            y = Math.max(0, Math.min(y, mDefaultDisplayMetrics.heightPixels - height));
+
+            if (DEBUG) {
+                Log.d(TAG, "updateWindowParams: scale=" + scale
+                        + ", offsetScale=" + offsetScale
+                        + ", x=" + x + ", y=" + y
+                        + ", width=" + width + ", height=" + height);
+            }
+
+            mTextureView.setScaleX(scale);
+            mTextureView.setScaleY(scale);
+
+            mTextureView.setTranslationX(
+                    (mWidth - mTextureView.getLayoutParams().width) * scale / 2);
+            mTextureView.setTranslationY(
+                    (mHeight - mTextureView.getLayoutParams().height) * scale / 2);
+
+            mWindowParams.x = x;
+            mWindowParams.y = y;
+            mWindowParams.width = width;
+            mWindowParams.height = height;
+        }
+
+        private void saveWindowParams() {
+            mWindowX = mWindowParams.x;
+            mWindowY = mWindowParams.y;
+            mWindowScale = mTextureView.getScaleX();
+            clearLiveState();
+        }
+
+        private void clearLiveState() {
+            mLiveTranslationX = 0f;
+            mLiveTranslationY = 0f;
+            mLiveScale = 1.0f;
+        }
+
+        private final DisplayManager.DisplayListener mDisplayListener =
+                new DisplayManager.DisplayListener() {
+            @Override
+            public void onDisplayAdded(int displayId) {
+            }
+
+            @Override
+            public void onDisplayChanged(int displayId) {
+                if (displayId == mDefaultDisplay.getDisplayId()) {
+                    if (updateDefaultDisplayInfo()) {
+                        relayout();
+                    } else {
+                        dismiss();
+                    }
+                }
+            }
+
+            @Override
+            public void onDisplayRemoved(int displayId) {
+                if (displayId == mDefaultDisplay.getDisplayId()) {
+                    dismiss();
+                }
+            }
+        };
+
+        private final SurfaceTextureListener mSurfaceTextureListener =
+                new SurfaceTextureListener() {
+            @Override
+            public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture,
+                    int width, int height) {
+                if (mListener != null) {
+                    mListener.onWindowCreated(new Surface(surfaceTexture));
+                }
+            }
+
+            @Override
+            public boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture) {
+                if (mListener != null) {
+                    mListener.onWindowDestroyed();
+                }
+                return true;
+            }
+
+            @Override
+            public void onSurfaceTextureSizeChanged(SurfaceTexture surfaceTexture,
+                    int width, int height) {
+            }
+
+            @Override
+            public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) {
+            }
+        };
+
+        private final View.OnTouchListener mOnTouchListener = new View.OnTouchListener() {
+            @Override
+            public boolean onTouch(View view, MotionEvent event) {
+                // Work in screen coordinates.
+                final float oldX = event.getX();
+                final float oldY = event.getY();
+                event.setLocation(event.getRawX(), event.getRawY());
+
+                mGestureDetector.onTouchEvent(event);
+                mScaleGestureDetector.onTouchEvent(event);
+
+                switch (event.getActionMasked()) {
+                    case MotionEvent.ACTION_UP:
+                    case MotionEvent.ACTION_CANCEL:
+                        saveWindowParams();
+                        break;
+                }
+
+                // Revert to window coordinates.
+                event.setLocation(oldX, oldY);
+                return true;
+            }
+        };
+
+        private final GestureDetector.OnGestureListener mOnGestureListener =
+                new GestureDetector.SimpleOnGestureListener() {
+            @Override
+            public boolean onScroll(MotionEvent e1, MotionEvent e2,
+                    float distanceX, float distanceY) {
+                mLiveTranslationX -= distanceX;
+                mLiveTranslationY -= distanceY;
+                relayout();
+                return true;
+            }
+        };
+
+        private final ScaleGestureDetector.OnScaleGestureListener mOnScaleGestureListener =
+                new ScaleGestureDetector.SimpleOnScaleGestureListener() {
+            @Override
+            public boolean onScale(ScaleGestureDetector detector) {
+                mLiveScale *= detector.getScaleFactor();
+                relayout();
+                return true;
+            }
+        };
+    }
+}
diff --git a/samples/browseable/MediaRouter/src/com.example.android.mediarouter/player/Player.java b/samples/browseable/MediaRouter/src/com.example.android.mediarouter/player/Player.java
new file mode 100644
index 0000000..f842cf6
--- /dev/null
+++ b/samples/browseable/MediaRouter/src/com.example.android.mediarouter/player/Player.java
@@ -0,0 +1,81 @@
+/*
+ * 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.mediarouter.player;
+
+import android.content.Context;
+import android.support.v7.media.MediaControlIntent;
+import android.support.v7.media.MediaRouter.RouteInfo;
+
+/**
+ * Abstraction of common playback operations of media items, such as play,
+ * seek, etc. Used by PlaybackManager as a backend to handle actual playback
+ * of media items.
+ */
+public abstract class Player {
+    protected Callback mCallback;
+
+    public abstract boolean isRemotePlayback();
+    public abstract boolean isQueuingSupported();
+
+    public abstract void connect(RouteInfo route);
+    public abstract void release();
+
+    // basic operations that are always supported
+    public abstract void play(final PlaylistItem item);
+    public abstract void seek(final PlaylistItem item);
+    public abstract void getStatus(final PlaylistItem item, final boolean update);
+    public abstract void pause();
+    public abstract void resume();
+    public abstract void stop();
+
+    // advanced queuing (enqueue & remove) are only supported
+    // if isQueuingSupported() returns true
+    public abstract void enqueue(final PlaylistItem item);
+    public abstract PlaylistItem remove(String iid);
+
+    // route statistics
+    public void updateStatistics() {}
+    public String getStatistics() { return ""; }
+
+    // presentation display
+    public void updatePresentation() {}
+
+    public void setCallback(Callback callback) {
+        mCallback = callback;
+    }
+
+    public static Player create(Context context, RouteInfo route) {
+        Player player;
+        if (route != null && route.supportsControlCategory(
+                MediaControlIntent.CATEGORY_REMOTE_PLAYBACK)) {
+            player = new RemotePlayer(context);
+        } else if (route != null) {
+            player = new LocalPlayer.SurfaceViewPlayer(context);
+        } else {
+            player = new LocalPlayer.OverlayPlayer(context);
+        }
+        player.connect(route);
+        return player;
+    }
+
+    public interface Callback {
+        void onError();
+        void onCompletion();
+        void onPlaylistChanged();
+        void onPlaylistReady();
+    }
+}
diff --git a/samples/browseable/MediaRouter/src/com.example.android.mediarouter/player/PlaylistItem.java b/samples/browseable/MediaRouter/src/com.example.android.mediarouter/player/PlaylistItem.java
new file mode 100644
index 0000000..a560538
--- /dev/null
+++ b/samples/browseable/MediaRouter/src/com.example.android.mediarouter/player/PlaylistItem.java
@@ -0,0 +1,130 @@
+/*
+ * 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.mediarouter.player;
+
+import android.app.PendingIntent;
+import android.net.Uri;
+import android.os.SystemClock;
+import android.support.v7.media.MediaItemStatus;
+
+/**
+ * PlaylistItem helps keep track of the current status of an media item.
+ */
+public final class PlaylistItem {
+    // immutables
+    private final String mSessionId;
+    private final String mItemId;
+    private final Uri mUri;
+    private final String mMime;
+    private final PendingIntent mUpdateReceiver;
+    // changeable states
+    private int mPlaybackState = MediaItemStatus.PLAYBACK_STATE_PENDING;
+    private long mContentPosition;
+    private long mContentDuration;
+    private long mTimestamp;
+    private String mRemoteItemId;
+
+    public PlaylistItem(String qid, String iid, Uri uri, String mime, PendingIntent pi) {
+        mSessionId = qid;
+        mItemId = iid;
+        mUri = uri;
+        mMime = mime;
+        mUpdateReceiver = pi;
+        setTimestamp(SystemClock.elapsedRealtime());
+    }
+
+    public void setRemoteItemId(String riid) {
+        mRemoteItemId = riid;
+    }
+
+    public void setState(int state) {
+        mPlaybackState = state;
+    }
+
+    public void setPosition(long pos) {
+        mContentPosition = pos;
+    }
+
+    public void setTimestamp(long ts) {
+        mTimestamp = ts;
+    }
+
+    public void setDuration(long duration) {
+        mContentDuration = duration;
+    }
+
+    public String getSessionId() {
+        return mSessionId;
+    }
+
+    public String getItemId() {
+        return mItemId;
+    }
+
+    public String getRemoteItemId() {
+        return mRemoteItemId;
+    }
+
+    public Uri getUri() {
+        return mUri;
+    }
+
+    public PendingIntent getUpdateReceiver() {
+        return mUpdateReceiver;
+    }
+
+    public int getState() {
+        return mPlaybackState;
+    }
+
+    public long getPosition() {
+        return mContentPosition;
+    }
+
+    public long getDuration() {
+        return mContentDuration;
+    }
+
+    public long getTimestamp() {
+        return mTimestamp;
+    }
+
+    public MediaItemStatus getStatus() {
+        return new MediaItemStatus.Builder(mPlaybackState)
+            .setContentPosition(mContentPosition)
+            .setContentDuration(mContentDuration)
+            .setTimestamp(mTimestamp)
+            .build();
+    }
+
+    @Override
+    public String toString() {
+        String state[] = {
+            "PENDING",
+            "PLAYING",
+            "PAUSED",
+            "BUFFERING",
+            "FINISHED",
+            "CANCELED",
+            "INVALIDATED",
+            "ERROR"
+        };
+        return "[" + mSessionId + "|" + mItemId + "|"
+            + (mRemoteItemId != null ? mRemoteItemId : "-") + "|"
+            + state[mPlaybackState] + "] " + mUri.toString();
+    }
+}
diff --git a/samples/browseable/MediaRouter/src/com.example.android.mediarouter/player/RemotePlayer.java b/samples/browseable/MediaRouter/src/com.example.android.mediarouter/player/RemotePlayer.java
new file mode 100644
index 0000000..6726718
--- /dev/null
+++ b/samples/browseable/MediaRouter/src/com.example.android.mediarouter/player/RemotePlayer.java
@@ -0,0 +1,482 @@
+/*
+ * 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.mediarouter.player;
+
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.support.v7.media.MediaItemStatus;
+import android.support.v7.media.MediaRouter.ControlRequestCallback;
+import android.support.v7.media.MediaRouter.RouteInfo;
+import android.support.v7.media.MediaSessionStatus;
+import android.support.v7.media.RemotePlaybackClient;
+import android.support.v7.media.RemotePlaybackClient.ItemActionCallback;
+import android.support.v7.media.RemotePlaybackClient.SessionActionCallback;
+import android.support.v7.media.RemotePlaybackClient.StatusCallback;
+import android.util.Log;
+
+import com.example.android.mediarouter.player.Player;
+import com.example.android.mediarouter.player.PlaylistItem;
+import com.example.android.mediarouter.provider.SampleMediaRouteProvider;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Handles playback of media items using a remote route.
+ *
+ * This class is used as a backend by PlaybackManager to feed media items to
+ * the remote route. When the remote route doesn't support queuing, media items
+ * are fed one-at-a-time; otherwise media items are enqueued to the remote side.
+ */
+public class RemotePlayer extends Player {
+    private static final String TAG = "RemotePlayer";
+    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+    private Context mContext;
+    private RouteInfo mRoute;
+    private boolean mEnqueuePending;
+    private String mStatsInfo = "";
+    private List<PlaylistItem> mTempQueue = new ArrayList<PlaylistItem>();
+
+    private RemotePlaybackClient mClient;
+    private StatusCallback mStatusCallback = new StatusCallback() {
+        @Override
+        public void onItemStatusChanged(Bundle data,
+                String sessionId, MediaSessionStatus sessionStatus,
+                String itemId, MediaItemStatus itemStatus) {
+            logStatus("onItemStatusChanged", sessionId, sessionStatus, itemId, itemStatus);
+            if (mCallback != null) {
+                if (itemStatus.getPlaybackState() ==
+                        MediaItemStatus.PLAYBACK_STATE_FINISHED) {
+                    mCallback.onCompletion();
+                } else if (itemStatus.getPlaybackState() ==
+                        MediaItemStatus.PLAYBACK_STATE_ERROR) {
+                    mCallback.onError();
+                }
+            }
+        }
+
+        @Override
+        public void onSessionStatusChanged(Bundle data,
+                String sessionId, MediaSessionStatus sessionStatus) {
+            logStatus("onSessionStatusChanged", sessionId, sessionStatus, null, null);
+            if (mCallback != null) {
+                mCallback.onPlaylistChanged();
+            }
+        }
+
+        @Override
+        public void onSessionChanged(String sessionId) {
+            if (DEBUG) {
+                Log.d(TAG, "onSessionChanged: sessionId=" + sessionId);
+            }
+        }
+    };
+
+    public RemotePlayer(Context context) {
+        mContext = context;
+    }
+
+    @Override
+    public boolean isRemotePlayback() {
+        return true;
+    }
+
+    @Override
+    public boolean isQueuingSupported() {
+        return mClient.isQueuingSupported();
+    }
+
+    @Override
+    public void connect(RouteInfo route) {
+        mRoute = route;
+        mClient = new RemotePlaybackClient(mContext, route);
+        mClient.setStatusCallback(mStatusCallback);
+
+        if (DEBUG) {
+            Log.d(TAG, "connected to: " + route
+                    + ", isRemotePlaybackSupported: " + mClient.isRemotePlaybackSupported()
+                    + ", isQueuingSupported: "+ mClient.isQueuingSupported());
+        }
+    }
+
+    @Override
+    public void release() {
+        mClient.release();
+
+        if (DEBUG) {
+            Log.d(TAG, "released.");
+        }
+    }
+
+    // basic playback operations that are always supported
+    @Override
+    public void play(final PlaylistItem item) {
+        if (DEBUG) {
+            Log.d(TAG, "play: item=" + item);
+        }
+        mClient.play(item.getUri(), "video/mp4", null, 0, null, new ItemActionCallback() {
+            @Override
+            public void onResult(Bundle data, String sessionId, MediaSessionStatus sessionStatus,
+                    String itemId, MediaItemStatus itemStatus) {
+                logStatus("play: succeeded", sessionId, sessionStatus, itemId, itemStatus);
+                item.setRemoteItemId(itemId);
+                if (item.getPosition() > 0) {
+                    seekInternal(item);
+                }
+                if (item.getState() == MediaItemStatus.PLAYBACK_STATE_PAUSED) {
+                    pause();
+                }
+                if (mCallback != null) {
+                    mCallback.onPlaylistChanged();
+                }
+            }
+
+            @Override
+            public void onError(String error, int code, Bundle data) {
+                logError("play: failed", error, code);
+            }
+        });
+    }
+
+    @Override
+    public void seek(final PlaylistItem item) {
+        seekInternal(item);
+    }
+
+    @Override
+    public void getStatus(final PlaylistItem item, final boolean update) {
+        if (!mClient.hasSession() || item.getRemoteItemId() == null) {
+            // if session is not valid or item id not assigend yet.
+            // just return, it's not fatal
+            return;
+        }
+
+        if (DEBUG) {
+            Log.d(TAG, "getStatus: item=" + item + ", update=" + update);
+        }
+        mClient.getStatus(item.getRemoteItemId(), null, new ItemActionCallback() {
+            @Override
+            public void onResult(Bundle data, String sessionId, MediaSessionStatus sessionStatus,
+                    String itemId, MediaItemStatus itemStatus) {
+                logStatus("getStatus: succeeded", sessionId, sessionStatus, itemId, itemStatus);
+                int state = itemStatus.getPlaybackState();
+                if (state == MediaItemStatus.PLAYBACK_STATE_PLAYING
+                        || state == MediaItemStatus.PLAYBACK_STATE_PAUSED
+                        || state == MediaItemStatus.PLAYBACK_STATE_PENDING) {
+                    item.setState(state);
+                    item.setPosition(itemStatus.getContentPosition());
+                    item.setDuration(itemStatus.getContentDuration());
+                    item.setTimestamp(itemStatus.getTimestamp());
+                }
+                if (update && mCallback != null) {
+                    mCallback.onPlaylistReady();
+                }
+            }
+
+            @Override
+            public void onError(String error, int code, Bundle data) {
+                logError("getStatus: failed", error, code);
+                if (update && mCallback != null) {
+                    mCallback.onPlaylistReady();
+                }
+            }
+        });
+    }
+
+    @Override
+    public void pause() {
+        if (!mClient.hasSession()) {
+            // ignore if no session
+            return;
+        }
+        if (DEBUG) {
+            Log.d(TAG, "pause");
+        }
+        mClient.pause(null, new SessionActionCallback() {
+            @Override
+            public void onResult(Bundle data, String sessionId, MediaSessionStatus sessionStatus) {
+                logStatus("pause: succeeded", sessionId, sessionStatus, null, null);
+                if (mCallback != null) {
+                    mCallback.onPlaylistChanged();
+                }
+            }
+
+            @Override
+            public void onError(String error, int code, Bundle data) {
+                logError("pause: failed", error, code);
+            }
+        });
+    }
+
+    @Override
+    public void resume() {
+        if (!mClient.hasSession()) {
+            // ignore if no session
+            return;
+        }
+        if (DEBUG) {
+            Log.d(TAG, "resume");
+        }
+        mClient.resume(null, new SessionActionCallback() {
+            @Override
+            public void onResult(Bundle data, String sessionId, MediaSessionStatus sessionStatus) {
+                logStatus("resume: succeeded", sessionId, sessionStatus, null, null);
+                if (mCallback != null) {
+                    mCallback.onPlaylistChanged();
+                }
+            }
+
+            @Override
+            public void onError(String error, int code, Bundle data) {
+                logError("resume: failed", error, code);
+            }
+        });
+    }
+
+    @Override
+    public void stop() {
+        if (!mClient.hasSession()) {
+            // ignore if no session
+            return;
+        }
+        if (DEBUG) {
+            Log.d(TAG, "stop");
+        }
+        mClient.stop(null, new SessionActionCallback() {
+            @Override
+            public void onResult(Bundle data, String sessionId, MediaSessionStatus sessionStatus) {
+                logStatus("stop: succeeded", sessionId, sessionStatus, null, null);
+                if (mClient.isSessionManagementSupported()) {
+                    endSession();
+                }
+                if (mCallback != null) {
+                    mCallback.onPlaylistChanged();
+                }
+            }
+
+            @Override
+            public void onError(String error, int code, Bundle data) {
+                logError("stop: failed", error, code);
+            }
+        });
+    }
+
+    // enqueue & remove are only supported if isQueuingSupported() returns true
+    @Override
+    public void enqueue(final PlaylistItem item) {
+        throwIfQueuingUnsupported();
+
+        if (!mClient.hasSession() && !mEnqueuePending) {
+            mEnqueuePending = true;
+            if (mClient.isSessionManagementSupported()) {
+                startSession(item);
+            } else {
+                enqueueInternal(item);
+            }
+        } else if (mEnqueuePending){
+            mTempQueue.add(item);
+        } else {
+            enqueueInternal(item);
+        }
+    }
+
+    @Override
+    public PlaylistItem remove(String itemId) {
+        throwIfNoSession();
+        throwIfQueuingUnsupported();
+
+        if (DEBUG) {
+            Log.d(TAG, "remove: itemId=" + itemId);
+        }
+        mClient.remove(itemId, null, new ItemActionCallback() {
+            @Override
+            public void onResult(Bundle data, String sessionId, MediaSessionStatus sessionStatus,
+                    String itemId, MediaItemStatus itemStatus) {
+                logStatus("remove: succeeded", sessionId, sessionStatus, itemId, itemStatus);
+            }
+
+            @Override
+            public void onError(String error, int code, Bundle data) {
+                logError("remove: failed", error, code);
+            }
+        });
+
+        return null;
+    }
+
+    @Override
+    public void updateStatistics() {
+        // clear stats info first
+        mStatsInfo = "";
+
+        Intent intent = new Intent(SampleMediaRouteProvider.ACTION_GET_STATISTICS);
+        intent.addCategory(SampleMediaRouteProvider.CATEGORY_SAMPLE_ROUTE);
+
+        if (mRoute != null && mRoute.supportsControlRequest(intent)) {
+            ControlRequestCallback callback = new ControlRequestCallback() {
+                @Override
+                public void onResult(Bundle data) {
+                    if (DEBUG) {
+                        Log.d(TAG, "getStatistics: succeeded: data=" + data);
+                    }
+                    if (data != null) {
+                        int playbackCount = data.getInt(
+                                SampleMediaRouteProvider.DATA_PLAYBACK_COUNT, -1);
+                        mStatsInfo = "Total playback count: " + playbackCount;
+                    }
+                }
+
+                @Override
+                public void onError(String error, Bundle data) {
+                    Log.d(TAG, "getStatistics: failed: error=" + error + ", data=" + data);
+                }
+            };
+
+            mRoute.sendControlRequest(intent, callback);
+        }
+    }
+
+    @Override
+    public String getStatistics() {
+        return mStatsInfo;
+    }
+
+    private void enqueueInternal(final PlaylistItem item) {
+        throwIfQueuingUnsupported();
+
+        if (DEBUG) {
+            Log.d(TAG, "enqueue: item=" + item);
+        }
+        mClient.enqueue(item.getUri(), "video/mp4", null, 0, null, new ItemActionCallback() {
+            @Override
+            public void onResult(Bundle data, String sessionId, MediaSessionStatus sessionStatus,
+                    String itemId, MediaItemStatus itemStatus) {
+                logStatus("enqueue: succeeded", sessionId, sessionStatus, itemId, itemStatus);
+                item.setRemoteItemId(itemId);
+                if (item.getPosition() > 0) {
+                    seekInternal(item);
+                }
+                if (item.getState() == MediaItemStatus.PLAYBACK_STATE_PAUSED) {
+                    pause();
+                }
+                if (mEnqueuePending) {
+                    mEnqueuePending = false;
+                    for (PlaylistItem item : mTempQueue) {
+                        enqueueInternal(item);
+                    }
+                    mTempQueue.clear();
+                }
+                if (mCallback != null) {
+                    mCallback.onPlaylistChanged();
+                }
+            }
+
+            @Override
+            public void onError(String error, int code, Bundle data) {
+                logError("enqueue: failed", error, code);
+                if (mCallback != null) {
+                    mCallback.onPlaylistChanged();
+                }
+            }
+        });
+    }
+
+    private void seekInternal(final PlaylistItem item) {
+        throwIfNoSession();
+
+        if (DEBUG) {
+            Log.d(TAG, "seek: item=" + item);
+        }
+        mClient.seek(item.getRemoteItemId(), item.getPosition(), null, new ItemActionCallback() {
+           @Override
+           public void onResult(Bundle data, String sessionId, MediaSessionStatus sessionStatus,
+                   String itemId, MediaItemStatus itemStatus) {
+               logStatus("seek: succeeded", sessionId, sessionStatus, itemId, itemStatus);
+               if (mCallback != null) {
+                   mCallback.onPlaylistChanged();
+               }
+           }
+
+           @Override
+           public void onError(String error, int code, Bundle data) {
+               logError("seek: failed", error, code);
+           }
+        });
+    }
+
+    private void startSession(final PlaylistItem item) {
+        mClient.startSession(null, new SessionActionCallback() {
+            @Override
+            public void onResult(Bundle data, String sessionId, MediaSessionStatus sessionStatus) {
+                logStatus("startSession: succeeded", sessionId, sessionStatus, null, null);
+                enqueueInternal(item);
+            }
+
+            @Override
+            public void onError(String error, int code, Bundle data) {
+                logError("startSession: failed", error, code);
+            }
+        });
+    }
+
+    private void endSession() {
+        mClient.endSession(null, new SessionActionCallback() {
+            @Override
+            public void onResult(Bundle data, String sessionId, MediaSessionStatus sessionStatus) {
+                logStatus("endSession: succeeded", sessionId, sessionStatus, null, null);
+            }
+
+            @Override
+            public void onError(String error, int code, Bundle data) {
+                logError("endSession: failed", error, code);
+            }
+        });
+    }
+
+    private void logStatus(String message,
+            String sessionId, MediaSessionStatus sessionStatus,
+            String itemId, MediaItemStatus itemStatus) {
+        if (DEBUG) {
+            String result = "";
+            if (sessionId != null && sessionStatus != null) {
+                result += "sessionId=" + sessionId + ", sessionStatus=" + sessionStatus;
+            }
+            if (itemId != null & itemStatus != null) {
+                result += (result.isEmpty() ? "" : ", ")
+                        + "itemId=" + itemId + ", itemStatus=" + itemStatus;
+            }
+            Log.d(TAG, message + ": " + result);
+        }
+    }
+
+    private void logError(String message, String error, int code) {
+        Log.d(TAG, message + ": error=" + error + ", code=" + code);
+    }
+
+    private void throwIfNoSession() {
+        if (!mClient.hasSession()) {
+            throw new IllegalStateException("Session is invalid");
+        }
+    }
+
+    private void throwIfQueuingUnsupported() {
+        if (!isQueuingSupported()) {
+            throw new UnsupportedOperationException("Queuing is unsupported");
+        }
+    }
+}
diff --git a/samples/browseable/MediaRouter/src/com.example.android.mediarouter/player/SampleMediaButtonReceiver.java b/samples/browseable/MediaRouter/src/com.example.android.mediarouter/player/SampleMediaButtonReceiver.java
new file mode 100644
index 0000000..855bc1e
--- /dev/null
+++ b/samples/browseable/MediaRouter/src/com.example.android.mediarouter/player/SampleMediaButtonReceiver.java
@@ -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.
+ */
+
+package com.example.android.mediarouter.player;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.view.KeyEvent;
+
+/**
+ * Broadcast receiver for handling ACTION_MEDIA_BUTTON.
+ *
+ * This is needed to create the RemoteControlClient for controlling
+ * remote route volume in lock screen. It routes media key events back
+ * to main app activity MainActivity.
+ */
+public class SampleMediaButtonReceiver extends BroadcastReceiver {
+    private static final String TAG = "SampleMediaButtonReceiver";
+    private static MainActivity mActivity;
+
+    public static void setActivity(MainActivity activity) {
+        mActivity = activity;
+    }
+
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        if (mActivity != null && Intent.ACTION_MEDIA_BUTTON.equals(intent.getAction())) {
+            mActivity.handleMediaKey(
+                    (KeyEvent)intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT));
+        }
+    }
+}
diff --git a/samples/browseable/MediaRouter/src/com.example.android.mediarouter/player/SessionManager.java b/samples/browseable/MediaRouter/src/com.example.android.mediarouter/player/SessionManager.java
new file mode 100644
index 0000000..b6c5a46
--- /dev/null
+++ b/samples/browseable/MediaRouter/src/com.example.android.mediarouter/player/SessionManager.java
@@ -0,0 +1,419 @@
+/*
+ * 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.mediarouter.player;
+
+import android.app.PendingIntent;
+import android.net.Uri;
+import android.support.v7.media.MediaItemStatus;
+import android.support.v7.media.MediaSessionStatus;
+import android.util.Log;
+
+import com.example.android.mediarouter.player.Player.Callback;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * SessionManager manages a media session as a queue. It supports common
+ * queuing behaviors such as enqueue/remove of media items, pause/resume/stop,
+ * etc.
+ *
+ * Actual playback of a single media item is abstracted into a Player interface,
+ * and is handled outside this class.
+ */
+public class SessionManager implements Callback {
+    private static final String TAG = "SessionManager";
+    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
+    private String mName;
+    private int mSessionId;
+    private int mItemId;
+    private boolean mPaused;
+    private boolean mSessionValid;
+    private Player mPlayer;
+    private Callback mCallback;
+    private List<PlaylistItem> mPlaylist = new ArrayList<PlaylistItem>();
+
+    public SessionManager(String name) {
+        mName = name;
+    }
+
+    public boolean hasSession() {
+        return mSessionValid;
+    }
+
+    public String getSessionId() {
+        return mSessionValid ? Integer.toString(mSessionId) : null;
+    }
+
+    public PlaylistItem getCurrentItem() {
+        return mPlaylist.isEmpty() ? null : mPlaylist.get(0);
+    }
+
+    // Get the cached statistic info from the player (will not update it)
+    public String getStatistics() {
+        checkPlayer();
+        return mPlayer.getStatistics();
+    }
+
+    // Returns the cached playlist (note this is not responsible for updating it)
+    public List<PlaylistItem> getPlaylist() {
+        return mPlaylist;
+    }
+
+    // Updates the playlist asynchronously, calls onPlaylistReady() when finished.
+    public void updateStatus() {
+        if (DEBUG) {
+            log("updateStatus");
+        }
+        checkPlayer();
+        // update the statistics first, so that the stats string is valid when
+        // onPlaylistReady() gets called in the end
+        mPlayer.updateStatistics();
+
+        if (mPlaylist.isEmpty()) {
+            // If queue is empty, don't forget to call onPlaylistReady()!
+            onPlaylistReady();
+        } else if (mPlayer.isQueuingSupported()) {
+            // If player supports queuing, get status of each item. Player is
+            // responsible to call onPlaylistReady() after last getStatus().
+            // (update=1 requires player to callback onPlaylistReady())
+            for (int i = 0; i < mPlaylist.size(); i++) {
+                PlaylistItem item = mPlaylist.get(i);
+                mPlayer.getStatus(item, (i == mPlaylist.size() - 1) /* update */);
+            }
+        } else {
+            // Otherwise, only need to get status for current item. Player is
+            // responsible to call onPlaylistReady() when finished.
+            mPlayer.getStatus(getCurrentItem(), true /* update */);
+        }
+    }
+
+    public PlaylistItem add(Uri uri, String mime) {
+        return add(uri, mime, null);
+    }
+
+    public PlaylistItem add(Uri uri, String mime, PendingIntent receiver) {
+        if (DEBUG) {
+            log("add: uri=" + uri + ", receiver=" + receiver);
+        }
+        // create new session if needed
+        startSession();
+        checkPlayerAndSession();
+
+        // append new item with initial status PLAYBACK_STATE_PENDING
+        PlaylistItem item = new PlaylistItem(
+                Integer.toString(mSessionId), Integer.toString(mItemId), uri, mime, receiver);
+        mPlaylist.add(item);
+        mItemId++;
+
+        // if player supports queuing, enqueue the item now
+        if (mPlayer.isQueuingSupported()) {
+            mPlayer.enqueue(item);
+        }
+        updatePlaybackState();
+        return item;
+    }
+
+    public PlaylistItem remove(String iid) {
+        if (DEBUG) {
+            log("remove: iid=" + iid);
+        }
+        checkPlayerAndSession();
+        return removeItem(iid, MediaItemStatus.PLAYBACK_STATE_CANCELED);
+    }
+
+    public PlaylistItem seek(String iid, long pos) {
+        if (DEBUG) {
+            log("seek: iid=" + iid +", pos=" + pos);
+        }
+        checkPlayerAndSession();
+        // seeking on pending items are not yet supported
+        checkItemCurrent(iid);
+
+        PlaylistItem item = getCurrentItem();
+        if (pos != item.getPosition()) {
+            item.setPosition(pos);
+            if (item.getState() == MediaItemStatus.PLAYBACK_STATE_PLAYING
+                    || item.getState() == MediaItemStatus.PLAYBACK_STATE_PAUSED) {
+                mPlayer.seek(item);
+            }
+        }
+        return item;
+    }
+
+    public PlaylistItem getStatus(String iid) {
+        checkPlayerAndSession();
+
+        // This should only be called for local player. Remote player is
+        // asynchronous, need to use updateStatus() instead.
+        if (mPlayer.isRemotePlayback()) {
+            throw new IllegalStateException(
+                    "getStatus should not be called on remote player!");
+        }
+
+        for (PlaylistItem item : mPlaylist) {
+            if (item.getItemId().equals(iid)) {
+                if (item == getCurrentItem()) {
+                    mPlayer.getStatus(item, false);
+                }
+                return item;
+            }
+        }
+        return null;
+    }
+
+    public void pause() {
+        if (DEBUG) {
+            log("pause");
+        }
+        mPaused = true;
+        updatePlaybackState();
+    }
+
+    public void resume() {
+        if (DEBUG) {
+            log("resume");
+        }
+        mPaused = false;
+        updatePlaybackState();
+    }
+
+    public void stop() {
+        if (DEBUG) {
+            log("stop");
+        }
+        mPlayer.stop();
+        mPlaylist.clear();
+        mPaused = false;
+        updateStatus();
+    }
+
+    public String startSession() {
+        if (!mSessionValid) {
+            mSessionId++;
+            mItemId = 0;
+            mPaused = false;
+            mSessionValid = true;
+            return Integer.toString(mSessionId);
+        }
+        return null;
+    }
+
+    public boolean endSession() {
+        if (mSessionValid) {
+            mSessionValid = false;
+            return true;
+        }
+        return false;
+    }
+
+    public MediaSessionStatus getSessionStatus(String sid) {
+        int sessionState = (sid != null && sid.equals(mSessionId)) ?
+                MediaSessionStatus.SESSION_STATE_ACTIVE :
+                    MediaSessionStatus.SESSION_STATE_INVALIDATED;
+
+        return new MediaSessionStatus.Builder(sessionState)
+                .setQueuePaused(mPaused)
+                .build();
+    }
+
+    // Suspend the playback manager. Put the current item back into PENDING
+    // state, and remember the current playback position. Called when switching
+    // to a different player (route).
+    public void suspend(long pos) {
+        for (PlaylistItem item : mPlaylist) {
+            item.setRemoteItemId(null);
+            item.setDuration(0);
+        }
+        PlaylistItem item = getCurrentItem();
+        if (DEBUG) {
+            log("suspend: item=" + item + ", pos=" + pos);
+        }
+        if (item != null) {
+            if (item.getState() == MediaItemStatus.PLAYBACK_STATE_PLAYING
+                    || item.getState() == MediaItemStatus.PLAYBACK_STATE_PAUSED) {
+                item.setState(MediaItemStatus.PLAYBACK_STATE_PENDING);
+                item.setPosition(pos);
+            }
+        }
+    }
+
+    // Unsuspend the playback manager. Restart playback on new player (route).
+    // This will resume playback of current item. Furthermore, if the new player
+    // supports queuing, playlist will be re-established on the remote player.
+    public void unsuspend() {
+        if (DEBUG) {
+            log("unsuspend");
+        }
+        if (mPlayer.isQueuingSupported()) {
+            for (PlaylistItem item : mPlaylist) {
+                mPlayer.enqueue(item);
+            }
+        }
+        updatePlaybackState();
+    }
+
+    // Player.Callback
+    @Override
+    public void onError() {
+        finishItem(true);
+    }
+
+    @Override
+    public void onCompletion() {
+        finishItem(false);
+    }
+
+    @Override
+    public void onPlaylistChanged() {
+        // Playlist has changed, update the cached playlist
+        updateStatus();
+    }
+
+    @Override
+    public void onPlaylistReady() {
+        // Notify activity to update Ui
+        if (mCallback != null) {
+            mCallback.onStatusChanged();
+        }
+    }
+
+    private void log(String message) {
+        Log.d(TAG, mName + ": " + message);
+    }
+
+    private void checkPlayer() {
+        if (mPlayer == null) {
+            throw new IllegalStateException("Player not set!");
+        }
+    }
+
+    private void checkSession() {
+        if (!mSessionValid) {
+            throw new IllegalStateException("Session not set!");
+        }
+    }
+
+    private void checkPlayerAndSession() {
+        checkPlayer();
+        checkSession();
+    }
+
+    private void checkItemCurrent(String iid) {
+        PlaylistItem item = getCurrentItem();
+        if (item == null || !item.getItemId().equals(iid)) {
+            throw new IllegalArgumentException("Item is not current!");
+        }
+    }
+
+    private void updatePlaybackState() {
+        PlaylistItem item = getCurrentItem();
+        if (item != null) {
+            if (item.getState() == MediaItemStatus.PLAYBACK_STATE_PENDING) {
+                item.setState(mPaused ? MediaItemStatus.PLAYBACK_STATE_PAUSED
+                        : MediaItemStatus.PLAYBACK_STATE_PLAYING);
+                if (!mPlayer.isQueuingSupported()) {
+                    mPlayer.play(item);
+                }
+            } else if (mPaused && item.getState() == MediaItemStatus.PLAYBACK_STATE_PLAYING) {
+                mPlayer.pause();
+                item.setState(MediaItemStatus.PLAYBACK_STATE_PAUSED);
+            } else if (!mPaused && item.getState() == MediaItemStatus.PLAYBACK_STATE_PAUSED) {
+                mPlayer.resume();
+                item.setState(MediaItemStatus.PLAYBACK_STATE_PLAYING);
+            }
+            // notify client that item playback status has changed
+            if (mCallback != null) {
+                mCallback.onItemChanged(item);
+            }
+        }
+        updateStatus();
+    }
+
+    private PlaylistItem removeItem(String iid, int state) {
+        checkPlayerAndSession();
+        List<PlaylistItem> queue =
+                new ArrayList<PlaylistItem>(mPlaylist.size());
+        PlaylistItem found = null;
+        for (PlaylistItem item : mPlaylist) {
+            if (iid.equals(item.getItemId())) {
+                if (mPlayer.isQueuingSupported()) {
+                    mPlayer.remove(item.getRemoteItemId());
+                } else if (item.getState() == MediaItemStatus.PLAYBACK_STATE_PLAYING
+                        || item.getState() == MediaItemStatus.PLAYBACK_STATE_PAUSED){
+                    mPlayer.stop();
+                }
+                item.setState(state);
+                found = item;
+                // notify client that item is now removed
+                if (mCallback != null) {
+                    mCallback.onItemChanged(found);
+                }
+            } else {
+                queue.add(item);
+            }
+        }
+        if (found != null) {
+            mPlaylist = queue;
+            updatePlaybackState();
+        } else {
+            log("item not found");
+        }
+        return found;
+    }
+
+    private void finishItem(boolean error) {
+        PlaylistItem item = getCurrentItem();
+        if (item != null) {
+            removeItem(item.getItemId(), error ?
+                    MediaItemStatus.PLAYBACK_STATE_ERROR :
+                        MediaItemStatus.PLAYBACK_STATE_FINISHED);
+            updateStatus();
+        }
+    }
+
+    // set the Player that this playback manager will interact with
+    public void setPlayer(Player player) {
+        mPlayer = player;
+        checkPlayer();
+        mPlayer.setCallback(this);
+    }
+
+    // provide a callback interface to tell the UI when significant state changes occur
+    public void setCallback(Callback callback) {
+        mCallback = callback;
+    }
+
+    @Override
+    public String toString() {
+        String result = "Media Queue: ";
+        if (!mPlaylist.isEmpty()) {
+            for (PlaylistItem item : mPlaylist) {
+                result += "\n" + item.toString();
+            }
+        } else {
+            result += "<empty>";
+        }
+        return result;
+    }
+
+    public interface Callback {
+        void onStatusChanged();
+        void onItemChanged(PlaylistItem item);
+    }
+}
diff --git a/samples/browseable/MediaRouter/src/com.example.android.mediarouter/provider/SampleMediaRouteProvider.java b/samples/browseable/MediaRouter/src/com.example.android.mediarouter/provider/SampleMediaRouteProvider.java
new file mode 100644
index 0000000..739e3ba
--- /dev/null
+++ b/samples/browseable/MediaRouter/src/com.example.android.mediarouter/provider/SampleMediaRouteProvider.java
@@ -0,0 +1,602 @@
+/*
+ * 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.mediarouter.provider;
+
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.IntentFilter.MalformedMimeTypeException;
+import android.content.res.Resources;
+import android.media.AudioManager;
+import android.media.MediaRouter;
+import android.net.Uri;
+import android.os.Bundle;
+import android.support.v7.media.MediaControlIntent;
+import android.support.v7.media.MediaRouteDescriptor;
+import android.support.v7.media.MediaRouteProvider;
+import android.support.v7.media.MediaRouteProviderDescriptor;
+import android.support.v7.media.MediaRouter.ControlRequestCallback;
+import android.support.v7.media.MediaSessionStatus;
+import android.util.Log;
+
+import com.example.android.mediarouter.player.Player;
+import com.example.android.mediarouter.player.PlaylistItem;
+import com.example.android.mediarouter.R;
+import com.example.android.mediarouter.player.SessionManager;
+
+import java.util.ArrayList;
+
+/**
+ * Demonstrates how to create a custom media route provider.
+ *
+ * @see SampleMediaRouteProviderService
+ */
+public final class SampleMediaRouteProvider extends MediaRouteProvider {
+    private static final String TAG = "SampleMediaRouteProvider";
+
+    private static final String FIXED_VOLUME_ROUTE_ID = "fixed";
+    private static final String VARIABLE_VOLUME_BASIC_ROUTE_ID = "variable_basic";
+    private static final String VARIABLE_VOLUME_QUEUING_ROUTE_ID = "variable_queuing";
+    private static final String VARIABLE_VOLUME_SESSION_ROUTE_ID = "variable_session";
+    private static final int VOLUME_MAX = 10;
+
+    /**
+     * A custom media control intent category for special requests that are
+     * supported by this provider's routes.
+     */
+    public static final String CATEGORY_SAMPLE_ROUTE =
+            "com.example.android.mediarouteprovider.CATEGORY_SAMPLE_ROUTE";
+
+    /**
+     * A custom media control intent action for special requests that are
+     * supported by this provider's routes.
+     * <p>
+     * This particular request is designed to return a bundle of not very
+     * interesting statistics for demonstration purposes.
+     * </p>
+     *
+     * @see #DATA_PLAYBACK_COUNT
+     */
+    public static final String ACTION_GET_STATISTICS =
+            "com.example.android.mediarouteprovider.ACTION_GET_STATISTICS";
+
+    /**
+     * {@link #ACTION_GET_STATISTICS} result data: Number of times the
+     * playback action was invoked.
+     */
+    public static final String DATA_PLAYBACK_COUNT =
+            "com.example.android.mediarouteprovider.EXTRA_PLAYBACK_COUNT";
+
+    private static final ArrayList<IntentFilter> CONTROL_FILTERS_BASIC;
+    private static final ArrayList<IntentFilter> CONTROL_FILTERS_QUEUING;
+    private static final ArrayList<IntentFilter> CONTROL_FILTERS_SESSION;
+
+    static {
+        IntentFilter f1 = new IntentFilter();
+        f1.addCategory(CATEGORY_SAMPLE_ROUTE);
+        f1.addAction(ACTION_GET_STATISTICS);
+
+        IntentFilter f2 = new IntentFilter();
+        f2.addCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK);
+        f2.addAction(MediaControlIntent.ACTION_PLAY);
+        f2.addDataScheme("http");
+        f2.addDataScheme("https");
+        f2.addDataScheme("rtsp");
+        f2.addDataScheme("file");
+        addDataTypeUnchecked(f2, "video/*");
+
+        IntentFilter f3 = new IntentFilter();
+        f3.addCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK);
+        f3.addAction(MediaControlIntent.ACTION_SEEK);
+        f3.addAction(MediaControlIntent.ACTION_GET_STATUS);
+        f3.addAction(MediaControlIntent.ACTION_PAUSE);
+        f3.addAction(MediaControlIntent.ACTION_RESUME);
+        f3.addAction(MediaControlIntent.ACTION_STOP);
+
+        IntentFilter f4 = new IntentFilter();
+        f4.addCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK);
+        f4.addAction(MediaControlIntent.ACTION_ENQUEUE);
+        f4.addDataScheme("http");
+        f4.addDataScheme("https");
+        f4.addDataScheme("rtsp");
+        f4.addDataScheme("file");
+        addDataTypeUnchecked(f4, "video/*");
+
+        IntentFilter f5 = new IntentFilter();
+        f5.addCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK);
+        f5.addAction(MediaControlIntent.ACTION_REMOVE);
+
+        IntentFilter f6 = new IntentFilter();
+        f6.addCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK);
+        f6.addAction(MediaControlIntent.ACTION_START_SESSION);
+        f6.addAction(MediaControlIntent.ACTION_GET_SESSION_STATUS);
+        f6.addAction(MediaControlIntent.ACTION_END_SESSION);
+
+        CONTROL_FILTERS_BASIC = new ArrayList<IntentFilter>();
+        CONTROL_FILTERS_BASIC.add(f1);
+        CONTROL_FILTERS_BASIC.add(f2);
+        CONTROL_FILTERS_BASIC.add(f3);
+
+        CONTROL_FILTERS_QUEUING =
+                new ArrayList<IntentFilter>(CONTROL_FILTERS_BASIC);
+        CONTROL_FILTERS_QUEUING.add(f4);
+        CONTROL_FILTERS_QUEUING.add(f5);
+
+        CONTROL_FILTERS_SESSION =
+                new ArrayList<IntentFilter>(CONTROL_FILTERS_QUEUING);
+        CONTROL_FILTERS_SESSION.add(f6);
+    }
+
+    private static void addDataTypeUnchecked(IntentFilter filter, String type) {
+        try {
+            filter.addDataType(type);
+        } catch (MalformedMimeTypeException ex) {
+            throw new RuntimeException(ex);
+        }
+    }
+
+    private int mVolume = 5;
+    private int mEnqueueCount;
+
+    public SampleMediaRouteProvider(Context context) {
+        super(context);
+
+        publishRoutes();
+    }
+
+    @Override
+    public RouteController onCreateRouteController(String routeId) {
+        return new SampleRouteController(routeId);
+    }
+
+    private void publishRoutes() {
+        Resources r = getContext().getResources();
+
+        MediaRouteDescriptor routeDescriptor1 = new MediaRouteDescriptor.Builder(
+                FIXED_VOLUME_ROUTE_ID,
+                r.getString(R.string.fixed_volume_route_name))
+                .setDescription(r.getString(R.string.sample_route_description))
+                .addControlFilters(CONTROL_FILTERS_BASIC)
+                .setPlaybackStream(AudioManager.STREAM_MUSIC)
+                .setPlaybackType(MediaRouter.RouteInfo.PLAYBACK_TYPE_REMOTE)
+                .setVolumeHandling(MediaRouter.RouteInfo.PLAYBACK_VOLUME_FIXED)
+                .setVolume(VOLUME_MAX)
+                .build();
+
+        MediaRouteDescriptor routeDescriptor2 = new MediaRouteDescriptor.Builder(
+                VARIABLE_VOLUME_BASIC_ROUTE_ID,
+                r.getString(R.string.variable_volume_basic_route_name))
+                .setDescription(r.getString(R.string.sample_route_description))
+                .addControlFilters(CONTROL_FILTERS_BASIC)
+                .setPlaybackStream(AudioManager.STREAM_MUSIC)
+                .setPlaybackType(MediaRouter.RouteInfo.PLAYBACK_TYPE_REMOTE)
+                .setVolumeHandling(MediaRouter.RouteInfo.PLAYBACK_VOLUME_VARIABLE)
+                .setVolumeMax(VOLUME_MAX)
+                .setVolume(mVolume)
+                .build();
+
+        MediaRouteDescriptor routeDescriptor3 = new MediaRouteDescriptor.Builder(
+                VARIABLE_VOLUME_QUEUING_ROUTE_ID,
+                r.getString(R.string.variable_volume_queuing_route_name))
+                .setDescription(r.getString(R.string.sample_route_description))
+                .addControlFilters(CONTROL_FILTERS_QUEUING)
+                .setPlaybackStream(AudioManager.STREAM_MUSIC)
+                .setPlaybackType(MediaRouter.RouteInfo.PLAYBACK_TYPE_REMOTE)
+                .setVolumeHandling(MediaRouter.RouteInfo.PLAYBACK_VOLUME_VARIABLE)
+                .setVolumeMax(VOLUME_MAX)
+                .setVolume(mVolume)
+                .build();
+
+        MediaRouteDescriptor routeDescriptor4 = new MediaRouteDescriptor.Builder(
+                VARIABLE_VOLUME_SESSION_ROUTE_ID,
+                r.getString(R.string.variable_volume_session_route_name))
+                .setDescription(r.getString(R.string.sample_route_description))
+                .addControlFilters(CONTROL_FILTERS_SESSION)
+                .setPlaybackStream(AudioManager.STREAM_MUSIC)
+                .setPlaybackType(MediaRouter.RouteInfo.PLAYBACK_TYPE_REMOTE)
+                .setVolumeHandling(MediaRouter.RouteInfo.PLAYBACK_VOLUME_VARIABLE)
+                .setVolumeMax(VOLUME_MAX)
+                .setVolume(mVolume)
+                .build();
+
+        MediaRouteProviderDescriptor providerDescriptor =
+                new MediaRouteProviderDescriptor.Builder()
+                .addRoute(routeDescriptor1)
+                .addRoute(routeDescriptor2)
+                .addRoute(routeDescriptor3)
+                .addRoute(routeDescriptor4)
+                .build();
+        setDescriptor(providerDescriptor);
+    }
+
+    private final class SampleRouteController extends MediaRouteProvider.RouteController {
+        private final String mRouteId;
+        private final SessionManager mSessionManager = new SessionManager("mrp");
+        private final Player mPlayer;
+        private PendingIntent mSessionReceiver;
+
+        public SampleRouteController(String routeId) {
+            mRouteId = routeId;
+            mPlayer = Player.create(getContext(), null);
+            mSessionManager.setPlayer(mPlayer);
+            mSessionManager.setCallback(new SessionManager.Callback() {
+                @Override
+                public void onStatusChanged() {
+                }
+
+                @Override
+                public void onItemChanged(PlaylistItem item) {
+                    handleStatusChange(item);
+                }
+            });
+            Log.d(TAG, mRouteId + ": Controller created");
+        }
+
+        @Override
+        public void onRelease() {
+            Log.d(TAG, mRouteId + ": Controller released");
+            mPlayer.release();
+        }
+
+        @Override
+        public void onSelect() {
+            Log.d(TAG, mRouteId + ": Selected");
+            mPlayer.connect(null);
+        }
+
+        @Override
+        public void onUnselect() {
+            Log.d(TAG, mRouteId + ": Unselected");
+            mPlayer.release();
+        }
+
+        @Override
+        public void onSetVolume(int volume) {
+            Log.d(TAG, mRouteId + ": Set volume to " + volume);
+            if (!mRouteId.equals(FIXED_VOLUME_ROUTE_ID)) {
+                setVolumeInternal(volume);
+            }
+        }
+
+        @Override
+        public void onUpdateVolume(int delta) {
+            Log.d(TAG, mRouteId + ": Update volume by " + delta);
+            if (!mRouteId.equals(FIXED_VOLUME_ROUTE_ID)) {
+                setVolumeInternal(mVolume + delta);
+            }
+        }
+
+        @Override
+        public boolean onControlRequest(Intent intent, ControlRequestCallback callback) {
+            Log.d(TAG, mRouteId + ": Received control request " + intent);
+            String action = intent.getAction();
+            if (intent.hasCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK)) {
+                boolean success = false;
+                if (action.equals(MediaControlIntent.ACTION_PLAY)) {
+                    success = handlePlay(intent, callback);
+                } else if (action.equals(MediaControlIntent.ACTION_ENQUEUE)) {
+                    success = handleEnqueue(intent, callback);
+                } else if (action.equals(MediaControlIntent.ACTION_REMOVE)) {
+                    success = handleRemove(intent, callback);
+                } else if (action.equals(MediaControlIntent.ACTION_SEEK)) {
+                    success = handleSeek(intent, callback);
+                } else if (action.equals(MediaControlIntent.ACTION_GET_STATUS)) {
+                    success = handleGetStatus(intent, callback);
+                } else if (action.equals(MediaControlIntent.ACTION_PAUSE)) {
+                    success = handlePause(intent, callback);
+                } else if (action.equals(MediaControlIntent.ACTION_RESUME)) {
+                    success = handleResume(intent, callback);
+                } else if (action.equals(MediaControlIntent.ACTION_STOP)) {
+                    success = handleStop(intent, callback);
+                } else if (action.equals(MediaControlIntent.ACTION_START_SESSION)) {
+                    success = handleStartSession(intent, callback);
+                } else if (action.equals(MediaControlIntent.ACTION_GET_SESSION_STATUS)) {
+                    success = handleGetSessionStatus(intent, callback);
+                } else if (action.equals(MediaControlIntent.ACTION_END_SESSION)) {
+                    success = handleEndSession(intent, callback);
+                }
+                Log.d(TAG, mSessionManager.toString());
+                return success;
+            }
+
+            if (action.equals(ACTION_GET_STATISTICS)
+                    && intent.hasCategory(CATEGORY_SAMPLE_ROUTE)) {
+                Bundle data = new Bundle();
+                data.putInt(DATA_PLAYBACK_COUNT, mEnqueueCount);
+                if (callback != null) {
+                    callback.onResult(data);
+                }
+                return true;
+            }
+            return false;
+        }
+
+        private void setVolumeInternal(int volume) {
+            if (volume >= 0 && volume <= VOLUME_MAX) {
+                mVolume = volume;
+                Log.d(TAG, mRouteId + ": New volume is " + mVolume);
+                AudioManager audioManager =
+                        (AudioManager)getContext().getSystemService(Context.AUDIO_SERVICE);
+                audioManager.setStreamVolume(AudioManager.STREAM_MUSIC, volume, 0);
+                publishRoutes();
+            }
+        }
+
+        private boolean handlePlay(Intent intent, ControlRequestCallback callback) {
+            String sid = intent.getStringExtra(MediaControlIntent.EXTRA_SESSION_ID);
+            if (sid != null && !sid.equals(mSessionManager.getSessionId())) {
+                Log.d(TAG, "handlePlay fails because of bad sid="+sid);
+                return false;
+            }
+            if (mSessionManager.hasSession()) {
+                mSessionManager.stop();
+            }
+            return handleEnqueue(intent, callback);
+        }
+
+        private boolean handleEnqueue(Intent intent, ControlRequestCallback callback) {
+            String sid = intent.getStringExtra(MediaControlIntent.EXTRA_SESSION_ID);
+            if (sid != null && !sid.equals(mSessionManager.getSessionId())) {
+                Log.d(TAG, "handleEnqueue fails because of bad sid="+sid);
+                return false;
+            }
+
+            Uri uri = intent.getData();
+            if (uri == null) {
+                Log.d(TAG, "handleEnqueue fails because of bad uri="+uri);
+                return false;
+            }
+
+            boolean enqueue = intent.getAction().equals(MediaControlIntent.ACTION_ENQUEUE);
+            String mime = intent.getType();
+            long pos = intent.getLongExtra(MediaControlIntent.EXTRA_ITEM_CONTENT_POSITION, 0);
+            Bundle metadata = intent.getBundleExtra(MediaControlIntent.EXTRA_ITEM_METADATA);
+            Bundle headers = intent.getBundleExtra(MediaControlIntent.EXTRA_ITEM_HTTP_HEADERS);
+            PendingIntent receiver = (PendingIntent)intent.getParcelableExtra(
+                    MediaControlIntent.EXTRA_ITEM_STATUS_UPDATE_RECEIVER);
+
+            Log.d(TAG, mRouteId + ": Received " + (enqueue?"enqueue":"play") + " request"
+                    + ", uri=" + uri
+                    + ", mime=" + mime
+                    + ", sid=" + sid
+                    + ", pos=" + pos
+                    + ", metadata=" + metadata
+                    + ", headers=" + headers
+                    + ", receiver=" + receiver);
+            PlaylistItem item = mSessionManager.add(uri, mime, receiver);
+            if (callback != null) {
+                if (item != null) {
+                    Bundle result = new Bundle();
+                    result.putString(MediaControlIntent.EXTRA_SESSION_ID, item.getSessionId());
+                    result.putString(MediaControlIntent.EXTRA_ITEM_ID, item.getItemId());
+                    result.putBundle(MediaControlIntent.EXTRA_ITEM_STATUS,
+                            item.getStatus().asBundle());
+                    callback.onResult(result);
+                } else {
+                    callback.onError("Failed to open " + uri.toString(), null);
+                }
+            }
+            mEnqueueCount +=1;
+            return true;
+        }
+
+        private boolean handleRemove(Intent intent, ControlRequestCallback callback) {
+            String sid = intent.getStringExtra(MediaControlIntent.EXTRA_SESSION_ID);
+            if (sid == null || !sid.equals(mSessionManager.getSessionId())) {
+                return false;
+            }
+
+            String iid = intent.getStringExtra(MediaControlIntent.EXTRA_ITEM_ID);
+            PlaylistItem item = mSessionManager.remove(iid);
+            if (callback != null) {
+                if (item != null) {
+                    Bundle result = new Bundle();
+                    result.putBundle(MediaControlIntent.EXTRA_ITEM_STATUS,
+                            item.getStatus().asBundle());
+                    callback.onResult(result);
+                } else {
+                    callback.onError("Failed to remove" +
+                            ", sid=" + sid + ", iid=" + iid, null);
+                }
+            }
+            return (item != null);
+        }
+
+        private boolean handleSeek(Intent intent, ControlRequestCallback callback) {
+            String sid = intent.getStringExtra(MediaControlIntent.EXTRA_SESSION_ID);
+            if (sid == null || !sid.equals(mSessionManager.getSessionId())) {
+                return false;
+            }
+
+            String iid = intent.getStringExtra(MediaControlIntent.EXTRA_ITEM_ID);
+            long pos = intent.getLongExtra(MediaControlIntent.EXTRA_ITEM_CONTENT_POSITION, 0);
+            Log.d(TAG, mRouteId + ": Received seek request, pos=" + pos);
+            PlaylistItem item = mSessionManager.seek(iid, pos);
+            if (callback != null) {
+                if (item != null) {
+                    Bundle result = new Bundle();
+                    result.putBundle(MediaControlIntent.EXTRA_ITEM_STATUS,
+                            item.getStatus().asBundle());
+                    callback.onResult(result);
+                } else {
+                    callback.onError("Failed to seek" +
+                            ", sid=" + sid + ", iid=" + iid + ", pos=" + pos, null);
+                }
+            }
+            return (item != null);
+        }
+
+        private boolean handleGetStatus(Intent intent, ControlRequestCallback callback) {
+            String sid = intent.getStringExtra(MediaControlIntent.EXTRA_SESSION_ID);
+            String iid = intent.getStringExtra(MediaControlIntent.EXTRA_ITEM_ID);
+            Log.d(TAG, mRouteId + ": Received getStatus request, sid=" + sid + ", iid=" + iid);
+            PlaylistItem item = mSessionManager.getStatus(iid);
+            if (callback != null) {
+                if (item != null) {
+                    Bundle result = new Bundle();
+                    result.putBundle(MediaControlIntent.EXTRA_ITEM_STATUS,
+                            item.getStatus().asBundle());
+                    callback.onResult(result);
+                } else {
+                    callback.onError("Failed to get status" +
+                            ", sid=" + sid + ", iid=" + iid, null);
+                }
+            }
+            return (item != null);
+        }
+
+        private boolean handlePause(Intent intent, ControlRequestCallback callback) {
+            String sid = intent.getStringExtra(MediaControlIntent.EXTRA_SESSION_ID);
+            boolean success = (sid != null) && sid.equals(mSessionManager.getSessionId());
+            mSessionManager.pause();
+            if (callback != null) {
+                if (success) {
+                    callback.onResult(new Bundle());
+                    handleSessionStatusChange(sid);
+                } else {
+                    callback.onError("Failed to pause, sid=" + sid, null);
+                }
+            }
+            return success;
+        }
+
+        private boolean handleResume(Intent intent, ControlRequestCallback callback) {
+            String sid = intent.getStringExtra(MediaControlIntent.EXTRA_SESSION_ID);
+            boolean success = (sid != null) && sid.equals(mSessionManager.getSessionId());
+            mSessionManager.resume();
+            if (callback != null) {
+                if (success) {
+                    callback.onResult(new Bundle());
+                    handleSessionStatusChange(sid);
+                } else {
+                    callback.onError("Failed to resume, sid=" + sid, null);
+                }
+            }
+            return success;
+        }
+
+        private boolean handleStop(Intent intent, ControlRequestCallback callback) {
+            String sid = intent.getStringExtra(MediaControlIntent.EXTRA_SESSION_ID);
+            boolean success = (sid != null) && sid.equals(mSessionManager.getSessionId());
+            mSessionManager.stop();
+            if (callback != null) {
+                if (success) {
+                    callback.onResult(new Bundle());
+                    handleSessionStatusChange(sid);
+                } else {
+                    callback.onError("Failed to stop, sid=" + sid, null);
+                }
+            }
+            return success;
+        }
+
+        private boolean handleStartSession(Intent intent, ControlRequestCallback callback) {
+            String sid = mSessionManager.startSession();
+            Log.d(TAG, "StartSession returns sessionId "+sid);
+            if (callback != null) {
+                if (sid != null) {
+                    Bundle result = new Bundle();
+                    result.putString(MediaControlIntent.EXTRA_SESSION_ID, sid);
+                    result.putBundle(MediaControlIntent.EXTRA_SESSION_STATUS,
+                            mSessionManager.getSessionStatus(sid).asBundle());
+                    callback.onResult(result);
+                    mSessionReceiver = (PendingIntent)intent.getParcelableExtra(
+                            MediaControlIntent.EXTRA_SESSION_STATUS_UPDATE_RECEIVER);
+                    handleSessionStatusChange(sid);
+                } else {
+                    callback.onError("Failed to start session.", null);
+                }
+            }
+            return (sid != null);
+        }
+
+        private boolean handleGetSessionStatus(Intent intent, ControlRequestCallback callback) {
+            String sid = intent.getStringExtra(MediaControlIntent.EXTRA_SESSION_ID);
+
+            MediaSessionStatus sessionStatus = mSessionManager.getSessionStatus(sid);
+            if (callback != null) {
+                if (sessionStatus != null) {
+                    Bundle result = new Bundle();
+                    result.putBundle(MediaControlIntent.EXTRA_SESSION_STATUS,
+                            mSessionManager.getSessionStatus(sid).asBundle());
+                    callback.onResult(result);
+                } else {
+                    callback.onError("Failed to get session status, sid=" + sid, null);
+                }
+            }
+            return (sessionStatus != null);
+        }
+
+        private boolean handleEndSession(Intent intent, ControlRequestCallback callback) {
+            String sid = intent.getStringExtra(MediaControlIntent.EXTRA_SESSION_ID);
+            boolean success = (sid != null) && sid.equals(mSessionManager.getSessionId())
+                    && mSessionManager.endSession();
+            if (callback != null) {
+                if (success) {
+                    Bundle result = new Bundle();
+                    MediaSessionStatus sessionStatus = new MediaSessionStatus.Builder(
+                            MediaSessionStatus.SESSION_STATE_ENDED).build();
+                    result.putBundle(MediaControlIntent.EXTRA_SESSION_STATUS, sessionStatus.asBundle());
+                    callback.onResult(result);
+                    handleSessionStatusChange(sid);
+                    mSessionReceiver = null;
+                } else {
+                    callback.onError("Failed to end session, sid=" + sid, null);
+                }
+            }
+            return success;
+        }
+
+        private void handleStatusChange(PlaylistItem item) {
+            if (item == null) {
+                item = mSessionManager.getCurrentItem();
+            }
+            if (item != null) {
+                PendingIntent receiver = item.getUpdateReceiver();
+                if (receiver != null) {
+                    Intent intent = new Intent();
+                    intent.putExtra(MediaControlIntent.EXTRA_SESSION_ID, item.getSessionId());
+                    intent.putExtra(MediaControlIntent.EXTRA_ITEM_ID, item.getItemId());
+                    intent.putExtra(MediaControlIntent.EXTRA_ITEM_STATUS,
+                            item.getStatus().asBundle());
+                    try {
+                        receiver.send(getContext(), 0, intent);
+                        Log.d(TAG, mRouteId + ": Sending status update from provider");
+                    } catch (PendingIntent.CanceledException e) {
+                        Log.d(TAG, mRouteId + ": Failed to send status update!");
+                    }
+                }
+            }
+        }
+
+        private void handleSessionStatusChange(String sid) {
+            if (mSessionReceiver != null) {
+                Intent intent = new Intent();
+                intent.putExtra(MediaControlIntent.EXTRA_SESSION_ID, sid);
+                intent.putExtra(MediaControlIntent.EXTRA_SESSION_STATUS,
+                        mSessionManager.getSessionStatus(sid).asBundle());
+                try {
+                    mSessionReceiver.send(getContext(), 0, intent);
+                    Log.d(TAG, mRouteId + ": Sending session status update from provider");
+                } catch (PendingIntent.CanceledException e) {
+                    Log.d(TAG, mRouteId + ": Failed to send session status update!");
+                }
+            }
+        }
+    }
+}
diff --git a/samples/browseable/MediaRouter/src/com.example.android.mediarouter/provider/SampleMediaRouteProviderService.java b/samples/browseable/MediaRouter/src/com.example.android.mediarouter/provider/SampleMediaRouteProviderService.java
new file mode 100644
index 0000000..41a6cbd
--- /dev/null
+++ b/samples/browseable/MediaRouter/src/com.example.android.mediarouter/provider/SampleMediaRouteProviderService.java
@@ -0,0 +1,35 @@
+/*
+ * 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.mediarouter.provider;
+
+import android.support.v7.media.MediaRouteProvider;
+import android.support.v7.media.MediaRouteProviderService;
+
+import com.example.android.mediarouter.provider.SampleMediaRouteProvider;
+
+/**
+ * Demonstrates how to register a custom media route provider service
+ * using the support library.
+ *
+ * @see com.example.android.mediarouter.provider.SampleMediaRouteProvider
+ */
+public class SampleMediaRouteProviderService extends MediaRouteProviderService {
+    @Override
+    public MediaRouteProvider onCreateMediaRouteProvider() {
+        return new SampleMediaRouteProvider(this);
+    }
+}
diff --git a/samples/browseable/NetworkConnect/res/values-sw600dp/dimens.xml b/samples/browseable/NetworkConnect/res/values-sw600dp/template-dimens.xml
similarity index 100%
rename from samples/browseable/NetworkConnect/res/values-sw600dp/dimens.xml
rename to samples/browseable/NetworkConnect/res/values-sw600dp/template-dimens.xml
diff --git a/samples/browseable/NetworkConnect/res/values-sw600dp/styles.xml b/samples/browseable/NetworkConnect/res/values-sw600dp/template-styles.xml
similarity index 100%
rename from samples/browseable/NetworkConnect/res/values-sw600dp/styles.xml
rename to samples/browseable/NetworkConnect/res/values-sw600dp/template-styles.xml
diff --git a/samples/browseable/NetworkConnect/res/values/dimens.xml b/samples/browseable/NetworkConnect/res/values/template-dimens.xml
similarity index 100%
rename from samples/browseable/NetworkConnect/res/values/dimens.xml
rename to samples/browseable/NetworkConnect/res/values/template-dimens.xml
diff --git a/samples/browseable/NetworkConnect/res/values/styles.xml b/samples/browseable/NetworkConnect/res/values/template-styles.xml
similarity index 100%
rename from samples/browseable/NetworkConnect/res/values/styles.xml
rename to samples/browseable/NetworkConnect/res/values/template-styles.xml
diff --git a/samples/browseable/RenderScriptIntrinsic/AndroidManifest.xml b/samples/browseable/RenderScriptIntrinsic/AndroidManifest.xml
new file mode 100644
index 0000000..566ef8a
--- /dev/null
+++ b/samples/browseable/RenderScriptIntrinsic/AndroidManifest.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="UTF-8"?><!--
+ Copyright 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.example.android.renderscriptintrinsic"
+    android:versionCode="1"
+    android:versionName="1.0">
+
+    <uses-sdk
+        android:minSdkVersion="8"
+        android:targetSdkVersion="19" />
+
+    <application
+        android:allowBackup="true"
+        android:label="RenderScriptIntrinsic"
+        android:icon="@drawable/ic_launcher"
+        android:theme="@style/AppTheme">
+
+        <activity
+            android:name=".MainActivity"
+            android:label="RenderScriptIntrinsic"
+            android:theme="@style/FullscreenTheme">
+            <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/browseable/RenderScriptIntrinsic/_index.jd b/samples/browseable/RenderScriptIntrinsic/_index.jd
new file mode 100644
index 0000000..2724c1a
--- /dev/null
+++ b/samples/browseable/RenderScriptIntrinsic/_index.jd
@@ -0,0 +1,15 @@
+
+
+
+page.tags="RenderScriptIntrinsic"
+sample.group=RenderScript
+@jd:body
+
+<p>
+  This sample demonstrates how to use <a href=
+  "http://android-developers.blogspot.com/2013/08/renderscript-intrinsics.html">
+  RenderScript intrinsics</a>. The app creates several RenderScript intrinsics
+  and shows a filtering result with various parameters. The sample also shows
+  how to extend {@link android.widget.RadioButton} with {@link
+  android.graphics.drawable.StateListDrawable}.
+</p>
diff --git a/samples/training/bitmapfun/BitmapFun/src/main/res/drawable-hdpi/ic_launcher.png b/samples/browseable/RenderScriptIntrinsic/res/drawable-hdpi/ic_launcher.png
old mode 100644
new mode 100755
similarity index 100%
copy from samples/training/bitmapfun/BitmapFun/src/main/res/drawable-hdpi/ic_launcher.png
copy to samples/browseable/RenderScriptIntrinsic/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/Basic/res/drawable-hdpi/tile.9.png b/samples/browseable/RenderScriptIntrinsic/res/drawable-hdpi/tile.9.png
similarity index 100%
copy from samples/browseable/Basic/res/drawable-hdpi/tile.9.png
copy to samples/browseable/RenderScriptIntrinsic/res/drawable-hdpi/tile.9.png
Binary files differ
diff --git a/samples/browseable/RenderScriptIntrinsic/res/drawable-mdpi/ic_launcher.png b/samples/browseable/RenderScriptIntrinsic/res/drawable-mdpi/ic_launcher.png
new file mode 100755
index 0000000..4ccd98e
--- /dev/null
+++ b/samples/browseable/RenderScriptIntrinsic/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/RenderScriptIntrinsic/res/drawable-nodpi/data.jpg b/samples/browseable/RenderScriptIntrinsic/res/drawable-nodpi/data.jpg
new file mode 100644
index 0000000..48e48e6
--- /dev/null
+++ b/samples/browseable/RenderScriptIntrinsic/res/drawable-nodpi/data.jpg
Binary files differ
diff --git a/samples/training/bitmapfun/BitmapFun/src/main/res/drawable-xhdpi/ic_launcher.png b/samples/browseable/RenderScriptIntrinsic/res/drawable-xhdpi/ic_launcher.png
old mode 100644
new mode 100755
similarity index 100%
copy from samples/training/bitmapfun/BitmapFun/src/main/res/drawable-xhdpi/ic_launcher.png
copy to samples/browseable/RenderScriptIntrinsic/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/RenderScriptIntrinsic/res/drawable-xxhdpi/ic_launcher.png b/samples/browseable/RenderScriptIntrinsic/res/drawable-xxhdpi/ic_launcher.png
new file mode 100755
index 0000000..3c45f51
--- /dev/null
+++ b/samples/browseable/RenderScriptIntrinsic/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/Basic/res/layout/activity_main.xml b/samples/browseable/RenderScriptIntrinsic/res/layout/activity_main.xml
similarity index 100%
copy from samples/browseable/Basic/res/layout/activity_main.xml
copy to samples/browseable/RenderScriptIntrinsic/res/layout/activity_main.xml
diff --git a/samples/browseable/RenderScriptIntrinsic/res/layout/main_layout.xml b/samples/browseable/RenderScriptIntrinsic/res/layout/main_layout.xml
new file mode 100644
index 0000000..13516d8
--- /dev/null
+++ b/samples/browseable/RenderScriptIntrinsic/res/layout/main_layout.xml
@@ -0,0 +1,51 @@
+<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:background="#0099cc"
+    tools:context=".MainActivity">
+
+    <ImageView
+        android:id="@+id/imageView"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:scaleType="centerCrop"
+        android:src="@drawable/data" />
+
+    <RadioGroup
+        android:id="@+id/radioGroup1"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_centerHorizontal="true"
+        android:orientation="horizontal"
+        android:layout_above="@+id/seekBar1"
+        android:layout_marginBottom="8dp">
+
+        <com.example.android.renderscriptintrinsic.ThumbnailRadioButton
+            android:id="@+id/radio0"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:checked="true"
+            android:text="Blur" />
+
+        <com.example.android.renderscriptintrinsic.ThumbnailRadioButton
+            android:id="@+id/radio1"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="Emboss" />
+
+        <com.example.android.renderscriptintrinsic.ThumbnailRadioButton
+            android:id="@+id/radio2"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="Hue" />
+    </RadioGroup>
+
+    <SeekBar
+        android:id="@+id/seekBar1"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_alignParentBottom="true"
+        android:layout_marginBottom="16dp" />
+
+</RelativeLayout>
diff --git a/samples/browseable/Basic/res/values-sw600dp/dimens.xml b/samples/browseable/RenderScriptIntrinsic/res/values-sw600dp/template-dimens.xml
similarity index 100%
copy from samples/browseable/Basic/res/values-sw600dp/dimens.xml
copy to samples/browseable/RenderScriptIntrinsic/res/values-sw600dp/template-dimens.xml
diff --git a/samples/browseable/Basic/res/values-sw600dp/styles.xml b/samples/browseable/RenderScriptIntrinsic/res/values-sw600dp/template-styles.xml
similarity index 100%
copy from samples/browseable/Basic/res/values-sw600dp/styles.xml
copy to samples/browseable/RenderScriptIntrinsic/res/values-sw600dp/template-styles.xml
diff --git a/samples/browseable/RenderScriptIntrinsic/res/values-v11/styles.xml b/samples/browseable/RenderScriptIntrinsic/res/values-v11/styles.xml
new file mode 100644
index 0000000..f3a90c6
--- /dev/null
+++ b/samples/browseable/RenderScriptIntrinsic/res/values-v11/styles.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<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>
+
+    <style name="FullscreenTheme" parent="android:Theme.Holo">
+        <item name="android:actionBarStyle">@style/FullscreenActionBarStyle</item>
+        <item name="android:windowActionBarOverlay">true</item>
+        <item name="android:windowBackground">@null</item>
+        <item name="buttonBarStyle">?android:attr/buttonBarStyle</item>
+        <item name="buttonBarButtonStyle">?android:attr/buttonBarButtonStyle</item>
+    </style>
+
+    <style name="FullscreenActionBarStyle" parent="android:Widget.Holo.ActionBar">
+        <item name="android:background">@color/black_overlay</item>
+    </style>
+
+</resources>
diff --git a/samples/browseable/RenderScriptIntrinsic/res/values-v14/styles.xml b/samples/browseable/RenderScriptIntrinsic/res/values-v14/styles.xml
new file mode 100644
index 0000000..a91fd03
--- /dev/null
+++ b/samples/browseable/RenderScriptIntrinsic/res/values-v14/styles.xml
@@ -0,0 +1,12 @@
+<resources>
+
+    <!--
+        Base application theme for API 14+. This theme completely replaces
+        AppBaseTheme from BOTH res/values/styles.xml and
+        res/values-v11/styles.xml on API 14+ devices.
+    -->
+    <style name="AppBaseTheme" parent="android:Theme.Holo.Light.DarkActionBar">
+        <!-- API 14 theme customizations can go here. -->
+    </style>
+
+</resources>
diff --git a/samples/browseable/RenderScriptIntrinsic/res/values/attrs.xml b/samples/browseable/RenderScriptIntrinsic/res/values/attrs.xml
new file mode 100644
index 0000000..e67df0a
--- /dev/null
+++ b/samples/browseable/RenderScriptIntrinsic/res/values/attrs.xml
@@ -0,0 +1,14 @@
+<resources>
+
+    <!--
+         Declare custom theme attributes that allow changing which styles are
+         used for button bars depending on the API level.
+         ?android:attr/buttonBarStyle is new as of API 11 so this is
+         necessary to support previous API levels.
+    -->
+    <declare-styleable name="ButtonBarContainerTheme">
+        <attr name="buttonBarStyle" format="reference" />
+        <attr name="buttonBarButtonStyle" format="reference" />
+    </declare-styleable>
+
+</resources>
diff --git a/samples/browseable/repeatingAlarm/res/values/base-strings.xml b/samples/browseable/RenderScriptIntrinsic/res/values/base-strings.xml
similarity index 69%
copy from samples/browseable/repeatingAlarm/res/values/base-strings.xml
copy to samples/browseable/RenderScriptIntrinsic/res/values/base-strings.xml
index c11b89b..c8488be 100644
--- a/samples/browseable/repeatingAlarm/res/values/base-strings.xml
+++ b/samples/browseable/RenderScriptIntrinsic/res/values/base-strings.xml
@@ -18,13 +18,14 @@
 
 
 <resources>
-    <string name="app_name">repeatingAlarm</string>
+    <string name="app_name">RenderScriptIntrinsic</string>
     <string name="intro_message">
         <![CDATA[
         
             
-                Introductory text that explains what the sample is intended to demonstrate. Edit
-                in template-params.xml.
+            RenderScriptIntrinsic sample that demonstrates how to use RenderScript intrinsics.
+            Creates several RenderScript intrinsics and shows a filtering result with various parameters.
+            Also shows how to extends RedioButton with StateListDrawable.
             
         
         ]]>
diff --git a/samples/browseable/RenderScriptIntrinsic/res/values/colors.xml b/samples/browseable/RenderScriptIntrinsic/res/values/colors.xml
new file mode 100644
index 0000000..327c060
--- /dev/null
+++ b/samples/browseable/RenderScriptIntrinsic/res/values/colors.xml
@@ -0,0 +1,5 @@
+<resources>
+
+    <color name="black_overlay">#66000000</color>
+
+</resources>
diff --git a/samples/browseable/RenderScriptIntrinsic/res/values/styles.xml b/samples/browseable/RenderScriptIntrinsic/res/values/styles.xml
new file mode 100644
index 0000000..12eb930
--- /dev/null
+++ b/samples/browseable/RenderScriptIntrinsic/res/values/styles.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<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>
+
+    <style name="FullscreenTheme" parent="android:Theme.NoTitleBar">
+        <item name="android:windowContentOverlay">@null</item>
+        <item name="android:windowBackground">@null</item>
+        <item name="buttonBarStyle">@style/ButtonBar</item>
+        <item name="buttonBarButtonStyle">@style/ButtonBarButton</item>
+    </style>
+
+    <style name="ButtonBar">
+        <item name="android:paddingLeft">2dp</item>
+        <item name="android:paddingTop">5dp</item>
+        <item name="android:paddingRight">2dp</item>
+        <item name="android:paddingBottom">0dp</item>
+        <item name="android:background">@android:drawable/bottom_bar</item>
+    </style>
+
+    <style name="ButtonBarButton" />
+
+</resources>
diff --git a/samples/browseable/Basic/res/values/dimens.xml b/samples/browseable/RenderScriptIntrinsic/res/values/template-dimens.xml
similarity index 100%
copy from samples/browseable/Basic/res/values/dimens.xml
copy to samples/browseable/RenderScriptIntrinsic/res/values/template-dimens.xml
diff --git a/samples/browseable/Basic/res/values/styles.xml b/samples/browseable/RenderScriptIntrinsic/res/values/template-styles.xml
similarity index 100%
copy from samples/browseable/Basic/res/values/styles.xml
copy to samples/browseable/RenderScriptIntrinsic/res/values/template-styles.xml
diff --git a/samples/browseable/repeatingAlarm/src/com.example.android.common/logger/Log.java b/samples/browseable/RenderScriptIntrinsic/src/com.example.android.common.logger/Log.java
similarity index 100%
copy from samples/browseable/repeatingAlarm/src/com.example.android.common/logger/Log.java
copy to samples/browseable/RenderScriptIntrinsic/src/com.example.android.common.logger/Log.java
diff --git a/samples/browseable/repeatingAlarm/src/com.example.android.common/logger/LogFragment.java b/samples/browseable/RenderScriptIntrinsic/src/com.example.android.common.logger/LogFragment.java
similarity index 100%
copy from samples/browseable/repeatingAlarm/src/com.example.android.common/logger/LogFragment.java
copy to samples/browseable/RenderScriptIntrinsic/src/com.example.android.common.logger/LogFragment.java
diff --git a/samples/browseable/repeatingAlarm/src/com.example.android.common/logger/LogNode.java b/samples/browseable/RenderScriptIntrinsic/src/com.example.android.common.logger/LogNode.java
similarity index 100%
copy from samples/browseable/repeatingAlarm/src/com.example.android.common/logger/LogNode.java
copy to samples/browseable/RenderScriptIntrinsic/src/com.example.android.common.logger/LogNode.java
diff --git a/samples/browseable/repeatingAlarm/src/com.example.android.common/logger/LogView.java b/samples/browseable/RenderScriptIntrinsic/src/com.example.android.common.logger/LogView.java
similarity index 100%
copy from samples/browseable/repeatingAlarm/src/com.example.android.common/logger/LogView.java
copy to samples/browseable/RenderScriptIntrinsic/src/com.example.android.common.logger/LogView.java
diff --git a/samples/browseable/repeatingAlarm/src/com.example.android.common/logger/LogWrapper.java b/samples/browseable/RenderScriptIntrinsic/src/com.example.android.common.logger/LogWrapper.java
similarity index 100%
copy from samples/browseable/repeatingAlarm/src/com.example.android.common/logger/LogWrapper.java
copy to samples/browseable/RenderScriptIntrinsic/src/com.example.android.common.logger/LogWrapper.java
diff --git a/samples/browseable/repeatingAlarm/src/com.example.android.common/logger/MessageOnlyLogFilter.java b/samples/browseable/RenderScriptIntrinsic/src/com.example.android.common.logger/MessageOnlyLogFilter.java
similarity index 100%
copy from samples/browseable/repeatingAlarm/src/com.example.android.common/logger/MessageOnlyLogFilter.java
copy to samples/browseable/RenderScriptIntrinsic/src/com.example.android.common.logger/MessageOnlyLogFilter.java
diff --git a/samples/browseable/RenderScriptIntrinsic/src/com.example.android.renderscriptintrinsic/MainActivity.java b/samples/browseable/RenderScriptIntrinsic/src/com.example.android.renderscriptintrinsic/MainActivity.java
new file mode 100644
index 0000000..4b6f5ce
--- /dev/null
+++ b/samples/browseable/RenderScriptIntrinsic/src/com.example.android.renderscriptintrinsic/MainActivity.java
@@ -0,0 +1,370 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.renderscriptintrinsic;
+
+import android.app.Activity;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.widget.CompoundButton;
+import android.widget.CompoundButton.OnCheckedChangeListener;
+import android.widget.ImageView;
+import android.widget.RadioButton;
+import android.widget.SeekBar;
+import android.widget.SeekBar.OnSeekBarChangeListener;
+import android.support.v8.renderscript.*;
+
+public class MainActivity extends Activity {
+    /* Number of bitmaps that is used for renderScript thread and UI thread synchronization.
+       Ideally, this can be reduced to 2, however in some devices, 2 buffers still showing tierings on UI.
+       Investigating a root cause.
+     */
+    private final int NUM_BITMAPS = 3;
+    private int mCurrentBitmap = 0;
+    private Bitmap mBitmapIn;
+    private Bitmap[] mBitmapsOut;
+    private ImageView mImageView;
+
+    private RenderScript mRS;
+    private Allocation mInAllocation;
+    private Allocation[] mOutAllocations;
+
+    private ScriptIntrinsicBlur mScriptBlur;
+    private ScriptIntrinsicConvolve5x5 mScriptConvolve;
+    private ScriptIntrinsicColorMatrix mScriptMatrix;
+
+    private final int MODE_BLUR = 0;
+    private final int MODE_CONVOLVE = 1;
+    private final int MODE_COLORMATRIX = 2;
+
+    private int mFilterMode = MODE_BLUR;
+
+    private RenderScriptTask mLatestTask = null;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        setContentView(R.layout.main_layout);
+
+        /*
+         * Initialize UI
+         */
+
+        //Set up main image view
+        mBitmapIn = loadBitmap(R.drawable.data);
+        mBitmapsOut = new Bitmap[NUM_BITMAPS];
+        for (int i = 0; i < NUM_BITMAPS; ++i) {
+            mBitmapsOut[i] = Bitmap.createBitmap(mBitmapIn.getWidth(),
+                    mBitmapIn.getHeight(), mBitmapIn.getConfig());
+        }
+
+        mImageView = (ImageView) findViewById(R.id.imageView);
+        mImageView.setImageBitmap(mBitmapsOut[mCurrentBitmap]);
+        mCurrentBitmap += (mCurrentBitmap + 1) % NUM_BITMAPS;
+
+        //Set up seekbar
+        final SeekBar seekbar = (SeekBar) findViewById(R.id.seekBar1);
+        seekbar.setProgress(50);
+        seekbar.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
+            public void onProgressChanged(SeekBar seekBar, int progress,
+                                          boolean fromUser) {
+                updateImage(progress);
+            }
+
+            @Override
+            public void onStartTrackingTouch(SeekBar seekBar) {
+            }
+
+            @Override
+            public void onStopTrackingTouch(SeekBar seekBar) {
+            }
+        });
+
+        //Setup effect selector
+        RadioButton radio0 = (RadioButton) findViewById(R.id.radio0);
+        radio0.setOnCheckedChangeListener(new OnCheckedChangeListener() {
+
+            @Override
+            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+                if (isChecked) {
+                    mFilterMode = MODE_BLUR;
+                    updateImage(seekbar.getProgress());
+                }
+            }
+        });
+        RadioButton radio1 = (RadioButton) findViewById(R.id.radio1);
+        radio1.setOnCheckedChangeListener(new OnCheckedChangeListener() {
+
+            @Override
+            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+                if (isChecked) {
+                    mFilterMode = MODE_CONVOLVE;
+                    updateImage(seekbar.getProgress());
+                }
+            }
+        });
+        RadioButton radio2 = (RadioButton) findViewById(R.id.radio2);
+        radio2.setOnCheckedChangeListener(new OnCheckedChangeListener() {
+
+            @Override
+            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+                if (isChecked) {
+                    mFilterMode = MODE_COLORMATRIX;
+                    updateImage(seekbar.getProgress());
+                }
+            }
+        });
+
+        /*
+         * Create renderScript
+         */
+        createScript();
+
+        /*
+         * Create thumbnails
+         */
+        createThumbnail();
+
+
+        /*
+         * Invoke renderScript kernel and update imageView
+         */
+        mFilterMode = MODE_BLUR;
+        updateImage(50);
+    }
+
+    private void createScript() {
+        mRS = RenderScript.create(this);
+
+        mInAllocation = Allocation.createFromBitmap(mRS, mBitmapIn);
+
+        mOutAllocations = new Allocation[NUM_BITMAPS];
+        for (int i = 0; i < NUM_BITMAPS; ++i) {
+            mOutAllocations[i] = Allocation.createFromBitmap(mRS, mBitmapsOut[i]);
+        }
+
+        /*
+        Create intrinsics.
+        RenderScript has built-in features such as blur, convolve filter etc.
+        These intrinsics are handy for specific operations without writing RenderScript kernel.
+        In the sample, it's creating blur, convolve and matrix intrinsics.
+         */
+
+        mScriptBlur = ScriptIntrinsicBlur.create(mRS, Element.U8_4(mRS));
+        mScriptConvolve = ScriptIntrinsicConvolve5x5.create(mRS,
+                Element.U8_4(mRS));
+        mScriptMatrix = ScriptIntrinsicColorMatrix.create(mRS,
+                Element.U8_4(mRS));
+    }
+
+    private void performFilter(Allocation inAllocation,
+                               Allocation outAllocation, Bitmap bitmapOut, float value) {
+        switch (mFilterMode) {
+            case MODE_BLUR:
+            /*
+             * Set blur kernel size
+             */
+                mScriptBlur.setRadius(value);
+
+            /*
+             * Invoke filter kernel
+             */
+                mScriptBlur.setInput(inAllocation);
+                mScriptBlur.forEach(outAllocation);
+                break;
+            case MODE_CONVOLVE: {
+                float f1 = value;
+                float f2 = 1.0f - f1;
+
+                // Emboss filter kernel
+                float coefficients[] = {-f1 * 2, 0, -f1, 0, 0, 0, -f2 * 2, -f2, 0,
+                        0, -f1, -f2, 1, f2, f1, 0, 0, f2, f2 * 2, 0, 0, 0, f1, 0,
+                        f1 * 2,};
+            /*
+             * Set kernel parameter
+             */
+                mScriptConvolve.setCoefficients(coefficients);
+
+            /*
+             * Invoke filter kernel
+             */
+                mScriptConvolve.setInput(inAllocation);
+                mScriptConvolve.forEach(outAllocation);
+                break;
+            }
+            case MODE_COLORMATRIX: {
+            /*
+             * Set HUE rotation matrix
+             * The matrix below performs a combined operation of,
+             * RGB->HSV transform * HUE rotation * HSV->RGB transform
+             */
+                float cos = (float) Math.cos((double) value);
+                float sin = (float) Math.sin((double) value);
+                Matrix3f mat = new Matrix3f();
+                mat.set(0, 0, (float) (.299 + .701 * cos + .168 * sin));
+                mat.set(1, 0, (float) (.587 - .587 * cos + .330 * sin));
+                mat.set(2, 0, (float) (.114 - .114 * cos - .497 * sin));
+                mat.set(0, 1, (float) (.299 - .299 * cos - .328 * sin));
+                mat.set(1, 1, (float) (.587 + .413 * cos + .035 * sin));
+                mat.set(2, 1, (float) (.114 - .114 * cos + .292 * sin));
+                mat.set(0, 2, (float) (.299 - .3 * cos + 1.25 * sin));
+                mat.set(1, 2, (float) (.587 - .588 * cos - 1.05 * sin));
+                mat.set(2, 2, (float) (.114 + .886 * cos - .203 * sin));
+                mScriptMatrix.setColorMatrix(mat);
+
+            /*
+             * Invoke filter kernel
+             */
+                mScriptMatrix.forEach(inAllocation, outAllocation);
+            }
+            break;
+        }
+
+        /*
+         * Copy to bitmap and invalidate image view
+         */
+        outAllocation.copyTo(bitmapOut);
+    }
+
+    /*
+    Convert seekBar progress parameter (0-100 in range) to parameter for each intrinsic filter.
+    (e.g. 1.0-25.0 in Blur filter)
+     */
+    private float getFilterParameter(int i) {
+        float f = 0.f;
+        switch (mFilterMode) {
+            case MODE_BLUR: {
+                final float max = 25.0f;
+                final float min = 1.f;
+                f = (float) ((max - min) * (i / 100.0) + min);
+            }
+            break;
+            case MODE_CONVOLVE: {
+                final float max = 2.f;
+                final float min = 0.f;
+                f = (float) ((max - min) * (i / 100.0) + min);
+            }
+            break;
+            case MODE_COLORMATRIX: {
+                final float max = (float) Math.PI;
+                final float min = (float) -Math.PI;
+                f = (float) ((max - min) * (i / 100.0) + min);
+            }
+            break;
+        }
+        return f;
+
+    }
+
+    /*
+     * In the AsyncTask, it invokes RenderScript intrinsics to do a filtering.
+     * After the filtering is done, an operation blocks at Allication.copyTo() in AsyncTask thread.
+     * Once all operation is finished at onPostExecute() in UI thread, it can invalidate and update ImageView UI.
+     */
+    private class RenderScriptTask extends AsyncTask<Float, Integer, Integer> {
+        Boolean issued = false;
+
+        protected Integer doInBackground(Float... values) {
+            int index = -1;
+            if (isCancelled() == false) {
+                issued = true;
+                index = mCurrentBitmap;
+
+                performFilter(mInAllocation, mOutAllocations[index], mBitmapsOut[index], values[0]);
+                mCurrentBitmap = (mCurrentBitmap + 1) % NUM_BITMAPS;
+            }
+            return index;
+        }
+
+        void updateView(Integer result) {
+            if (result != -1) {
+                // Request UI update
+                mImageView.setImageBitmap(mBitmapsOut[result]);
+                mImageView.invalidate();
+            }
+        }
+
+        protected void onPostExecute(Integer result) {
+            updateView(result);
+        }
+
+        protected void onCancelled(Integer result) {
+            if (issued) {
+                updateView(result);
+            }
+        }
+    }
+
+    /*
+    Invoke AsynchTask and cancel previous task.
+    When AsyncTasks are piled up (typically in slow device with heavy kernel),
+    Only the latest (and already started) task invokes RenderScript operation.
+     */
+    private void updateImage(int progress) {
+        float f = getFilterParameter(progress);
+
+        if (mLatestTask != null)
+            mLatestTask.cancel(false);
+        mLatestTask = new RenderScriptTask();
+
+        mLatestTask.execute(f);
+    }
+
+    /*
+    Helper to load Bitmap from resource
+     */
+    private Bitmap loadBitmap(int resource) {
+        final BitmapFactory.Options options = new BitmapFactory.Options();
+        options.inPreferredConfig = Bitmap.Config.ARGB_8888;
+        return BitmapFactory.decodeResource(getResources(), resource, options);
+    }
+
+    /*
+    Create thumbNail for UI. It invokes RenderScript kernel synchronously in UI-thread,
+    which is OK for small thumbnail (but not ideal).
+     */
+    private void createThumbnail() {
+        int width = 72;
+        int height = 96;
+        float scale = getResources().getDisplayMetrics().density;
+        int pixelsWidth = (int) (width * scale + 0.5f);
+        int pixelsHeight = (int) (height * scale + 0.5f);
+
+        //Temporary image
+        Bitmap tempBitmap = Bitmap.createScaledBitmap(mBitmapIn, pixelsWidth, pixelsHeight, false);
+        Allocation inAllocation = Allocation.createFromBitmap(mRS, tempBitmap);
+
+        //Create thumbnail with each RS intrinsic and set it to radio buttons
+        int[] modes = {MODE_BLUR, MODE_CONVOLVE, MODE_COLORMATRIX};
+        int[] ids = {R.id.radio0, R.id.radio1, R.id.radio2};
+        int[] parameter = {50, 100, 25};
+        for (int mode : modes) {
+            mFilterMode = mode;
+            float f = getFilterParameter(parameter[mode]);
+
+            Bitmap destBitpmap = Bitmap.createBitmap(tempBitmap.getWidth(),
+                    tempBitmap.getHeight(), tempBitmap.getConfig());
+            Allocation outAllocation = Allocation.createFromBitmap(mRS, destBitpmap);
+            performFilter(inAllocation, outAllocation, destBitpmap, f);
+
+            ThumbnailRadioButton button = (ThumbnailRadioButton) findViewById(ids[mode]);
+            button.setThumbnail(destBitpmap);
+        }
+    }
+}
diff --git a/samples/browseable/RenderScriptIntrinsic/src/com.example.android.renderscriptintrinsic/ThumbnailRadioButton.java b/samples/browseable/RenderScriptIntrinsic/src/com.example.android.renderscriptintrinsic/ThumbnailRadioButton.java
new file mode 100644
index 0000000..160e970
--- /dev/null
+++ b/samples/browseable/RenderScriptIntrinsic/src/com.example.android.renderscriptintrinsic/ThumbnailRadioButton.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.renderscriptintrinsic;
+
+import android.graphics.Bitmap;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.LayerDrawable;
+import android.graphics.drawable.ShapeDrawable;
+import android.graphics.drawable.StateListDrawable;
+import android.graphics.drawable.shapes.RectShape;
+import android.os.Build;
+import android.view.Gravity;
+import android.widget.RadioButton;
+import android.content.Context;
+import android.util.AttributeSet;
+
+/*
+ A button with Thumbnail which extends Radio Button.
+ The widget override a background drawable of Radio Button with a StateList Drawable.
+ Each state has a LayerDrawable with a Thumbnail image and a Focus rectangle.
+ It's using original Radio Buttons text as a label, because LayerDrawable showed some issues with Canvas.drawText().
+ */
+public class ThumbnailRadioButton extends RadioButton {
+    public ThumbnailRadioButton(Context context) {
+        super(context);
+        init();
+    }
+
+    public ThumbnailRadioButton(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        init();
+    }
+
+    public ThumbnailRadioButton(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+        init();
+    }
+
+    private void init() {
+        setButtonDrawable(android.R.color.transparent);
+    }
+
+    public void setThumbnail(Bitmap bitmap) {
+        //Bitmap drawable
+        BitmapDrawable bmp = new BitmapDrawable(getResources(), bitmap);
+        bmp.setGravity(Gravity.CENTER);
+
+        int strokeWidth = 24;
+        //Checked state
+        ShapeDrawable rectChecked = new ShapeDrawable(new RectShape());
+        rectChecked.getPaint().setColor(0xFFFFFFFF);
+        rectChecked.getPaint().setStyle(Paint.Style.STROKE);
+        rectChecked.getPaint().setStrokeWidth(strokeWidth);
+        rectChecked.setIntrinsicWidth(bitmap.getWidth() + strokeWidth);
+        rectChecked.setIntrinsicHeight(bitmap.getHeight() + strokeWidth);
+        Drawable drawableArray[] = new Drawable[]{bmp, rectChecked};
+        LayerDrawable layerChecked = new LayerDrawable(drawableArray);
+
+        //Unchecked state
+        ShapeDrawable rectUnchecked = new ShapeDrawable(new RectShape());
+        rectUnchecked.getPaint().setColor(0x0);
+        rectUnchecked.getPaint().setStyle(Paint.Style.STROKE);
+        rectUnchecked.getPaint().setStrokeWidth(strokeWidth);
+        rectUnchecked.setIntrinsicWidth(bitmap.getWidth() + strokeWidth);
+        rectUnchecked.setIntrinsicHeight(bitmap.getHeight() + strokeWidth);
+        Drawable drawableArray2[] = new Drawable[]{bmp, rectUnchecked};
+        LayerDrawable layerUnchecked = new LayerDrawable(drawableArray2);
+
+        //Statelist drawable
+        StateListDrawable states = new StateListDrawable();
+        states.addState(new int[]{android.R.attr.state_checked},
+                layerChecked);
+        states.addState(new int[]{},
+                layerUnchecked);
+
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN)
+            setBackground(states);
+        else
+            setBackgroundDrawable(states);
+
+        //Offset text to center/bottom of the checkbox
+        Paint paint = new Paint();
+        paint.setAntiAlias(true);
+        paint.setTextSize(getTextSize());
+        paint.setTypeface(getTypeface());
+        float w = paint.measureText(getText(), 0, getText().length());
+        setPadding(getPaddingLeft() + (int) ((bitmap.getWidth() - w) / 2.f + .5f),
+                getPaddingTop() + (int) (bitmap.getHeight() * 0.70),
+                getPaddingRight(),
+                getPaddingBottom());
+
+        setShadowLayer(5, 0, 0, Color.BLACK);
+    }
+}
diff --git a/samples/browseable/repeatingAlarm/AndroidManifest.xml b/samples/browseable/RepeatingAlarm/AndroidManifest.xml
similarity index 100%
rename from samples/browseable/repeatingAlarm/AndroidManifest.xml
rename to samples/browseable/RepeatingAlarm/AndroidManifest.xml
diff --git a/samples/browseable/repeatingAlarm/_index.jd b/samples/browseable/RepeatingAlarm/_index.jd
similarity index 71%
rename from samples/browseable/repeatingAlarm/_index.jd
rename to samples/browseable/RepeatingAlarm/_index.jd
index bd77d6c..69f7ee1 100644
--- a/samples/browseable/repeatingAlarm/_index.jd
+++ b/samples/browseable/RepeatingAlarm/_index.jd
@@ -4,6 +4,6 @@
 page.tags="RepeatingAlarm"
 sample.group=Background
 @jd:body
-
-<p>This sample demonstrates how to implement a repeating alarm using an
-{@link android.app.AlarmManager}.</p>
+	
+		
+<p>This sample demonstrates how to implement a repeating alarm using an	{@link android.app.AlarmManager}.</p>
diff --git a/samples/browseable/repeatingAlarm/res/drawable-hdpi/ic_launcher.png b/samples/browseable/RepeatingAlarm/res/drawable-hdpi/ic_launcher.png
similarity index 100%
rename from samples/browseable/repeatingAlarm/res/drawable-hdpi/ic_launcher.png
rename to samples/browseable/RepeatingAlarm/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/repeatingAlarm/res/drawable-hdpi/tile.9.png b/samples/browseable/RepeatingAlarm/res/drawable-hdpi/tile.9.png
similarity index 100%
rename from samples/browseable/repeatingAlarm/res/drawable-hdpi/tile.9.png
rename to samples/browseable/RepeatingAlarm/res/drawable-hdpi/tile.9.png
Binary files differ
diff --git a/samples/browseable/repeatingAlarm/res/drawable-mdpi/ic_launcher.png b/samples/browseable/RepeatingAlarm/res/drawable-mdpi/ic_launcher.png
similarity index 100%
rename from samples/browseable/repeatingAlarm/res/drawable-mdpi/ic_launcher.png
rename to samples/browseable/RepeatingAlarm/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/repeatingAlarm/res/drawable-xhdpi/ic_launcher.png b/samples/browseable/RepeatingAlarm/res/drawable-xhdpi/ic_launcher.png
similarity index 100%
rename from samples/browseable/repeatingAlarm/res/drawable-xhdpi/ic_launcher.png
rename to samples/browseable/RepeatingAlarm/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/repeatingAlarm/res/drawable-xxhdpi/ic_launcher.png b/samples/browseable/RepeatingAlarm/res/drawable-xxhdpi/ic_launcher.png
similarity index 100%
rename from samples/browseable/repeatingAlarm/res/drawable-xxhdpi/ic_launcher.png
rename to samples/browseable/RepeatingAlarm/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/repeatingAlarm/res/layout/activity_main.xml b/samples/browseable/RepeatingAlarm/res/layout/activity_main.xml
similarity index 100%
rename from samples/browseable/repeatingAlarm/res/layout/activity_main.xml
rename to samples/browseable/RepeatingAlarm/res/layout/activity_main.xml
diff --git a/samples/browseable/repeatingAlarm/res/menu/main.xml b/samples/browseable/RepeatingAlarm/res/menu/main.xml
similarity index 100%
rename from samples/browseable/repeatingAlarm/res/menu/main.xml
rename to samples/browseable/RepeatingAlarm/res/menu/main.xml
diff --git a/samples/browseable/repeatingAlarm/res/values-sw600dp/dimens.xml b/samples/browseable/RepeatingAlarm/res/values-sw600dp/template-dimens.xml
similarity index 100%
rename from samples/browseable/repeatingAlarm/res/values-sw600dp/dimens.xml
rename to samples/browseable/RepeatingAlarm/res/values-sw600dp/template-dimens.xml
diff --git a/samples/browseable/repeatingAlarm/res/values-sw600dp/styles.xml b/samples/browseable/RepeatingAlarm/res/values-sw600dp/template-styles.xml
similarity index 100%
rename from samples/browseable/repeatingAlarm/res/values-sw600dp/styles.xml
rename to samples/browseable/RepeatingAlarm/res/values-sw600dp/template-styles.xml
diff --git a/samples/browseable/repeatingAlarm/res/values/base-strings.xml b/samples/browseable/RepeatingAlarm/res/values/base-strings.xml
similarity index 94%
rename from samples/browseable/repeatingAlarm/res/values/base-strings.xml
rename to samples/browseable/RepeatingAlarm/res/values/base-strings.xml
index c11b89b..6b89192 100644
--- a/samples/browseable/repeatingAlarm/res/values/base-strings.xml
+++ b/samples/browseable/RepeatingAlarm/res/values/base-strings.xml
@@ -18,7 +18,7 @@
 
 
 <resources>
-    <string name="app_name">repeatingAlarm</string>
+    <string name="app_name">RepeatingAlarm</string>
     <string name="intro_message">
         <![CDATA[
         
diff --git a/samples/browseable/repeatingAlarm/res/values/strings.xml b/samples/browseable/RepeatingAlarm/res/values/strings.xml
similarity index 100%
rename from samples/browseable/repeatingAlarm/res/values/strings.xml
rename to samples/browseable/RepeatingAlarm/res/values/strings.xml
diff --git a/samples/browseable/repeatingAlarm/res/values/dimens.xml b/samples/browseable/RepeatingAlarm/res/values/template-dimens.xml
similarity index 100%
rename from samples/browseable/repeatingAlarm/res/values/dimens.xml
rename to samples/browseable/RepeatingAlarm/res/values/template-dimens.xml
diff --git a/samples/browseable/repeatingAlarm/res/values/styles.xml b/samples/browseable/RepeatingAlarm/res/values/template-styles.xml
similarity index 100%
rename from samples/browseable/repeatingAlarm/res/values/styles.xml
rename to samples/browseable/RepeatingAlarm/res/values/template-styles.xml
diff --git a/samples/browseable/repeatingAlarm/src/com.example.android.common/activities/SampleActivityBase.java b/samples/browseable/RepeatingAlarm/src/com.example.android.common/activities/SampleActivityBase.java
similarity index 100%
rename from samples/browseable/repeatingAlarm/src/com.example.android.common/activities/SampleActivityBase.java
rename to samples/browseable/RepeatingAlarm/src/com.example.android.common/activities/SampleActivityBase.java
diff --git a/samples/browseable/repeatingAlarm/src/com.example.android.common/logger/Log.java b/samples/browseable/RepeatingAlarm/src/com.example.android.common/logger/Log.java
similarity index 100%
rename from samples/browseable/repeatingAlarm/src/com.example.android.common/logger/Log.java
rename to samples/browseable/RepeatingAlarm/src/com.example.android.common/logger/Log.java
diff --git a/samples/browseable/repeatingAlarm/src/com.example.android.common/logger/LogFragment.java b/samples/browseable/RepeatingAlarm/src/com.example.android.common/logger/LogFragment.java
similarity index 100%
rename from samples/browseable/repeatingAlarm/src/com.example.android.common/logger/LogFragment.java
rename to samples/browseable/RepeatingAlarm/src/com.example.android.common/logger/LogFragment.java
diff --git a/samples/browseable/repeatingAlarm/src/com.example.android.common/logger/LogNode.java b/samples/browseable/RepeatingAlarm/src/com.example.android.common/logger/LogNode.java
similarity index 100%
rename from samples/browseable/repeatingAlarm/src/com.example.android.common/logger/LogNode.java
rename to samples/browseable/RepeatingAlarm/src/com.example.android.common/logger/LogNode.java
diff --git a/samples/browseable/repeatingAlarm/src/com.example.android.common/logger/LogView.java b/samples/browseable/RepeatingAlarm/src/com.example.android.common/logger/LogView.java
similarity index 100%
rename from samples/browseable/repeatingAlarm/src/com.example.android.common/logger/LogView.java
rename to samples/browseable/RepeatingAlarm/src/com.example.android.common/logger/LogView.java
diff --git a/samples/browseable/repeatingAlarm/src/com.example.android.common/logger/LogWrapper.java b/samples/browseable/RepeatingAlarm/src/com.example.android.common/logger/LogWrapper.java
similarity index 100%
rename from samples/browseable/repeatingAlarm/src/com.example.android.common/logger/LogWrapper.java
rename to samples/browseable/RepeatingAlarm/src/com.example.android.common/logger/LogWrapper.java
diff --git a/samples/browseable/repeatingAlarm/src/com.example.android.common/logger/MessageOnlyLogFilter.java b/samples/browseable/RepeatingAlarm/src/com.example.android.common/logger/MessageOnlyLogFilter.java
similarity index 100%
rename from samples/browseable/repeatingAlarm/src/com.example.android.common/logger/MessageOnlyLogFilter.java
rename to samples/browseable/RepeatingAlarm/src/com.example.android.common/logger/MessageOnlyLogFilter.java
diff --git a/samples/browseable/repeatingAlarm/src/com.example.android.repeatingalarm/MainActivity.java b/samples/browseable/RepeatingAlarm/src/com.example.android.repeatingalarm/MainActivity.java
similarity index 100%
rename from samples/browseable/repeatingAlarm/src/com.example.android.repeatingalarm/MainActivity.java
rename to samples/browseable/RepeatingAlarm/src/com.example.android.repeatingalarm/MainActivity.java
diff --git a/samples/browseable/repeatingAlarm/src/com.example.android.repeatingalarm/RepeatingAlarmFragment.java b/samples/browseable/RepeatingAlarm/src/com.example.android.repeatingalarm/RepeatingAlarmFragment.java
similarity index 100%
rename from samples/browseable/repeatingAlarm/src/com.example.android.repeatingalarm/RepeatingAlarmFragment.java
rename to samples/browseable/RepeatingAlarm/src/com.example.android.repeatingalarm/RepeatingAlarmFragment.java
diff --git a/samples/browseable/SlidingTabsBasic/AndroidManifest.xml b/samples/browseable/SlidingTabsBasic/AndroidManifest.xml
new file mode 100644
index 0000000..31cbfb8
--- /dev/null
+++ b/samples/browseable/SlidingTabsBasic/AndroidManifest.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 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.slidingtabsbasic"
+    android:versionCode="1"
+    android:versionName="1.0">
+
+    <uses-sdk android:minSdkVersion="4" android:targetSdkVersion="19" />
+
+    <application android:allowBackup="true"
+        android:label="@string/app_name"
+        android:icon="@drawable/ic_launcher"
+        android:theme="@style/AppTheme">
+
+        <activity android:name=".MainActivity"
+                  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/browseable/SlidingTabsBasic/_index.jd b/samples/browseable/SlidingTabsBasic/_index.jd
new file mode 100644
index 0000000..261885c
--- /dev/null
+++ b/samples/browseable/SlidingTabsBasic/_index.jd
@@ -0,0 +1,14 @@
+
+
+
+page.tags="SlidingTabsBasic"
+sample.group=UI
+@jd:body
+
+<p>
+  This sample shows how to use <code><a href=
+  "{@docRoot}samples/SlidingTabsBasic/src/com.example.android.common/view/SlidingTabLayout.html">
+  SlidingTabLayout</a></code> to display a custom {@link
+  android.support.v4.view.ViewPager ViewPager} title strip that gives
+  continuous feedback to the user when scrolling.
+</p>
\ No newline at end of file
diff --git a/samples/browseable/SlidingTabsBasic/res/drawable-hdpi/ic_launcher.png b/samples/browseable/SlidingTabsBasic/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..53ebb57
--- /dev/null
+++ b/samples/browseable/SlidingTabsBasic/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/Basic/res/drawable-hdpi/tile.9.png b/samples/browseable/SlidingTabsBasic/res/drawable-hdpi/tile.9.png
similarity index 100%
copy from samples/browseable/Basic/res/drawable-hdpi/tile.9.png
copy to samples/browseable/SlidingTabsBasic/res/drawable-hdpi/tile.9.png
Binary files differ
diff --git a/samples/browseable/SlidingTabsBasic/res/drawable-mdpi/ic_launcher.png b/samples/browseable/SlidingTabsBasic/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..33aa87a
--- /dev/null
+++ b/samples/browseable/SlidingTabsBasic/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/SlidingTabsBasic/res/drawable-xhdpi/ic_launcher.png b/samples/browseable/SlidingTabsBasic/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..6a4ba00
--- /dev/null
+++ b/samples/browseable/SlidingTabsBasic/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/SlidingTabsBasic/res/drawable-xxhdpi/ic_launcher.png b/samples/browseable/SlidingTabsBasic/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..c3744cd
--- /dev/null
+++ b/samples/browseable/SlidingTabsBasic/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/SlidingTabsBasic/res/layout-w720dp/activity_main.xml b/samples/browseable/SlidingTabsBasic/res/layout-w720dp/activity_main.xml
new file mode 100755
index 0000000..c9a52f6
--- /dev/null
+++ b/samples/browseable/SlidingTabsBasic/res/layout-w720dp/activity_main.xml
@@ -0,0 +1,73 @@
+<!--
+  Copyright 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"
+      android:orientation="horizontal"
+      android:layout_width="match_parent"
+      android:layout_height="match_parent"
+      android:id="@+id/sample_main_layout">
+
+    <LinearLayout
+          android:id="@+id/sample_output"
+          android:layout_width="0px"
+          android:layout_height="match_parent"
+          android:layout_weight="1"
+          android:orientation="vertical">
+
+        <FrameLayout
+              style="@style/Widget.SampleMessageTile"
+              android:layout_width="match_parent"
+              android:layout_height="wrap_content">
+
+            <TextView
+                  style="@style/Widget.SampleMessage"
+                  android:layout_width="match_parent"
+                  android:layout_height="wrap_content"
+                  android:paddingLeft="@dimen/margin_medium"
+                  android:paddingRight="@dimen/margin_medium"
+                  android:paddingTop="@dimen/margin_large"
+                  android:paddingBottom="@dimen/margin_large"
+                  android:text="@string/intro_message" />
+        </FrameLayout>
+
+        <View
+              android:layout_width="match_parent"
+              android:layout_height="1dp"
+              android:background="@android:color/darker_gray" />
+
+        <fragment
+              android:name="com.example.android.common.logger.LogFragment"
+              android:id="@+id/log_fragment"
+              android:layout_width="match_parent"
+              android:layout_height="0px"
+              android:layout_weight="1" />
+
+    </LinearLayout>
+
+    <View
+          android:layout_width="1dp"
+          android:layout_height="match_parent"
+          android:background="@android:color/darker_gray" />
+
+    <FrameLayout
+          android:id="@+id/sample_content_fragment"
+          android:layout_weight="2"
+          android:layout_width="0px"
+          android:layout_height="match_parent" />
+
+</LinearLayout>
+
+
diff --git a/samples/browseable/SlidingTabsBasic/res/layout/activity_main.xml b/samples/browseable/SlidingTabsBasic/res/layout/activity_main.xml
new file mode 100755
index 0000000..1ae4f98
--- /dev/null
+++ b/samples/browseable/SlidingTabsBasic/res/layout/activity_main.xml
@@ -0,0 +1,65 @@
+<!--
+  Copyright 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"
+      android:orientation="vertical"
+      android:layout_width="match_parent"
+      android:layout_height="match_parent"
+      android:id="@+id/sample_main_layout">
+
+    <ViewAnimator
+          android:id="@+id/sample_output"
+          android:layout_width="match_parent"
+          android:layout_height="0px"
+          android:layout_weight="1">
+
+        <ScrollView
+              style="@style/Widget.SampleMessageTile"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent">
+
+            <TextView
+                  style="@style/Widget.SampleMessage"
+                  android:layout_width="match_parent"
+                  android:layout_height="wrap_content"
+                  android:paddingLeft="@dimen/horizontal_page_margin"
+                  android:paddingRight="@dimen/horizontal_page_margin"
+                  android:paddingTop="@dimen/vertical_page_margin"
+                  android:paddingBottom="@dimen/vertical_page_margin"
+                  android:text="@string/intro_message" />
+        </ScrollView>
+
+        <fragment
+              android:name="com.example.android.common.logger.LogFragment"
+              android:id="@+id/log_fragment"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent" />
+
+    </ViewAnimator>
+
+    <View
+          android:layout_width="match_parent"
+          android:layout_height="1dp"
+          android:background="@android:color/darker_gray" />
+
+    <FrameLayout
+          android:id="@+id/sample_content_fragment"
+          android:layout_weight="2"
+          android:layout_width="match_parent"
+          android:layout_height="0px" />
+
+</LinearLayout>
+
diff --git a/samples/browseable/SlidingTabsBasic/res/layout/fragment_sample.xml b/samples/browseable/SlidingTabsBasic/res/layout/fragment_sample.xml
new file mode 100644
index 0000000..6ac3690
--- /dev/null
+++ b/samples/browseable/SlidingTabsBasic/res/layout/fragment_sample.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+      android:layout_width="match_parent"
+      android:layout_height="match_parent"
+      android:orientation="vertical">
+
+    <com.example.android.common.view.SlidingTabLayout
+          android:id="@+id/sliding_tabs"
+          android:layout_width="match_parent"
+          android:layout_height="wrap_content" />
+
+    <android.support.v4.view.ViewPager
+          android:id="@+id/viewpager"
+          android:layout_width="match_parent"
+          android:layout_height="0px"
+          android:layout_weight="1"
+          android:background="@android:color/white"/>
+
+</LinearLayout>
\ No newline at end of file
diff --git a/samples/browseable/SlidingTabsBasic/res/layout/pager_item.xml b/samples/browseable/SlidingTabsBasic/res/layout/pager_item.xml
new file mode 100644
index 0000000..ce4413f
--- /dev/null
+++ b/samples/browseable/SlidingTabsBasic/res/layout/pager_item.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+      android:layout_width="match_parent"
+      android:layout_height="match_parent"
+      android:orientation="vertical"
+      android:gravity="center">
+
+    <TextView
+          android:id="@+id/item_subtitle"
+          android:layout_width="wrap_content"
+          android:layout_height="wrap_content"
+          android:textAppearance="?android:attr/textAppearanceLarge"
+          android:text="Page:"/>
+
+    <TextView
+          android:id="@+id/item_title"
+          android:layout_width="wrap_content"
+          android:layout_height="wrap_content"
+          android:textSize="80sp" />
+
+</LinearLayout>
\ No newline at end of file
diff --git a/samples/training/bitmapfun/BitmapFun/src/main/res/values/colors.xml b/samples/browseable/SlidingTabsBasic/res/menu/main.xml
similarity index 60%
copy from samples/training/bitmapfun/BitmapFun/src/main/res/values/colors.xml
copy to samples/browseable/SlidingTabsBasic/res/menu/main.xml
index 7e4a4fe..b49c2c5 100644
--- a/samples/training/bitmapfun/BitmapFun/src/main/res/values/colors.xml
+++ b/samples/browseable/SlidingTabsBasic/res/menu/main.xml
@@ -1,23 +1,21 @@
-<?xml version="1.0" encoding="utf-8"?>
 <!--
-  Copyright (C) 2012 The Android Open Source Project
+  Copyright 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
+      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>
-
-    <color name="grid_state_pressed">#BB7dbcd3</color>
-    <color name="grid_state_focused">#777dbcd3</color>
-
-</resources>
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:id="@+id/menu_toggle_log"
+          android:showAsAction="always"
+          android:title="@string/sample_show_log" />
+</menu>
diff --git a/samples/browseable/Basic/res/values-sw600dp/dimens.xml b/samples/browseable/SlidingTabsBasic/res/values-sw600dp/template-dimens.xml
similarity index 100%
copy from samples/browseable/Basic/res/values-sw600dp/dimens.xml
copy to samples/browseable/SlidingTabsBasic/res/values-sw600dp/template-dimens.xml
diff --git a/samples/browseable/Basic/res/values-sw600dp/styles.xml b/samples/browseable/SlidingTabsBasic/res/values-sw600dp/template-styles.xml
similarity index 100%
copy from samples/browseable/Basic/res/values-sw600dp/styles.xml
copy to samples/browseable/SlidingTabsBasic/res/values-sw600dp/template-styles.xml
diff --git a/samples/browseable/repeatingAlarm/res/values/base-strings.xml b/samples/browseable/SlidingTabsBasic/res/values/base-strings.xml
similarity index 76%
copy from samples/browseable/repeatingAlarm/res/values/base-strings.xml
copy to samples/browseable/SlidingTabsBasic/res/values/base-strings.xml
index c11b89b..c7f26bf 100644
--- a/samples/browseable/repeatingAlarm/res/values/base-strings.xml
+++ b/samples/browseable/SlidingTabsBasic/res/values/base-strings.xml
@@ -18,13 +18,13 @@
 
 
 <resources>
-    <string name="app_name">repeatingAlarm</string>
+    <string name="app_name">SlidingTabsBasic</string>
     <string name="intro_message">
         <![CDATA[
         
             
-                Introductory text that explains what the sample is intended to demonstrate. Edit
-                in template-params.xml.
+            A basic sample which shows how to use SlidingTabLayout to display a custom
+            ViewPager title strip which gives continuous feedback to the user when scrolling.
             
         
         ]]>
diff --git a/samples/training/bitmapfun/BitmapFun/src/main/res/values/colors.xml b/samples/browseable/SlidingTabsBasic/res/values/strings.xml
old mode 100644
new mode 100755
similarity index 67%
copy from samples/training/bitmapfun/BitmapFun/src/main/res/values/colors.xml
copy to samples/browseable/SlidingTabsBasic/res/values/strings.xml
index 7e4a4fe..7b9d9ec
--- a/samples/training/bitmapfun/BitmapFun/src/main/res/values/colors.xml
+++ b/samples/browseable/SlidingTabsBasic/res/values/strings.xml
@@ -1,12 +1,11 @@
-<?xml version="1.0" encoding="utf-8"?>
 <!--
-  Copyright (C) 2012 The Android Open Source Project
+  Copyright 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
+      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,
@@ -14,10 +13,7 @@
   See the License for the specific language governing permissions and
   limitations under the License.
 -->
-
 <resources>
-
-    <color name="grid_state_pressed">#BB7dbcd3</color>
-    <color name="grid_state_focused">#777dbcd3</color>
-
+    <string name="sample_show_log">Show Log</string>
+    <string name="sample_hide_log">Hide Log</string>
 </resources>
diff --git a/samples/browseable/Basic/res/values/dimens.xml b/samples/browseable/SlidingTabsBasic/res/values/template-dimens.xml
similarity index 100%
copy from samples/browseable/Basic/res/values/dimens.xml
copy to samples/browseable/SlidingTabsBasic/res/values/template-dimens.xml
diff --git a/samples/browseable/Basic/res/values/styles.xml b/samples/browseable/SlidingTabsBasic/res/values/template-styles.xml
similarity index 100%
copy from samples/browseable/Basic/res/values/styles.xml
copy to samples/browseable/SlidingTabsBasic/res/values/template-styles.xml
diff --git a/samples/browseable/repeatingAlarm/src/com.example.android.common/activities/SampleActivityBase.java b/samples/browseable/SlidingTabsBasic/src/com.example.android.common/activities/SampleActivityBase.java
similarity index 100%
copy from samples/browseable/repeatingAlarm/src/com.example.android.common/activities/SampleActivityBase.java
copy to samples/browseable/SlidingTabsBasic/src/com.example.android.common/activities/SampleActivityBase.java
diff --git a/samples/browseable/repeatingAlarm/src/com.example.android.common/logger/Log.java b/samples/browseable/SlidingTabsBasic/src/com.example.android.common/logger/Log.java
similarity index 100%
copy from samples/browseable/repeatingAlarm/src/com.example.android.common/logger/Log.java
copy to samples/browseable/SlidingTabsBasic/src/com.example.android.common/logger/Log.java
diff --git a/samples/browseable/repeatingAlarm/src/com.example.android.common/logger/LogFragment.java b/samples/browseable/SlidingTabsBasic/src/com.example.android.common/logger/LogFragment.java
similarity index 100%
copy from samples/browseable/repeatingAlarm/src/com.example.android.common/logger/LogFragment.java
copy to samples/browseable/SlidingTabsBasic/src/com.example.android.common/logger/LogFragment.java
diff --git a/samples/browseable/repeatingAlarm/src/com.example.android.common/logger/LogNode.java b/samples/browseable/SlidingTabsBasic/src/com.example.android.common/logger/LogNode.java
similarity index 100%
copy from samples/browseable/repeatingAlarm/src/com.example.android.common/logger/LogNode.java
copy to samples/browseable/SlidingTabsBasic/src/com.example.android.common/logger/LogNode.java
diff --git a/samples/browseable/repeatingAlarm/src/com.example.android.common/logger/LogView.java b/samples/browseable/SlidingTabsBasic/src/com.example.android.common/logger/LogView.java
similarity index 100%
copy from samples/browseable/repeatingAlarm/src/com.example.android.common/logger/LogView.java
copy to samples/browseable/SlidingTabsBasic/src/com.example.android.common/logger/LogView.java
diff --git a/samples/browseable/repeatingAlarm/src/com.example.android.common/logger/LogWrapper.java b/samples/browseable/SlidingTabsBasic/src/com.example.android.common/logger/LogWrapper.java
similarity index 100%
copy from samples/browseable/repeatingAlarm/src/com.example.android.common/logger/LogWrapper.java
copy to samples/browseable/SlidingTabsBasic/src/com.example.android.common/logger/LogWrapper.java
diff --git a/samples/browseable/repeatingAlarm/src/com.example.android.common/logger/MessageOnlyLogFilter.java b/samples/browseable/SlidingTabsBasic/src/com.example.android.common/logger/MessageOnlyLogFilter.java
similarity index 100%
copy from samples/browseable/repeatingAlarm/src/com.example.android.common/logger/MessageOnlyLogFilter.java
copy to samples/browseable/SlidingTabsBasic/src/com.example.android.common/logger/MessageOnlyLogFilter.java
diff --git a/samples/browseable/SlidingTabsBasic/src/com.example.android.common/view/SlidingTabLayout.java b/samples/browseable/SlidingTabsBasic/src/com.example.android.common/view/SlidingTabLayout.java
new file mode 100644
index 0000000..20049e3
--- /dev/null
+++ b/samples/browseable/SlidingTabsBasic/src/com.example.android.common/view/SlidingTabLayout.java
@@ -0,0 +1,314 @@
+/*
+ * 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.common.view;
+
+import android.content.Context;
+import android.graphics.Typeface;
+import android.os.Build;
+import android.support.v4.view.PagerAdapter;
+import android.support.v4.view.ViewPager;
+import android.util.AttributeSet;
+import android.util.TypedValue;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.HorizontalScrollView;
+import android.widget.TextView;
+
+/**
+ * To be used with ViewPager to provide a tab indicator component which give constant feedback as to
+ * the user's scroll progress.
+ * <p>
+ * To use the component, simply add it to your view hierarchy. Then in your
+ * {@link android.app.Activity} or {@link android.support.v4.app.Fragment} call
+ * {@link #setViewPager(ViewPager)} providing it the ViewPager this layout is being used for.
+ * <p>
+ * The colors can be customized in two ways. The first and simplest is to provide an array of colors
+ * via {@link #setSelectedIndicatorColors(int...)} and {@link #setDividerColors(int...)}. The
+ * alternative is via the {@link TabColorizer} interface which provides you complete control over
+ * which color is used for any individual position.
+ * <p>
+ * The views used as tabs can be customized by calling {@link #setCustomTabView(int, int)},
+ * providing the layout ID of your custom layout.
+ */
+public class SlidingTabLayout extends HorizontalScrollView {
+
+    /**
+     * Allows complete control over the colors drawn in the tab layout. Set with
+     * {@link #setCustomTabColorizer(TabColorizer)}.
+     */
+    public interface TabColorizer {
+
+        /**
+         * @return return the color of the indicator used when {@code position} is selected.
+         */
+        int getIndicatorColor(int position);
+
+        /**
+         * @return return the color of the divider drawn to the right of {@code position}.
+         */
+        int getDividerColor(int position);
+
+    }
+
+    private static final int TITLE_OFFSET_DIPS = 24;
+    private static final int TAB_VIEW_PADDING_DIPS = 16;
+    private static final int TAB_VIEW_TEXT_SIZE_SP = 12;
+
+    private int mTitleOffset;
+
+    private int mTabViewLayoutId;
+    private int mTabViewTextViewId;
+
+    private ViewPager mViewPager;
+    private ViewPager.OnPageChangeListener mViewPagerPageChangeListener;
+
+    private final SlidingTabStrip mTabStrip;
+
+    public SlidingTabLayout(Context context) {
+        this(context, null);
+    }
+
+    public SlidingTabLayout(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public SlidingTabLayout(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+
+        // Disable the Scroll Bar
+        setHorizontalScrollBarEnabled(false);
+        // Make sure that the Tab Strips fills this View
+        setFillViewport(true);
+
+        mTitleOffset = (int) (TITLE_OFFSET_DIPS * getResources().getDisplayMetrics().density);
+
+        mTabStrip = new SlidingTabStrip(context);
+        addView(mTabStrip, LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
+    }
+
+    /**
+     * Set the custom {@link TabColorizer} to be used.
+     *
+     * If you only require simple custmisation then you can use
+     * {@link #setSelectedIndicatorColors(int...)} and {@link #setDividerColors(int...)} to achieve
+     * similar effects.
+     */
+    public void setCustomTabColorizer(TabColorizer tabColorizer) {
+        mTabStrip.setCustomTabColorizer(tabColorizer);
+    }
+
+    /**
+     * Sets the colors to be used for indicating the selected tab. These colors are treated as a
+     * circular array. Providing one color will mean that all tabs are indicated with the same color.
+     */
+    public void setSelectedIndicatorColors(int... colors) {
+        mTabStrip.setSelectedIndicatorColors(colors);
+    }
+
+    /**
+     * Sets the colors to be used for tab dividers. These colors are treated as a circular array.
+     * Providing one color will mean that all tabs are indicated with the same color.
+     */
+    public void setDividerColors(int... colors) {
+        mTabStrip.setDividerColors(colors);
+    }
+
+    /**
+     * Set the {@link ViewPager.OnPageChangeListener}. When using {@link SlidingTabLayout} you are
+     * required to set any {@link ViewPager.OnPageChangeListener} through this method. This is so
+     * that the layout can update it's scroll position correctly.
+     *
+     * @see ViewPager#setOnPageChangeListener(ViewPager.OnPageChangeListener)
+     */
+    public void setOnPageChangeListener(ViewPager.OnPageChangeListener listener) {
+        mViewPagerPageChangeListener = listener;
+    }
+
+    /**
+     * Set the custom layout to be inflated for the tab views.
+     *
+     * @param layoutResId Layout id to be inflated
+     * @param textViewId id of the {@link TextView} in the inflated view
+     */
+    public void setCustomTabView(int layoutResId, int textViewId) {
+        mTabViewLayoutId = layoutResId;
+        mTabViewTextViewId = textViewId;
+    }
+
+    /**
+     * Sets the associated view pager. Note that the assumption here is that the pager content
+     * (number of tabs and tab titles) does not change after this call has been made.
+     */
+    public void setViewPager(ViewPager viewPager) {
+        mTabStrip.removeAllViews();
+
+        mViewPager = viewPager;
+        if (viewPager != null) {
+            viewPager.setOnPageChangeListener(new InternalViewPagerListener());
+            populateTabStrip();
+        }
+    }
+
+    /**
+     * Create a default view to be used for tabs. This is called if a custom tab view is not set via
+     * {@link #setCustomTabView(int, int)}.
+     */
+    protected TextView createDefaultTabView(Context context) {
+        TextView textView = new TextView(context);
+        textView.setGravity(Gravity.CENTER);
+        textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, TAB_VIEW_TEXT_SIZE_SP);
+        textView.setTypeface(Typeface.DEFAULT_BOLD);
+
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
+            // If we're running on Honeycomb or newer, then we can use the Theme's
+            // selectableItemBackground to ensure that the View has a pressed state
+            TypedValue outValue = new TypedValue();
+            getContext().getTheme().resolveAttribute(android.R.attr.selectableItemBackground,
+                    outValue, true);
+            textView.setBackgroundResource(outValue.resourceId);
+        }
+
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
+            // If we're running on ICS or newer, enable all-caps to match the Action Bar tab style
+            textView.setAllCaps(true);
+        }
+
+        int padding = (int) (TAB_VIEW_PADDING_DIPS * getResources().getDisplayMetrics().density);
+        textView.setPadding(padding, padding, padding, padding);
+
+        return textView;
+    }
+
+    private void populateTabStrip() {
+        final PagerAdapter adapter = mViewPager.getAdapter();
+        final View.OnClickListener tabClickListener = new TabClickListener();
+
+        for (int i = 0; i < adapter.getCount(); i++) {
+            View tabView = null;
+            TextView tabTitleView = null;
+
+            if (mTabViewLayoutId != 0) {
+                // If there is a custom tab view layout id set, try and inflate it
+                tabView = LayoutInflater.from(getContext()).inflate(mTabViewLayoutId, mTabStrip,
+                        false);
+                tabTitleView = (TextView) tabView.findViewById(mTabViewTextViewId);
+            }
+
+            if (tabView == null) {
+                tabView = createDefaultTabView(getContext());
+            }
+
+            if (tabTitleView == null && TextView.class.isInstance(tabView)) {
+                tabTitleView = (TextView) tabView;
+            }
+
+            tabTitleView.setText(adapter.getPageTitle(i));
+            tabView.setOnClickListener(tabClickListener);
+
+            mTabStrip.addView(tabView);
+        }
+    }
+
+    @Override
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+
+        if (mViewPager != null) {
+            scrollToTab(mViewPager.getCurrentItem(), 0);
+        }
+    }
+
+    private void scrollToTab(int tabIndex, int positionOffset) {
+        final int tabStripChildCount = mTabStrip.getChildCount();
+        if (tabStripChildCount == 0 || tabIndex < 0 || tabIndex >= tabStripChildCount) {
+            return;
+        }
+
+        View selectedChild = mTabStrip.getChildAt(tabIndex);
+        if (selectedChild != null) {
+            int targetScrollX = selectedChild.getLeft() + positionOffset;
+
+            if (tabIndex > 0 || positionOffset > 0) {
+                // If we're not at the first child and are mid-scroll, make sure we obey the offset
+                targetScrollX -= mTitleOffset;
+            }
+
+            scrollTo(targetScrollX, 0);
+        }
+    }
+
+    private class InternalViewPagerListener implements ViewPager.OnPageChangeListener {
+        private int mScrollState;
+
+        @Override
+        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
+            int tabStripChildCount = mTabStrip.getChildCount();
+            if ((tabStripChildCount == 0) || (position < 0) || (position >= tabStripChildCount)) {
+                return;
+            }
+
+            mTabStrip.onViewPagerPageChanged(position, positionOffset);
+
+            View selectedTitle = mTabStrip.getChildAt(position);
+            int extraOffset = (selectedTitle != null)
+                    ? (int) (positionOffset * selectedTitle.getWidth())
+                    : 0;
+            scrollToTab(position, extraOffset);
+
+            if (mViewPagerPageChangeListener != null) {
+                mViewPagerPageChangeListener.onPageScrolled(position, positionOffset,
+                        positionOffsetPixels);
+            }
+        }
+
+        @Override
+        public void onPageScrollStateChanged(int state) {
+            mScrollState = state;
+
+            if (mViewPagerPageChangeListener != null) {
+                mViewPagerPageChangeListener.onPageScrollStateChanged(state);
+            }
+        }
+
+        @Override
+        public void onPageSelected(int position) {
+            if (mScrollState == ViewPager.SCROLL_STATE_IDLE) {
+                mTabStrip.onViewPagerPageChanged(position, 0f);
+                scrollToTab(position, 0);
+            }
+
+            if (mViewPagerPageChangeListener != null) {
+                mViewPagerPageChangeListener.onPageSelected(position);
+            }
+        }
+
+    }
+
+    private class TabClickListener implements View.OnClickListener {
+        @Override
+        public void onClick(View v) {
+            for (int i = 0; i < mTabStrip.getChildCount(); i++) {
+                if (v == mTabStrip.getChildAt(i)) {
+                    mViewPager.setCurrentItem(i);
+                    return;
+                }
+            }
+        }
+    }
+
+}
diff --git a/samples/browseable/SlidingTabsBasic/src/com.example.android.common/view/SlidingTabStrip.java b/samples/browseable/SlidingTabsBasic/src/com.example.android.common/view/SlidingTabStrip.java
new file mode 100644
index 0000000..d5bbbae
--- /dev/null
+++ b/samples/browseable/SlidingTabsBasic/src/com.example.android.common/view/SlidingTabStrip.java
@@ -0,0 +1,208 @@
+/*
+ * 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.common.view;
+
+import android.R;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.util.AttributeSet;
+import android.util.TypedValue;
+import android.view.View;
+import android.widget.LinearLayout;
+
+class SlidingTabStrip extends LinearLayout {
+
+    private static final int DEFAULT_BOTTOM_BORDER_THICKNESS_DIPS = 2;
+    private static final byte DEFAULT_BOTTOM_BORDER_COLOR_ALPHA = 0x26;
+    private static final int SELECTED_INDICATOR_THICKNESS_DIPS = 8;
+    private static final int DEFAULT_SELECTED_INDICATOR_COLOR = 0xFF33B5E5;
+
+    private static final int DEFAULT_DIVIDER_THICKNESS_DIPS = 1;
+    private static final byte DEFAULT_DIVIDER_COLOR_ALPHA = 0x20;
+    private static final float DEFAULT_DIVIDER_HEIGHT = 0.5f;
+
+    private final int mBottomBorderThickness;
+    private final Paint mBottomBorderPaint;
+
+    private final int mSelectedIndicatorThickness;
+    private final Paint mSelectedIndicatorPaint;
+
+    private final int mDefaultBottomBorderColor;
+
+    private final Paint mDividerPaint;
+    private final float mDividerHeight;
+
+    private int mSelectedPosition;
+    private float mSelectionOffset;
+
+    private SlidingTabLayout.TabColorizer mCustomTabColorizer;
+    private final SimpleTabColorizer mDefaultTabColorizer;
+
+    SlidingTabStrip(Context context) {
+        this(context, null);
+    }
+
+    SlidingTabStrip(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        setWillNotDraw(false);
+
+        final float density = getResources().getDisplayMetrics().density;
+
+        TypedValue outValue = new TypedValue();
+        context.getTheme().resolveAttribute(R.attr.colorForeground, outValue, true);
+        final int themeForegroundColor =  outValue.data;
+
+        mDefaultBottomBorderColor = setColorAlpha(themeForegroundColor,
+                DEFAULT_BOTTOM_BORDER_COLOR_ALPHA);
+
+        mDefaultTabColorizer = new SimpleTabColorizer();
+        mDefaultTabColorizer.setIndicatorColors(DEFAULT_SELECTED_INDICATOR_COLOR);
+        mDefaultTabColorizer.setDividerColors(setColorAlpha(themeForegroundColor,
+                DEFAULT_DIVIDER_COLOR_ALPHA));
+
+        mBottomBorderThickness = (int) (DEFAULT_BOTTOM_BORDER_THICKNESS_DIPS * density);
+        mBottomBorderPaint = new Paint();
+        mBottomBorderPaint.setColor(mDefaultBottomBorderColor);
+
+        mSelectedIndicatorThickness = (int) (SELECTED_INDICATOR_THICKNESS_DIPS * density);
+        mSelectedIndicatorPaint = new Paint();
+
+        mDividerHeight = DEFAULT_DIVIDER_HEIGHT;
+        mDividerPaint = new Paint();
+        mDividerPaint.setStrokeWidth((int) (DEFAULT_DIVIDER_THICKNESS_DIPS * density));
+    }
+
+    void setCustomTabColorizer(SlidingTabLayout.TabColorizer customTabColorizer) {
+        mCustomTabColorizer = customTabColorizer;
+        invalidate();
+    }
+
+    void setSelectedIndicatorColors(int... colors) {
+        // Make sure that the custom colorizer is removed
+        mCustomTabColorizer = null;
+        mDefaultTabColorizer.setIndicatorColors(colors);
+        invalidate();
+    }
+
+    void setDividerColors(int... colors) {
+        // Make sure that the custom colorizer is removed
+        mCustomTabColorizer = null;
+        mDefaultTabColorizer.setDividerColors(colors);
+        invalidate();
+    }
+
+    void onViewPagerPageChanged(int position, float positionOffset) {
+        mSelectedPosition = position;
+        mSelectionOffset = positionOffset;
+        invalidate();
+    }
+
+    @Override
+    protected void onDraw(Canvas canvas) {
+        final int height = getHeight();
+        final int childCount = getChildCount();
+        final int dividerHeightPx = (int) (Math.min(Math.max(0f, mDividerHeight), 1f) * height);
+        final SlidingTabLayout.TabColorizer tabColorizer = mCustomTabColorizer != null
+                ? mCustomTabColorizer
+                : mDefaultTabColorizer;
+
+        // Thick colored underline below the current selection
+        if (childCount > 0) {
+            View selectedTitle = getChildAt(mSelectedPosition);
+            int left = selectedTitle.getLeft();
+            int right = selectedTitle.getRight();
+            int color = tabColorizer.getIndicatorColor(mSelectedPosition);
+
+            if (mSelectionOffset > 0f && mSelectedPosition < (getChildCount() - 1)) {
+                int nextColor = tabColorizer.getIndicatorColor(mSelectedPosition + 1);
+                if (color != nextColor) {
+                    color = blendColors(nextColor, color, mSelectionOffset);
+                }
+
+                // Draw the selection partway between the tabs
+                View nextTitle = getChildAt(mSelectedPosition + 1);
+                left = (int) (mSelectionOffset * nextTitle.getLeft() +
+                        (1.0f - mSelectionOffset) * left);
+                right = (int) (mSelectionOffset * nextTitle.getRight() +
+                        (1.0f - mSelectionOffset) * right);
+            }
+
+            mSelectedIndicatorPaint.setColor(color);
+
+            canvas.drawRect(left, height - mSelectedIndicatorThickness, right,
+                    height, mSelectedIndicatorPaint);
+        }
+
+        // Thin underline along the entire bottom edge
+        canvas.drawRect(0, height - mBottomBorderThickness, getWidth(), height, mBottomBorderPaint);
+
+        // Vertical separators between the titles
+        int separatorTop = (height - dividerHeightPx) / 2;
+        for (int i = 0; i < childCount - 1; i++) {
+            View child = getChildAt(i);
+            mDividerPaint.setColor(tabColorizer.getDividerColor(i));
+            canvas.drawLine(child.getRight(), separatorTop, child.getRight(),
+                    separatorTop + dividerHeightPx, mDividerPaint);
+        }
+    }
+
+    /**
+     * Set the alpha value of the {@code color} to be the given {@code alpha} value.
+     */
+    private static int setColorAlpha(int color, byte alpha) {
+        return Color.argb(alpha, Color.red(color), Color.green(color), Color.blue(color));
+    }
+
+    /**
+     * Blend {@code color1} and {@code color2} using the given ratio.
+     *
+     * @param ratio of which to blend. 1.0 will return {@code color1}, 0.5 will give an even blend,
+     *              0.0 will return {@code color2}.
+     */
+    private static int blendColors(int color1, int color2, float ratio) {
+        final float inverseRation = 1f - ratio;
+        float r = (Color.red(color1) * ratio) + (Color.red(color2) * inverseRation);
+        float g = (Color.green(color1) * ratio) + (Color.green(color2) * inverseRation);
+        float b = (Color.blue(color1) * ratio) + (Color.blue(color2) * inverseRation);
+        return Color.rgb((int) r, (int) g, (int) b);
+    }
+
+    private static class SimpleTabColorizer implements SlidingTabLayout.TabColorizer {
+        private int[] mIndicatorColors;
+        private int[] mDividerColors;
+
+        @Override
+        public final int getIndicatorColor(int position) {
+            return mIndicatorColors[position % mIndicatorColors.length];
+        }
+
+        @Override
+        public final int getDividerColor(int position) {
+            return mDividerColors[position % mDividerColors.length];
+        }
+
+        void setIndicatorColors(int... colors) {
+            mIndicatorColors = colors;
+        }
+
+        void setDividerColors(int... colors) {
+            mDividerColors = colors;
+        }
+    }
+}
\ No newline at end of file
diff --git a/samples/browseable/SlidingTabsBasic/src/com.example.android.slidingtabsbasic/MainActivity.java b/samples/browseable/SlidingTabsBasic/src/com.example.android.slidingtabsbasic/MainActivity.java
new file mode 100644
index 0000000..ac405d1
--- /dev/null
+++ b/samples/browseable/SlidingTabsBasic/src/com.example.android.slidingtabsbasic/MainActivity.java
@@ -0,0 +1,110 @@
+/*
+* Copyright 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.slidingtabsbasic;
+
+import android.os.Bundle;
+import android.support.v4.app.FragmentTransaction;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.widget.ViewAnimator;
+
+import com.example.android.common.activities.SampleActivityBase;
+import com.example.android.common.logger.Log;
+import com.example.android.common.logger.LogFragment;
+import com.example.android.common.logger.LogWrapper;
+import com.example.android.common.logger.MessageOnlyLogFilter;
+
+/**
+ * A simple launcher activity containing a summary sample description, sample log and a custom
+ * {@link android.support.v4.app.Fragment} which can display a view.
+ * <p>
+ * For devices with displays with a width of 720dp or greater, the sample log is always visible,
+ * on other devices it's visibility is controlled by an item on the Action Bar.
+ */
+public class MainActivity extends SampleActivityBase {
+
+    public static final String TAG = "MainActivity";
+
+    // Whether the Log Fragment is currently shown
+    private boolean mLogShown;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_main);
+
+        FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
+        SlidingTabsBasicFragment fragment = new SlidingTabsBasicFragment();
+        transaction.replace(R.id.sample_content_fragment, fragment);
+        transaction.commit();
+    }
+
+    @Override
+    public boolean onCreateOptionsMenu(Menu menu) {
+        getMenuInflater().inflate(R.menu.main, menu);
+        return true;
+    }
+
+    @Override
+    public boolean onPrepareOptionsMenu(Menu menu) {
+        MenuItem logToggle = menu.findItem(R.id.menu_toggle_log);
+        logToggle.setVisible(findViewById(R.id.sample_output) instanceof ViewAnimator);
+        logToggle.setTitle(mLogShown ? R.string.sample_hide_log : R.string.sample_show_log);
+
+        return super.onPrepareOptionsMenu(menu);
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        switch(item.getItemId()) {
+            case R.id.menu_toggle_log:
+                mLogShown = !mLogShown;
+                ViewAnimator output = (ViewAnimator) findViewById(R.id.sample_output);
+                if (mLogShown) {
+                    output.setDisplayedChild(1);
+                } else {
+                    output.setDisplayedChild(0);
+                }
+                supportInvalidateOptionsMenu();
+                return true;
+        }
+        return super.onOptionsItemSelected(item);
+    }
+
+    /** Create a chain of targets that will receive log data */
+    @Override
+    public void initializeLogging() {
+        // Wraps Android's native log framework.
+        LogWrapper logWrapper = new LogWrapper();
+        // Using Log, front-end to the logging chain, emulates android.util.log method signatures.
+        Log.setLogNode(logWrapper);
+
+        // Filter strips out everything except the message text.
+        MessageOnlyLogFilter msgFilter = new MessageOnlyLogFilter();
+        logWrapper.setNext(msgFilter);
+
+        // On screen logging via a fragment with a TextView.
+        LogFragment logFragment = (LogFragment) getSupportFragmentManager()
+                .findFragmentById(R.id.log_fragment);
+        msgFilter.setNext(logFragment.getLogView());
+
+        Log.i(TAG, "Ready");
+    }
+}
diff --git a/samples/browseable/SlidingTabsBasic/src/com.example.android.slidingtabsbasic/SlidingTabsBasicFragment.java b/samples/browseable/SlidingTabsBasic/src/com.example.android.slidingtabsbasic/SlidingTabsBasicFragment.java
new file mode 100644
index 0000000..80f7b10
--- /dev/null
+++ b/samples/browseable/SlidingTabsBasic/src/com.example.android.slidingtabsbasic/SlidingTabsBasicFragment.java
@@ -0,0 +1,160 @@
+/*
+ * 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.slidingtabsbasic;
+
+import com.example.android.common.logger.Log;
+import com.example.android.common.view.SlidingTabLayout;
+
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.support.v4.view.PagerAdapter;
+import android.support.v4.view.ViewPager;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+/**
+ * A basic sample which shows how to use {@link com.example.android.common.view.SlidingTabLayout}
+ * to display a custom {@link ViewPager} title strip which gives continuous feedback to the user
+ * when scrolling.
+ */
+public class SlidingTabsBasicFragment extends Fragment {
+
+    static final String LOG_TAG = "SlidingTabsBasicFragment";
+
+    /**
+     * A custom {@link ViewPager} title strip which looks much like Tabs present in Android v4.0 and
+     * above, but is designed to give continuous feedback to the user when scrolling.
+     */
+    private SlidingTabLayout mSlidingTabLayout;
+
+    /**
+     * A {@link ViewPager} which will be used in conjunction with the {@link SlidingTabLayout} above.
+     */
+    private ViewPager mViewPager;
+
+    /**
+     * Inflates the {@link View} which will be displayed by this {@link Fragment}, from the app's
+     * resources.
+     */
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+            Bundle savedInstanceState) {
+        return inflater.inflate(R.layout.fragment_sample, container, false);
+    }
+
+    // BEGIN_INCLUDE (fragment_onviewcreated)
+    /**
+     * This is called after the {@link #onCreateView(LayoutInflater, ViewGroup, Bundle)} has finished.
+     * Here we can pick out the {@link View}s we need to configure from the content view.
+     *
+     * We set the {@link ViewPager}'s adapter to be an instance of {@link SamplePagerAdapter}. The
+     * {@link SlidingTabLayout} is then given the {@link ViewPager} so that it can populate itself.
+     *
+     * @param view View created in {@link #onCreateView(LayoutInflater, ViewGroup, Bundle)}
+     */
+    @Override
+    public void onViewCreated(View view, Bundle savedInstanceState) {
+        // BEGIN_INCLUDE (setup_viewpager)
+        // Get the ViewPager and set it's PagerAdapter so that it can display items
+        mViewPager = (ViewPager) view.findViewById(R.id.viewpager);
+        mViewPager.setAdapter(new SamplePagerAdapter());
+        // END_INCLUDE (setup_viewpager)
+
+        // BEGIN_INCLUDE (setup_slidingtablayout)
+        // Give the SlidingTabLayout the ViewPager, this must be done AFTER the ViewPager has had
+        // it's PagerAdapter set.
+        mSlidingTabLayout = (SlidingTabLayout) view.findViewById(R.id.sliding_tabs);
+        mSlidingTabLayout.setViewPager(mViewPager);
+        // END_INCLUDE (setup_slidingtablayout)
+    }
+    // END_INCLUDE (fragment_onviewcreated)
+
+    /**
+     * The {@link android.support.v4.view.PagerAdapter} used to display pages in this sample.
+     * The individual pages are simple and just display two lines of text. The important section of
+     * this class is the {@link #getPageTitle(int)} method which controls what is displayed in the
+     * {@link SlidingTabLayout}.
+     */
+    class SamplePagerAdapter extends PagerAdapter {
+
+        /**
+         * @return the number of pages to display
+         */
+        @Override
+        public int getCount() {
+            return 10;
+        }
+
+        /**
+         * @return true if the value returned from {@link #instantiateItem(ViewGroup, int)} is the
+         * same object as the {@link View} added to the {@link ViewPager}.
+         */
+        @Override
+        public boolean isViewFromObject(View view, Object o) {
+            return o == view;
+        }
+
+        // BEGIN_INCLUDE (pageradapter_getpagetitle)
+        /**
+         * Return the title of the item at {@code position}. This is important as what this method
+         * returns is what is displayed in the {@link SlidingTabLayout}.
+         * <p>
+         * Here we construct one using the position value, but for real application the title should
+         * refer to the item's contents.
+         */
+        @Override
+        public CharSequence getPageTitle(int position) {
+            return "Item " + (position + 1);
+        }
+        // END_INCLUDE (pageradapter_getpagetitle)
+
+        /**
+         * Instantiate the {@link View} which should be displayed at {@code position}. Here we
+         * inflate a layout from the apps resources and then change the text view to signify the position.
+         */
+        @Override
+        public Object instantiateItem(ViewGroup container, int position) {
+            // Inflate a new layout from our resources
+            View view = getActivity().getLayoutInflater().inflate(R.layout.pager_item,
+                    container, false);
+            // Add the newly created View to the ViewPager
+            container.addView(view);
+
+            // Retrieve a TextView from the inflated View, and update it's text
+            TextView title = (TextView) view.findViewById(R.id.item_title);
+            title.setText(String.valueOf(position + 1));
+
+            Log.i(LOG_TAG, "instantiateItem() [position: " + position + "]");
+
+            // Return the View
+            return view;
+        }
+
+        /**
+         * Destroy the item from the {@link ViewPager}. In our case this is simply removing the
+         * {@link View}.
+         */
+        @Override
+        public void destroyItem(ViewGroup container, int position, Object object) {
+            container.removeView((View) object);
+            Log.i(LOG_TAG, "destroyItem() [position: " + position + "]");
+        }
+
+    }
+}
diff --git a/samples/browseable/SlidingTabsColors/AndroidManifest.xml b/samples/browseable/SlidingTabsColors/AndroidManifest.xml
new file mode 100644
index 0000000..be4a43a
--- /dev/null
+++ b/samples/browseable/SlidingTabsColors/AndroidManifest.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright 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.slidingtabscolors"
+    android:versionCode="1"
+    android:versionName="1.0">
+
+    <uses-sdk android:minSdkVersion="4" android:targetSdkVersion="19" />
+
+    <application android:allowBackup="true"
+        android:label="@string/app_name"
+        android:icon="@drawable/ic_launcher"
+        android:theme="@style/AppTheme">
+
+        <activity android:name=".MainActivity"
+                  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/browseable/SlidingTabsColors/_index.jd b/samples/browseable/SlidingTabsColors/_index.jd
new file mode 100644
index 0000000..342ee15
--- /dev/null
+++ b/samples/browseable/SlidingTabsColors/_index.jd
@@ -0,0 +1,14 @@
+
+
+
+page.tags="SlidingTabsColors"
+sample.group=UI
+@jd:body
+
+<p>
+  This sample shows a more advanced example of how to use a <code><a href=
+  "{@docRoot}samples/SlidingTabsColors/src/com.example.android.common/view/SlidingTabLayout.html">
+  SlidingTabLayout</a></code> to display a custom {@link
+  android.support.v4.view.ViewPager ViewPager} title strip, with custom
+  coloring for each tab.
+</p>
\ No newline at end of file
diff --git a/samples/browseable/SlidingTabsColors/res/drawable-hdpi/ic_launcher.png b/samples/browseable/SlidingTabsColors/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..66542ee
--- /dev/null
+++ b/samples/browseable/SlidingTabsColors/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/Basic/res/drawable-hdpi/tile.9.png b/samples/browseable/SlidingTabsColors/res/drawable-hdpi/tile.9.png
similarity index 100%
copy from samples/browseable/Basic/res/drawable-hdpi/tile.9.png
copy to samples/browseable/SlidingTabsColors/res/drawable-hdpi/tile.9.png
Binary files differ
diff --git a/samples/browseable/SlidingTabsColors/res/drawable-mdpi/ic_launcher.png b/samples/browseable/SlidingTabsColors/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..56e4726
--- /dev/null
+++ b/samples/browseable/SlidingTabsColors/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/SlidingTabsColors/res/drawable-xhdpi/ic_launcher.png b/samples/browseable/SlidingTabsColors/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..ba41664
--- /dev/null
+++ b/samples/browseable/SlidingTabsColors/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/SlidingTabsColors/res/drawable-xxhdpi/ic_launcher.png b/samples/browseable/SlidingTabsColors/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..c9a51f6
--- /dev/null
+++ b/samples/browseable/SlidingTabsColors/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/browseable/SlidingTabsColors/res/layout-w720dp/activity_main.xml b/samples/browseable/SlidingTabsColors/res/layout-w720dp/activity_main.xml
new file mode 100755
index 0000000..c9a52f6
--- /dev/null
+++ b/samples/browseable/SlidingTabsColors/res/layout-w720dp/activity_main.xml
@@ -0,0 +1,73 @@
+<!--
+  Copyright 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"
+      android:orientation="horizontal"
+      android:layout_width="match_parent"
+      android:layout_height="match_parent"
+      android:id="@+id/sample_main_layout">
+
+    <LinearLayout
+          android:id="@+id/sample_output"
+          android:layout_width="0px"
+          android:layout_height="match_parent"
+          android:layout_weight="1"
+          android:orientation="vertical">
+
+        <FrameLayout
+              style="@style/Widget.SampleMessageTile"
+              android:layout_width="match_parent"
+              android:layout_height="wrap_content">
+
+            <TextView
+                  style="@style/Widget.SampleMessage"
+                  android:layout_width="match_parent"
+                  android:layout_height="wrap_content"
+                  android:paddingLeft="@dimen/margin_medium"
+                  android:paddingRight="@dimen/margin_medium"
+                  android:paddingTop="@dimen/margin_large"
+                  android:paddingBottom="@dimen/margin_large"
+                  android:text="@string/intro_message" />
+        </FrameLayout>
+
+        <View
+              android:layout_width="match_parent"
+              android:layout_height="1dp"
+              android:background="@android:color/darker_gray" />
+
+        <fragment
+              android:name="com.example.android.common.logger.LogFragment"
+              android:id="@+id/log_fragment"
+              android:layout_width="match_parent"
+              android:layout_height="0px"
+              android:layout_weight="1" />
+
+    </LinearLayout>
+
+    <View
+          android:layout_width="1dp"
+          android:layout_height="match_parent"
+          android:background="@android:color/darker_gray" />
+
+    <FrameLayout
+          android:id="@+id/sample_content_fragment"
+          android:layout_weight="2"
+          android:layout_width="0px"
+          android:layout_height="match_parent" />
+
+</LinearLayout>
+
+
diff --git a/samples/browseable/SlidingTabsColors/res/layout/activity_main.xml b/samples/browseable/SlidingTabsColors/res/layout/activity_main.xml
new file mode 100755
index 0000000..1ae4f98
--- /dev/null
+++ b/samples/browseable/SlidingTabsColors/res/layout/activity_main.xml
@@ -0,0 +1,65 @@
+<!--
+  Copyright 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"
+      android:orientation="vertical"
+      android:layout_width="match_parent"
+      android:layout_height="match_parent"
+      android:id="@+id/sample_main_layout">
+
+    <ViewAnimator
+          android:id="@+id/sample_output"
+          android:layout_width="match_parent"
+          android:layout_height="0px"
+          android:layout_weight="1">
+
+        <ScrollView
+              style="@style/Widget.SampleMessageTile"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent">
+
+            <TextView
+                  style="@style/Widget.SampleMessage"
+                  android:layout_width="match_parent"
+                  android:layout_height="wrap_content"
+                  android:paddingLeft="@dimen/horizontal_page_margin"
+                  android:paddingRight="@dimen/horizontal_page_margin"
+                  android:paddingTop="@dimen/vertical_page_margin"
+                  android:paddingBottom="@dimen/vertical_page_margin"
+                  android:text="@string/intro_message" />
+        </ScrollView>
+
+        <fragment
+              android:name="com.example.android.common.logger.LogFragment"
+              android:id="@+id/log_fragment"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent" />
+
+    </ViewAnimator>
+
+    <View
+          android:layout_width="match_parent"
+          android:layout_height="1dp"
+          android:background="@android:color/darker_gray" />
+
+    <FrameLayout
+          android:id="@+id/sample_content_fragment"
+          android:layout_weight="2"
+          android:layout_width="match_parent"
+          android:layout_height="0px" />
+
+</LinearLayout>
+
diff --git a/samples/browseable/SlidingTabsColors/res/layout/fragment_sample.xml b/samples/browseable/SlidingTabsColors/res/layout/fragment_sample.xml
new file mode 100644
index 0000000..605cba7
--- /dev/null
+++ b/samples/browseable/SlidingTabsColors/res/layout/fragment_sample.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent"
+              android:orientation="vertical">
+
+    <com.example.android.common.view.SlidingTabLayout
+          android:id="@+id/sliding_tabs"
+          android:layout_width="match_parent"
+          android:layout_height="wrap_content" />
+
+    <android.support.v4.view.ViewPager
+          android:id="@+id/viewpager"
+          android:layout_width="match_parent"
+          android:layout_height="0px"
+          android:layout_weight="1"
+          android:background="@android:color/white" />
+
+</LinearLayout>
\ No newline at end of file
diff --git a/samples/browseable/SlidingTabsColors/res/layout/pager_item.xml b/samples/browseable/SlidingTabsColors/res/layout/pager_item.xml
new file mode 100644
index 0000000..039ceb1
--- /dev/null
+++ b/samples/browseable/SlidingTabsColors/res/layout/pager_item.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent"
+              android:orientation="vertical"
+              android:gravity="center">
+
+    <TextView
+          android:id="@+id/item_title"
+          android:layout_width="wrap_content"
+          android:layout_height="wrap_content"
+          android:textAppearance="?android:attr/textAppearanceLarge" />
+
+    <TextView
+          android:id="@+id/item_indicator_color"
+          android:layout_width="wrap_content"
+          android:layout_height="wrap_content"
+          android:textAppearance="?android:attr/textAppearanceLarge" />
+
+    <TextView
+          android:id="@+id/item_divider_color"
+          android:layout_width="wrap_content"
+          android:layout_height="wrap_content"
+          android:textAppearance="?android:attr/textAppearanceLarge" />
+
+</LinearLayout>
\ No newline at end of file
diff --git a/samples/training/bitmapfun/BitmapFun/src/main/res/values/colors.xml b/samples/browseable/SlidingTabsColors/res/menu/main.xml
similarity index 60%
copy from samples/training/bitmapfun/BitmapFun/src/main/res/values/colors.xml
copy to samples/browseable/SlidingTabsColors/res/menu/main.xml
index 7e4a4fe..b49c2c5 100644
--- a/samples/training/bitmapfun/BitmapFun/src/main/res/values/colors.xml
+++ b/samples/browseable/SlidingTabsColors/res/menu/main.xml
@@ -1,23 +1,21 @@
-<?xml version="1.0" encoding="utf-8"?>
 <!--
-  Copyright (C) 2012 The Android Open Source Project
+  Copyright 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
+      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>
-
-    <color name="grid_state_pressed">#BB7dbcd3</color>
-    <color name="grid_state_focused">#777dbcd3</color>
-
-</resources>
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:id="@+id/menu_toggle_log"
+          android:showAsAction="always"
+          android:title="@string/sample_show_log" />
+</menu>
diff --git a/samples/browseable/AppRestrictions/res/values-sw600dp/dimens.xml b/samples/browseable/SlidingTabsColors/res/values-sw600dp/template-dimens.xml
similarity index 100%
copy from samples/browseable/AppRestrictions/res/values-sw600dp/dimens.xml
copy to samples/browseable/SlidingTabsColors/res/values-sw600dp/template-dimens.xml
diff --git a/samples/browseable/AppRestrictions/res/values-sw600dp/styles.xml b/samples/browseable/SlidingTabsColors/res/values-sw600dp/template-styles.xml
similarity index 100%
copy from samples/browseable/AppRestrictions/res/values-sw600dp/styles.xml
copy to samples/browseable/SlidingTabsColors/res/values-sw600dp/template-styles.xml
diff --git a/samples/browseable/repeatingAlarm/res/values/base-strings.xml b/samples/browseable/SlidingTabsColors/res/values/base-strings.xml
similarity index 77%
copy from samples/browseable/repeatingAlarm/res/values/base-strings.xml
copy to samples/browseable/SlidingTabsColors/res/values/base-strings.xml
index c11b89b..89cac2d 100644
--- a/samples/browseable/repeatingAlarm/res/values/base-strings.xml
+++ b/samples/browseable/SlidingTabsColors/res/values/base-strings.xml
@@ -18,13 +18,13 @@
 
 
 <resources>
-    <string name="app_name">repeatingAlarm</string>
+    <string name="app_name">SlidingTabsColors</string>
     <string name="intro_message">
         <![CDATA[
         
             
-                Introductory text that explains what the sample is intended to demonstrate. Edit
-                in template-params.xml.
+            A more advanced sample which shows how to use SlidingTabLayout to display a custom
+            ViewPager title strip, with custom coloring for each tab.
             
         
         ]]>
diff --git a/samples/training/bitmapfun/BitmapFun/src/main/res/values/colors.xml b/samples/browseable/SlidingTabsColors/res/values/strings.xml
old mode 100644
new mode 100755
similarity index 67%
copy from samples/training/bitmapfun/BitmapFun/src/main/res/values/colors.xml
copy to samples/browseable/SlidingTabsColors/res/values/strings.xml
index 7e4a4fe..7b9d9ec
--- a/samples/training/bitmapfun/BitmapFun/src/main/res/values/colors.xml
+++ b/samples/browseable/SlidingTabsColors/res/values/strings.xml
@@ -1,12 +1,11 @@
-<?xml version="1.0" encoding="utf-8"?>
 <!--
-  Copyright (C) 2012 The Android Open Source Project
+  Copyright 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
+      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,
@@ -14,10 +13,7 @@
   See the License for the specific language governing permissions and
   limitations under the License.
 -->
-
 <resources>
-
-    <color name="grid_state_pressed">#BB7dbcd3</color>
-    <color name="grid_state_focused">#777dbcd3</color>
-
+    <string name="sample_show_log">Show Log</string>
+    <string name="sample_hide_log">Hide Log</string>
 </resources>
diff --git a/samples/browseable/AppRestrictions/res/values/dimens.xml b/samples/browseable/SlidingTabsColors/res/values/template-dimens.xml
similarity index 100%
copy from samples/browseable/AppRestrictions/res/values/dimens.xml
copy to samples/browseable/SlidingTabsColors/res/values/template-dimens.xml
diff --git a/samples/browseable/AppRestrictions/res/values/styles.xml b/samples/browseable/SlidingTabsColors/res/values/template-styles.xml
similarity index 100%
copy from samples/browseable/AppRestrictions/res/values/styles.xml
copy to samples/browseable/SlidingTabsColors/res/values/template-styles.xml
diff --git a/samples/browseable/repeatingAlarm/src/com.example.android.common/activities/SampleActivityBase.java b/samples/browseable/SlidingTabsColors/src/com.example.android.common/activities/SampleActivityBase.java
similarity index 100%
copy from samples/browseable/repeatingAlarm/src/com.example.android.common/activities/SampleActivityBase.java
copy to samples/browseable/SlidingTabsColors/src/com.example.android.common/activities/SampleActivityBase.java
diff --git a/samples/browseable/repeatingAlarm/src/com.example.android.common/logger/Log.java b/samples/browseable/SlidingTabsColors/src/com.example.android.common/logger/Log.java
similarity index 100%
copy from samples/browseable/repeatingAlarm/src/com.example.android.common/logger/Log.java
copy to samples/browseable/SlidingTabsColors/src/com.example.android.common/logger/Log.java
diff --git a/samples/browseable/repeatingAlarm/src/com.example.android.common/logger/LogFragment.java b/samples/browseable/SlidingTabsColors/src/com.example.android.common/logger/LogFragment.java
similarity index 100%
copy from samples/browseable/repeatingAlarm/src/com.example.android.common/logger/LogFragment.java
copy to samples/browseable/SlidingTabsColors/src/com.example.android.common/logger/LogFragment.java
diff --git a/samples/browseable/repeatingAlarm/src/com.example.android.common/logger/LogNode.java b/samples/browseable/SlidingTabsColors/src/com.example.android.common/logger/LogNode.java
similarity index 100%
copy from samples/browseable/repeatingAlarm/src/com.example.android.common/logger/LogNode.java
copy to samples/browseable/SlidingTabsColors/src/com.example.android.common/logger/LogNode.java
diff --git a/samples/browseable/repeatingAlarm/src/com.example.android.common/logger/LogView.java b/samples/browseable/SlidingTabsColors/src/com.example.android.common/logger/LogView.java
similarity index 100%
copy from samples/browseable/repeatingAlarm/src/com.example.android.common/logger/LogView.java
copy to samples/browseable/SlidingTabsColors/src/com.example.android.common/logger/LogView.java
diff --git a/samples/browseable/repeatingAlarm/src/com.example.android.common/logger/LogWrapper.java b/samples/browseable/SlidingTabsColors/src/com.example.android.common/logger/LogWrapper.java
similarity index 100%
copy from samples/browseable/repeatingAlarm/src/com.example.android.common/logger/LogWrapper.java
copy to samples/browseable/SlidingTabsColors/src/com.example.android.common/logger/LogWrapper.java
diff --git a/samples/browseable/repeatingAlarm/src/com.example.android.common/logger/MessageOnlyLogFilter.java b/samples/browseable/SlidingTabsColors/src/com.example.android.common/logger/MessageOnlyLogFilter.java
similarity index 100%
copy from samples/browseable/repeatingAlarm/src/com.example.android.common/logger/MessageOnlyLogFilter.java
copy to samples/browseable/SlidingTabsColors/src/com.example.android.common/logger/MessageOnlyLogFilter.java
diff --git a/samples/browseable/SlidingTabsColors/src/com.example.android.common/view/SlidingTabLayout.java b/samples/browseable/SlidingTabsColors/src/com.example.android.common/view/SlidingTabLayout.java
new file mode 100644
index 0000000..20049e3
--- /dev/null
+++ b/samples/browseable/SlidingTabsColors/src/com.example.android.common/view/SlidingTabLayout.java
@@ -0,0 +1,314 @@
+/*
+ * 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.common.view;
+
+import android.content.Context;
+import android.graphics.Typeface;
+import android.os.Build;
+import android.support.v4.view.PagerAdapter;
+import android.support.v4.view.ViewPager;
+import android.util.AttributeSet;
+import android.util.TypedValue;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.HorizontalScrollView;
+import android.widget.TextView;
+
+/**
+ * To be used with ViewPager to provide a tab indicator component which give constant feedback as to
+ * the user's scroll progress.
+ * <p>
+ * To use the component, simply add it to your view hierarchy. Then in your
+ * {@link android.app.Activity} or {@link android.support.v4.app.Fragment} call
+ * {@link #setViewPager(ViewPager)} providing it the ViewPager this layout is being used for.
+ * <p>
+ * The colors can be customized in two ways. The first and simplest is to provide an array of colors
+ * via {@link #setSelectedIndicatorColors(int...)} and {@link #setDividerColors(int...)}. The
+ * alternative is via the {@link TabColorizer} interface which provides you complete control over
+ * which color is used for any individual position.
+ * <p>
+ * The views used as tabs can be customized by calling {@link #setCustomTabView(int, int)},
+ * providing the layout ID of your custom layout.
+ */
+public class SlidingTabLayout extends HorizontalScrollView {
+
+    /**
+     * Allows complete control over the colors drawn in the tab layout. Set with
+     * {@link #setCustomTabColorizer(TabColorizer)}.
+     */
+    public interface TabColorizer {
+
+        /**
+         * @return return the color of the indicator used when {@code position} is selected.
+         */
+        int getIndicatorColor(int position);
+
+        /**
+         * @return return the color of the divider drawn to the right of {@code position}.
+         */
+        int getDividerColor(int position);
+
+    }
+
+    private static final int TITLE_OFFSET_DIPS = 24;
+    private static final int TAB_VIEW_PADDING_DIPS = 16;
+    private static final int TAB_VIEW_TEXT_SIZE_SP = 12;
+
+    private int mTitleOffset;
+
+    private int mTabViewLayoutId;
+    private int mTabViewTextViewId;
+
+    private ViewPager mViewPager;
+    private ViewPager.OnPageChangeListener mViewPagerPageChangeListener;
+
+    private final SlidingTabStrip mTabStrip;
+
+    public SlidingTabLayout(Context context) {
+        this(context, null);
+    }
+
+    public SlidingTabLayout(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public SlidingTabLayout(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+
+        // Disable the Scroll Bar
+        setHorizontalScrollBarEnabled(false);
+        // Make sure that the Tab Strips fills this View
+        setFillViewport(true);
+
+        mTitleOffset = (int) (TITLE_OFFSET_DIPS * getResources().getDisplayMetrics().density);
+
+        mTabStrip = new SlidingTabStrip(context);
+        addView(mTabStrip, LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
+    }
+
+    /**
+     * Set the custom {@link TabColorizer} to be used.
+     *
+     * If you only require simple custmisation then you can use
+     * {@link #setSelectedIndicatorColors(int...)} and {@link #setDividerColors(int...)} to achieve
+     * similar effects.
+     */
+    public void setCustomTabColorizer(TabColorizer tabColorizer) {
+        mTabStrip.setCustomTabColorizer(tabColorizer);
+    }
+
+    /**
+     * Sets the colors to be used for indicating the selected tab. These colors are treated as a
+     * circular array. Providing one color will mean that all tabs are indicated with the same color.
+     */
+    public void setSelectedIndicatorColors(int... colors) {
+        mTabStrip.setSelectedIndicatorColors(colors);
+    }
+
+    /**
+     * Sets the colors to be used for tab dividers. These colors are treated as a circular array.
+     * Providing one color will mean that all tabs are indicated with the same color.
+     */
+    public void setDividerColors(int... colors) {
+        mTabStrip.setDividerColors(colors);
+    }
+
+    /**
+     * Set the {@link ViewPager.OnPageChangeListener}. When using {@link SlidingTabLayout} you are
+     * required to set any {@link ViewPager.OnPageChangeListener} through this method. This is so
+     * that the layout can update it's scroll position correctly.
+     *
+     * @see ViewPager#setOnPageChangeListener(ViewPager.OnPageChangeListener)
+     */
+    public void setOnPageChangeListener(ViewPager.OnPageChangeListener listener) {
+        mViewPagerPageChangeListener = listener;
+    }
+
+    /**
+     * Set the custom layout to be inflated for the tab views.
+     *
+     * @param layoutResId Layout id to be inflated
+     * @param textViewId id of the {@link TextView} in the inflated view
+     */
+    public void setCustomTabView(int layoutResId, int textViewId) {
+        mTabViewLayoutId = layoutResId;
+        mTabViewTextViewId = textViewId;
+    }
+
+    /**
+     * Sets the associated view pager. Note that the assumption here is that the pager content
+     * (number of tabs and tab titles) does not change after this call has been made.
+     */
+    public void setViewPager(ViewPager viewPager) {
+        mTabStrip.removeAllViews();
+
+        mViewPager = viewPager;
+        if (viewPager != null) {
+            viewPager.setOnPageChangeListener(new InternalViewPagerListener());
+            populateTabStrip();
+        }
+    }
+
+    /**
+     * Create a default view to be used for tabs. This is called if a custom tab view is not set via
+     * {@link #setCustomTabView(int, int)}.
+     */
+    protected TextView createDefaultTabView(Context context) {
+        TextView textView = new TextView(context);
+        textView.setGravity(Gravity.CENTER);
+        textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, TAB_VIEW_TEXT_SIZE_SP);
+        textView.setTypeface(Typeface.DEFAULT_BOLD);
+
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
+            // If we're running on Honeycomb or newer, then we can use the Theme's
+            // selectableItemBackground to ensure that the View has a pressed state
+            TypedValue outValue = new TypedValue();
+            getContext().getTheme().resolveAttribute(android.R.attr.selectableItemBackground,
+                    outValue, true);
+            textView.setBackgroundResource(outValue.resourceId);
+        }
+
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
+            // If we're running on ICS or newer, enable all-caps to match the Action Bar tab style
+            textView.setAllCaps(true);
+        }
+
+        int padding = (int) (TAB_VIEW_PADDING_DIPS * getResources().getDisplayMetrics().density);
+        textView.setPadding(padding, padding, padding, padding);
+
+        return textView;
+    }
+
+    private void populateTabStrip() {
+        final PagerAdapter adapter = mViewPager.getAdapter();
+        final View.OnClickListener tabClickListener = new TabClickListener();
+
+        for (int i = 0; i < adapter.getCount(); i++) {
+            View tabView = null;
+            TextView tabTitleView = null;
+
+            if (mTabViewLayoutId != 0) {
+                // If there is a custom tab view layout id set, try and inflate it
+                tabView = LayoutInflater.from(getContext()).inflate(mTabViewLayoutId, mTabStrip,
+                        false);
+                tabTitleView = (TextView) tabView.findViewById(mTabViewTextViewId);
+            }
+
+            if (tabView == null) {
+                tabView = createDefaultTabView(getContext());
+            }
+
+            if (tabTitleView == null && TextView.class.isInstance(tabView)) {
+                tabTitleView = (TextView) tabView;
+            }
+
+            tabTitleView.setText(adapter.getPageTitle(i));
+            tabView.setOnClickListener(tabClickListener);
+
+            mTabStrip.addView(tabView);
+        }
+    }
+
+    @Override
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+
+        if (mViewPager != null) {
+            scrollToTab(mViewPager.getCurrentItem(), 0);
+        }
+    }
+
+    private void scrollToTab(int tabIndex, int positionOffset) {
+        final int tabStripChildCount = mTabStrip.getChildCount();
+        if (tabStripChildCount == 0 || tabIndex < 0 || tabIndex >= tabStripChildCount) {
+            return;
+        }
+
+        View selectedChild = mTabStrip.getChildAt(tabIndex);
+        if (selectedChild != null) {
+            int targetScrollX = selectedChild.getLeft() + positionOffset;
+
+            if (tabIndex > 0 || positionOffset > 0) {
+                // If we're not at the first child and are mid-scroll, make sure we obey the offset
+                targetScrollX -= mTitleOffset;
+            }
+
+            scrollTo(targetScrollX, 0);
+        }
+    }
+
+    private class InternalViewPagerListener implements ViewPager.OnPageChangeListener {
+        private int mScrollState;
+
+        @Override
+        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
+            int tabStripChildCount = mTabStrip.getChildCount();
+            if ((tabStripChildCount == 0) || (position < 0) || (position >= tabStripChildCount)) {
+                return;
+            }
+
+            mTabStrip.onViewPagerPageChanged(position, positionOffset);
+
+            View selectedTitle = mTabStrip.getChildAt(position);
+            int extraOffset = (selectedTitle != null)
+                    ? (int) (positionOffset * selectedTitle.getWidth())
+                    : 0;
+            scrollToTab(position, extraOffset);
+
+            if (mViewPagerPageChangeListener != null) {
+                mViewPagerPageChangeListener.onPageScrolled(position, positionOffset,
+                        positionOffsetPixels);
+            }
+        }
+
+        @Override
+        public void onPageScrollStateChanged(int state) {
+            mScrollState = state;
+
+            if (mViewPagerPageChangeListener != null) {
+                mViewPagerPageChangeListener.onPageScrollStateChanged(state);
+            }
+        }
+
+        @Override
+        public void onPageSelected(int position) {
+            if (mScrollState == ViewPager.SCROLL_STATE_IDLE) {
+                mTabStrip.onViewPagerPageChanged(position, 0f);
+                scrollToTab(position, 0);
+            }
+
+            if (mViewPagerPageChangeListener != null) {
+                mViewPagerPageChangeListener.onPageSelected(position);
+            }
+        }
+
+    }
+
+    private class TabClickListener implements View.OnClickListener {
+        @Override
+        public void onClick(View v) {
+            for (int i = 0; i < mTabStrip.getChildCount(); i++) {
+                if (v == mTabStrip.getChildAt(i)) {
+                    mViewPager.setCurrentItem(i);
+                    return;
+                }
+            }
+        }
+    }
+
+}
diff --git a/samples/browseable/SlidingTabsColors/src/com.example.android.common/view/SlidingTabStrip.java b/samples/browseable/SlidingTabsColors/src/com.example.android.common/view/SlidingTabStrip.java
new file mode 100644
index 0000000..d5bbbae
--- /dev/null
+++ b/samples/browseable/SlidingTabsColors/src/com.example.android.common/view/SlidingTabStrip.java
@@ -0,0 +1,208 @@
+/*
+ * 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.common.view;
+
+import android.R;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.util.AttributeSet;
+import android.util.TypedValue;
+import android.view.View;
+import android.widget.LinearLayout;
+
+class SlidingTabStrip extends LinearLayout {
+
+    private static final int DEFAULT_BOTTOM_BORDER_THICKNESS_DIPS = 2;
+    private static final byte DEFAULT_BOTTOM_BORDER_COLOR_ALPHA = 0x26;
+    private static final int SELECTED_INDICATOR_THICKNESS_DIPS = 8;
+    private static final int DEFAULT_SELECTED_INDICATOR_COLOR = 0xFF33B5E5;
+
+    private static final int DEFAULT_DIVIDER_THICKNESS_DIPS = 1;
+    private static final byte DEFAULT_DIVIDER_COLOR_ALPHA = 0x20;
+    private static final float DEFAULT_DIVIDER_HEIGHT = 0.5f;
+
+    private final int mBottomBorderThickness;
+    private final Paint mBottomBorderPaint;
+
+    private final int mSelectedIndicatorThickness;
+    private final Paint mSelectedIndicatorPaint;
+
+    private final int mDefaultBottomBorderColor;
+
+    private final Paint mDividerPaint;
+    private final float mDividerHeight;
+
+    private int mSelectedPosition;
+    private float mSelectionOffset;
+
+    private SlidingTabLayout.TabColorizer mCustomTabColorizer;
+    private final SimpleTabColorizer mDefaultTabColorizer;
+
+    SlidingTabStrip(Context context) {
+        this(context, null);
+    }
+
+    SlidingTabStrip(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        setWillNotDraw(false);
+
+        final float density = getResources().getDisplayMetrics().density;
+
+        TypedValue outValue = new TypedValue();
+        context.getTheme().resolveAttribute(R.attr.colorForeground, outValue, true);
+        final int themeForegroundColor =  outValue.data;
+
+        mDefaultBottomBorderColor = setColorAlpha(themeForegroundColor,
+                DEFAULT_BOTTOM_BORDER_COLOR_ALPHA);
+
+        mDefaultTabColorizer = new SimpleTabColorizer();
+        mDefaultTabColorizer.setIndicatorColors(DEFAULT_SELECTED_INDICATOR_COLOR);
+        mDefaultTabColorizer.setDividerColors(setColorAlpha(themeForegroundColor,
+                DEFAULT_DIVIDER_COLOR_ALPHA));
+
+        mBottomBorderThickness = (int) (DEFAULT_BOTTOM_BORDER_THICKNESS_DIPS * density);
+        mBottomBorderPaint = new Paint();
+        mBottomBorderPaint.setColor(mDefaultBottomBorderColor);
+
+        mSelectedIndicatorThickness = (int) (SELECTED_INDICATOR_THICKNESS_DIPS * density);
+        mSelectedIndicatorPaint = new Paint();
+
+        mDividerHeight = DEFAULT_DIVIDER_HEIGHT;
+        mDividerPaint = new Paint();
+        mDividerPaint.setStrokeWidth((int) (DEFAULT_DIVIDER_THICKNESS_DIPS * density));
+    }
+
+    void setCustomTabColorizer(SlidingTabLayout.TabColorizer customTabColorizer) {
+        mCustomTabColorizer = customTabColorizer;
+        invalidate();
+    }
+
+    void setSelectedIndicatorColors(int... colors) {
+        // Make sure that the custom colorizer is removed
+        mCustomTabColorizer = null;
+        mDefaultTabColorizer.setIndicatorColors(colors);
+        invalidate();
+    }
+
+    void setDividerColors(int... colors) {
+        // Make sure that the custom colorizer is removed
+        mCustomTabColorizer = null;
+        mDefaultTabColorizer.setDividerColors(colors);
+        invalidate();
+    }
+
+    void onViewPagerPageChanged(int position, float positionOffset) {
+        mSelectedPosition = position;
+        mSelectionOffset = positionOffset;
+        invalidate();
+    }
+
+    @Override
+    protected void onDraw(Canvas canvas) {
+        final int height = getHeight();
+        final int childCount = getChildCount();
+        final int dividerHeightPx = (int) (Math.min(Math.max(0f, mDividerHeight), 1f) * height);
+        final SlidingTabLayout.TabColorizer tabColorizer = mCustomTabColorizer != null
+                ? mCustomTabColorizer
+                : mDefaultTabColorizer;
+
+        // Thick colored underline below the current selection
+        if (childCount > 0) {
+            View selectedTitle = getChildAt(mSelectedPosition);
+            int left = selectedTitle.getLeft();
+            int right = selectedTitle.getRight();
+            int color = tabColorizer.getIndicatorColor(mSelectedPosition);
+
+            if (mSelectionOffset > 0f && mSelectedPosition < (getChildCount() - 1)) {
+                int nextColor = tabColorizer.getIndicatorColor(mSelectedPosition + 1);
+                if (color != nextColor) {
+                    color = blendColors(nextColor, color, mSelectionOffset);
+                }
+
+                // Draw the selection partway between the tabs
+                View nextTitle = getChildAt(mSelectedPosition + 1);
+                left = (int) (mSelectionOffset * nextTitle.getLeft() +
+                        (1.0f - mSelectionOffset) * left);
+                right = (int) (mSelectionOffset * nextTitle.getRight() +
+                        (1.0f - mSelectionOffset) * right);
+            }
+
+            mSelectedIndicatorPaint.setColor(color);
+
+            canvas.drawRect(left, height - mSelectedIndicatorThickness, right,
+                    height, mSelectedIndicatorPaint);
+        }
+
+        // Thin underline along the entire bottom edge
+        canvas.drawRect(0, height - mBottomBorderThickness, getWidth(), height, mBottomBorderPaint);
+
+        // Vertical separators between the titles
+        int separatorTop = (height - dividerHeightPx) / 2;
+        for (int i = 0; i < childCount - 1; i++) {
+            View child = getChildAt(i);
+            mDividerPaint.setColor(tabColorizer.getDividerColor(i));
+            canvas.drawLine(child.getRight(), separatorTop, child.getRight(),
+                    separatorTop + dividerHeightPx, mDividerPaint);
+        }
+    }
+
+    /**
+     * Set the alpha value of the {@code color} to be the given {@code alpha} value.
+     */
+    private static int setColorAlpha(int color, byte alpha) {
+        return Color.argb(alpha, Color.red(color), Color.green(color), Color.blue(color));
+    }
+
+    /**
+     * Blend {@code color1} and {@code color2} using the given ratio.
+     *
+     * @param ratio of which to blend. 1.0 will return {@code color1}, 0.5 will give an even blend,
+     *              0.0 will return {@code color2}.
+     */
+    private static int blendColors(int color1, int color2, float ratio) {
+        final float inverseRation = 1f - ratio;
+        float r = (Color.red(color1) * ratio) + (Color.red(color2) * inverseRation);
+        float g = (Color.green(color1) * ratio) + (Color.green(color2) * inverseRation);
+        float b = (Color.blue(color1) * ratio) + (Color.blue(color2) * inverseRation);
+        return Color.rgb((int) r, (int) g, (int) b);
+    }
+
+    private static class SimpleTabColorizer implements SlidingTabLayout.TabColorizer {
+        private int[] mIndicatorColors;
+        private int[] mDividerColors;
+
+        @Override
+        public final int getIndicatorColor(int position) {
+            return mIndicatorColors[position % mIndicatorColors.length];
+        }
+
+        @Override
+        public final int getDividerColor(int position) {
+            return mDividerColors[position % mDividerColors.length];
+        }
+
+        void setIndicatorColors(int... colors) {
+            mIndicatorColors = colors;
+        }
+
+        void setDividerColors(int... colors) {
+            mDividerColors = colors;
+        }
+    }
+}
\ No newline at end of file
diff --git a/samples/browseable/SlidingTabsColors/src/com.example.android.slidingtabscolors/ContentFragment.java b/samples/browseable/SlidingTabsColors/src/com.example.android.slidingtabscolors/ContentFragment.java
new file mode 100644
index 0000000..4715fd7
--- /dev/null
+++ b/samples/browseable/SlidingTabsColors/src/com.example.android.slidingtabscolors/ContentFragment.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright 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.slidingtabscolors;
+
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+/**
+ * Simple Fragment used to display some meaningful content for each page in the sample's
+ * {@link android.support.v4.view.ViewPager}.
+ */
+public class ContentFragment extends Fragment {
+
+    private static final String KEY_TITLE = "title";
+    private static final String KEY_INDICATOR_COLOR = "indicator_color";
+    private static final String KEY_DIVIDER_COLOR = "divider_color";
+
+    /**
+     * @return a new instance of {@link ContentFragment}, adding the parameters into a bundle and
+     * setting them as arguments.
+     */
+    public static ContentFragment newInstance(CharSequence title, int indicatorColor,
+            int dividerColor) {
+        Bundle bundle = new Bundle();
+        bundle.putCharSequence(KEY_TITLE, title);
+        bundle.putInt(KEY_INDICATOR_COLOR, indicatorColor);
+        bundle.putInt(KEY_DIVIDER_COLOR, dividerColor);
+
+        ContentFragment fragment = new ContentFragment();
+        fragment.setArguments(bundle);
+
+        return fragment;
+    }
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+            Bundle savedInstanceState) {
+        return inflater.inflate(R.layout.pager_item, container, false);
+    }
+
+    @Override
+    public void onViewCreated(View view, Bundle savedInstanceState) {
+        super.onViewCreated(view, savedInstanceState);
+
+        Bundle args = getArguments();
+
+        if (args != null) {
+            TextView title = (TextView) view.findViewById(R.id.item_title);
+            title.setText("Title: " + args.getCharSequence(KEY_TITLE));
+
+            int indicatorColor = args.getInt(KEY_INDICATOR_COLOR);
+            TextView indicatorColorView = (TextView) view.findViewById(R.id.item_indicator_color);
+            indicatorColorView.setText("Indicator: #" + Integer.toHexString(indicatorColor));
+            indicatorColorView.setTextColor(indicatorColor);
+
+            int dividerColor = args.getInt(KEY_DIVIDER_COLOR);
+            TextView dividerColorView = (TextView) view.findViewById(R.id.item_divider_color);
+            dividerColorView.setText("Divider: #" + Integer.toHexString(dividerColor));
+            dividerColorView.setTextColor(dividerColor);
+        }
+    }
+}
diff --git a/samples/browseable/SlidingTabsColors/src/com.example.android.slidingtabscolors/MainActivity.java b/samples/browseable/SlidingTabsColors/src/com.example.android.slidingtabscolors/MainActivity.java
new file mode 100644
index 0000000..d3d7567
--- /dev/null
+++ b/samples/browseable/SlidingTabsColors/src/com.example.android.slidingtabscolors/MainActivity.java
@@ -0,0 +1,110 @@
+/*
+* Copyright 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.slidingtabscolors;
+
+import android.os.Bundle;
+import android.support.v4.app.FragmentTransaction;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.widget.ViewAnimator;
+
+import com.example.android.common.activities.SampleActivityBase;
+import com.example.android.common.logger.Log;
+import com.example.android.common.logger.LogFragment;
+import com.example.android.common.logger.LogWrapper;
+import com.example.android.common.logger.MessageOnlyLogFilter;
+
+/**
+ * A simple launcher activity containing a summary sample description, sample log and a custom
+ * {@link android.support.v4.app.Fragment} which can display a view.
+ * <p>
+ * For devices with displays with a width of 720dp or greater, the sample log is always visible,
+ * on other devices it's visibility is controlled by an item on the Action Bar.
+ */
+public class MainActivity extends SampleActivityBase {
+
+    public static final String TAG = "MainActivity";
+
+    // Whether the Log Fragment is currently shown
+    private boolean mLogShown;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_main);
+
+        FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
+        SlidingTabsColorsFragment fragment = new SlidingTabsColorsFragment();
+        transaction.replace(R.id.sample_content_fragment, fragment);
+        transaction.commit();
+    }
+
+    @Override
+    public boolean onCreateOptionsMenu(Menu menu) {
+        getMenuInflater().inflate(R.menu.main, menu);
+        return true;
+    }
+
+    @Override
+    public boolean onPrepareOptionsMenu(Menu menu) {
+        MenuItem logToggle = menu.findItem(R.id.menu_toggle_log);
+        logToggle.setVisible(findViewById(R.id.sample_output) instanceof ViewAnimator);
+        logToggle.setTitle(mLogShown ? R.string.sample_hide_log : R.string.sample_show_log);
+
+        return super.onPrepareOptionsMenu(menu);
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        switch(item.getItemId()) {
+            case R.id.menu_toggle_log:
+                mLogShown = !mLogShown;
+                ViewAnimator output = (ViewAnimator) findViewById(R.id.sample_output);
+                if (mLogShown) {
+                    output.setDisplayedChild(1);
+                } else {
+                    output.setDisplayedChild(0);
+                }
+                supportInvalidateOptionsMenu();
+                return true;
+        }
+        return super.onOptionsItemSelected(item);
+    }
+
+    /** Create a chain of targets that will receive log data */
+    @Override
+    public void initializeLogging() {
+        // Wraps Android's native log framework.
+        LogWrapper logWrapper = new LogWrapper();
+        // Using Log, front-end to the logging chain, emulates android.util.log method signatures.
+        Log.setLogNode(logWrapper);
+
+        // Filter strips out everything except the message text.
+        MessageOnlyLogFilter msgFilter = new MessageOnlyLogFilter();
+        logWrapper.setNext(msgFilter);
+
+        // On screen logging via a fragment with a TextView.
+        LogFragment logFragment = (LogFragment) getSupportFragmentManager()
+                .findFragmentById(R.id.log_fragment);
+        msgFilter.setNext(logFragment.getLogView());
+
+        Log.i(TAG, "Ready");
+    }
+}
diff --git a/samples/browseable/SlidingTabsColors/src/com.example.android.slidingtabscolors/SlidingTabsColorsFragment.java b/samples/browseable/SlidingTabsColors/src/com.example.android.slidingtabscolors/SlidingTabsColorsFragment.java
new file mode 100644
index 0000000..1e5c3e3
--- /dev/null
+++ b/samples/browseable/SlidingTabsColors/src/com.example.android.slidingtabscolors/SlidingTabsColorsFragment.java
@@ -0,0 +1,239 @@
+/*
+ * Copyright 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.slidingtabscolors;
+
+import com.example.android.common.view.SlidingTabLayout;
+
+import android.graphics.Color;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.support.v4.app.FragmentManager;
+import android.support.v4.app.FragmentPagerAdapter;
+import android.support.v4.view.ViewPager;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A basic sample which shows how to use {@link com.example.android.common.view.SlidingTabLayout}
+ * to display a custom {@link ViewPager} title strip which gives continuous feedback to the user
+ * when scrolling.
+ */
+public class SlidingTabsColorsFragment extends Fragment {
+
+    /**
+     * This class represents a tab to be displayed by {@link ViewPager} and it's associated
+     * {@link SlidingTabLayout}.
+     */
+    static class SamplePagerItem {
+        private final CharSequence mTitle;
+        private final int mIndicatorColor;
+        private final int mDividerColor;
+
+        SamplePagerItem(CharSequence title, int indicatorColor, int dividerColor) {
+            mTitle = title;
+            mIndicatorColor = indicatorColor;
+            mDividerColor = dividerColor;
+        }
+
+        /**
+         * @return A new {@link Fragment} to be displayed by a {@link ViewPager}
+         */
+        Fragment createFragment() {
+            return ContentFragment.newInstance(mTitle, mIndicatorColor, mDividerColor);
+        }
+
+        /**
+         * @return the title which represents this tab. In this sample this is used directly by
+         * {@link android.support.v4.view.PagerAdapter#getPageTitle(int)}
+         */
+        CharSequence getTitle() {
+            return mTitle;
+        }
+
+        /**
+         * @return the color to be used for indicator on the {@link SlidingTabLayout}
+         */
+        int getIndicatorColor() {
+            return mIndicatorColor;
+        }
+
+        /**
+         * @return the color to be used for right divider on the {@link SlidingTabLayout}
+         */
+        int getDividerColor() {
+            return mDividerColor;
+        }
+    }
+
+    static final String LOG_TAG = "SlidingTabsColorsFragment";
+
+    /**
+     * A custom {@link ViewPager} title strip which looks much like Tabs present in Android v4.0 and
+     * above, but is designed to give continuous feedback to the user when scrolling.
+     */
+    private SlidingTabLayout mSlidingTabLayout;
+
+    /**
+     * A {@link ViewPager} which will be used in conjunction with the {@link SlidingTabLayout} above.
+     */
+    private ViewPager mViewPager;
+
+    /**
+     * List of {@link SamplePagerItem} which represent this sample's tabs.
+     */
+    private List<SamplePagerItem> mTabs = new ArrayList<SamplePagerItem>();
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        // BEGIN_INCLUDE (populate_tabs)
+        /**
+         * Populate our tab list with tabs. Each item contains a title, indicator color and divider
+         * color, which are used by {@link SlidingTabLayout}.
+         */
+        mTabs.add(new SamplePagerItem(
+                getString(R.string.tab_stream), // Title
+                Color.BLUE, // Indicator color
+                Color.GRAY // Divider color
+        ));
+
+        mTabs.add(new SamplePagerItem(
+                getString(R.string.tab_messages), // Title
+                Color.RED, // Indicator color
+                Color.GRAY // Divider color
+        ));
+
+        mTabs.add(new SamplePagerItem(
+                getString(R.string.tab_photos), // Title
+                Color.YELLOW, // Indicator color
+                Color.GRAY // Divider color
+        ));
+
+        mTabs.add(new SamplePagerItem(
+                getString(R.string.tab_notifications), // Title
+                Color.GREEN, // Indicator color
+                Color.GRAY // Divider color
+        ));
+        // END_INCLUDE (populate_tabs)
+    }
+
+    /**
+     * Inflates the {@link View} which will be displayed by this {@link Fragment}, from the app's
+     * resources.
+     */
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+            Bundle savedInstanceState) {
+        return inflater.inflate(R.layout.fragment_sample, container, false);
+    }
+
+    // BEGIN_INCLUDE (fragment_onviewcreated)
+    /**
+     * This is called after the {@link #onCreateView(LayoutInflater, ViewGroup, Bundle)} has finished.
+     * Here we can pick out the {@link View}s we need to configure from the content view.
+     *
+     * We set the {@link ViewPager}'s adapter to be an instance of
+     * {@link SampleFragmentPagerAdapter}. The {@link SlidingTabLayout} is then given the
+     * {@link ViewPager} so that it can populate itself.
+     *
+     * @param view View created in {@link #onCreateView(LayoutInflater, ViewGroup, Bundle)}
+     */
+    @Override
+    public void onViewCreated(View view, Bundle savedInstanceState) {
+        // BEGIN_INCLUDE (setup_viewpager)
+        // Get the ViewPager and set it's PagerAdapter so that it can display items
+        mViewPager = (ViewPager) view.findViewById(R.id.viewpager);
+        mViewPager.setAdapter(new SampleFragmentPagerAdapter(getChildFragmentManager()));
+        // END_INCLUDE (setup_viewpager)
+
+        // BEGIN_INCLUDE (setup_slidingtablayout)
+        // Give the SlidingTabLayout the ViewPager, this must be done AFTER the ViewPager has had
+        // it's PagerAdapter set.
+        mSlidingTabLayout = (SlidingTabLayout) view.findViewById(R.id.sliding_tabs);
+        mSlidingTabLayout.setViewPager(mViewPager);
+
+        // BEGIN_INCLUDE (tab_colorizer)
+        // Set a TabColorizer to customize the indicator and divider colors. Here we just retrieve
+        // the tab at the position, and return it's set color
+        mSlidingTabLayout.setCustomTabColorizer(new SlidingTabLayout.TabColorizer() {
+
+            @Override
+            public int getIndicatorColor(int position) {
+                return mTabs.get(position).getIndicatorColor();
+            }
+
+            @Override
+            public int getDividerColor(int position) {
+                return mTabs.get(position).getDividerColor();
+            }
+
+        });
+        // END_INCLUDE (tab_colorizer)
+        // END_INCLUDE (setup_slidingtablayout)
+    }
+    // END_INCLUDE (fragment_onviewcreated)
+
+    /**
+     * The {@link FragmentPagerAdapter} used to display pages in this sample. The individual pages
+     * are instances of {@link ContentFragment} which just display three lines of text. Each page is
+     * created by the relevant {@link SamplePagerItem} for the requested position.
+     * <p>
+     * The important section of this class is the {@link #getPageTitle(int)} method which controls
+     * what is displayed in the {@link SlidingTabLayout}.
+     */
+    class SampleFragmentPagerAdapter extends FragmentPagerAdapter {
+
+        SampleFragmentPagerAdapter(FragmentManager fm) {
+            super(fm);
+        }
+
+        /**
+         * Return the {@link android.support.v4.app.Fragment} to be displayed at {@code position}.
+         * <p>
+         * Here we return the value returned from {@link SamplePagerItem#createFragment()}.
+         */
+        @Override
+        public Fragment getItem(int i) {
+            return mTabs.get(i).createFragment();
+        }
+
+        @Override
+        public int getCount() {
+            return mTabs.size();
+        }
+
+        // BEGIN_INCLUDE (pageradapter_getpagetitle)
+        /**
+         * Return the title of the item at {@code position}. This is important as what this method
+         * returns is what is displayed in the {@link SlidingTabLayout}.
+         * <p>
+         * Here we return the value returned from {@link SamplePagerItem#getTitle()}.
+         */
+        @Override
+        public CharSequence getPageTitle(int position) {
+            return mTabs.get(position).getTitle();
+        }
+        // END_INCLUDE (pageradapter_getpagetitle)
+
+    }
+
+}
\ No newline at end of file
diff --git a/samples/browseable/StorageClient/res/values-sw600dp/dimens.xml b/samples/browseable/StorageClient/res/values-sw600dp/template-dimens.xml
similarity index 100%
rename from samples/browseable/StorageClient/res/values-sw600dp/dimens.xml
rename to samples/browseable/StorageClient/res/values-sw600dp/template-dimens.xml
diff --git a/samples/browseable/StorageClient/res/values-sw600dp/styles.xml b/samples/browseable/StorageClient/res/values-sw600dp/template-styles.xml
similarity index 100%
rename from samples/browseable/StorageClient/res/values-sw600dp/styles.xml
rename to samples/browseable/StorageClient/res/values-sw600dp/template-styles.xml
diff --git a/samples/browseable/StorageClient/res/values/dimens.xml b/samples/browseable/StorageClient/res/values/template-dimens.xml
similarity index 100%
rename from samples/browseable/StorageClient/res/values/dimens.xml
rename to samples/browseable/StorageClient/res/values/template-dimens.xml
diff --git a/samples/browseable/StorageClient/res/values/styles.xml b/samples/browseable/StorageClient/res/values/template-styles.xml
similarity index 100%
rename from samples/browseable/StorageClient/res/values/styles.xml
rename to samples/browseable/StorageClient/res/values/template-styles.xml
diff --git a/samples/browseable/TextLinkify/res/values-sw600dp/dimens.xml b/samples/browseable/TextLinkify/res/values-sw600dp/template-dimens.xml
similarity index 100%
rename from samples/browseable/TextLinkify/res/values-sw600dp/dimens.xml
rename to samples/browseable/TextLinkify/res/values-sw600dp/template-dimens.xml
diff --git a/samples/browseable/TextLinkify/res/values-sw600dp/styles.xml b/samples/browseable/TextLinkify/res/values-sw600dp/template-styles.xml
similarity index 100%
rename from samples/browseable/TextLinkify/res/values-sw600dp/styles.xml
rename to samples/browseable/TextLinkify/res/values-sw600dp/template-styles.xml
diff --git a/samples/browseable/TextLinkify/res/values/dimens.xml b/samples/browseable/TextLinkify/res/values/dimens.xml
index 39e710b..3b1975a 100644
--- a/samples/browseable/TextLinkify/res/values/dimens.xml
+++ b/samples/browseable/TextLinkify/res/values/dimens.xml
@@ -5,28 +5,19 @@
   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
+        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>
 
-    <!-- Define standard dimensions to comply with Holo-style grids and rhythm. -->
-
-    <dimen name="margin_tiny">4dp</dimen>
-    <dimen name="margin_small">8dp</dimen>
-    <dimen name="margin_medium">16dp</dimen>
-    <dimen name="margin_large">32dp</dimen>
-    <dimen name="margin_huge">64dp</dimen>
-
-    <!-- Semantic definitions -->
-
-    <dimen name="horizontal_page_margin">@dimen/margin_medium</dimen>
-    <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+    <!-- Default screen margins, per the Android Design guidelines. -->
+    <dimen name="activity_horizontal_margin">16dp</dimen>
+    <dimen name="activity_vertical_margin">16dp</dimen>
 
 </resources>
diff --git a/samples/browseable/TextLinkify/res/values/styles.xml b/samples/browseable/TextLinkify/res/values/styles.xml
index 404623e..29c4230 100644
--- a/samples/browseable/TextLinkify/res/values/styles.xml
+++ b/samples/browseable/TextLinkify/res/values/styles.xml
@@ -5,38 +5,18 @@
   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
+        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>
-
-    <!-- Activity themes -->
-
-    <style name="Theme.Base" parent="android:Theme.Holo.Light" />
-
-    <style name="Theme.Sample" parent="Theme.Base" />
-
-    <style name="AppTheme" parent="Theme.Sample" />
-    <!-- Widget styling -->
-
-    <style name="Widget" />
-
-    <style name="Widget.SampleMessage">
-        <item name="android:textAppearance">?android:textAppearanceMedium</item>
-        <item name="android:lineSpacingMultiplier">1.1</item>
+<resources xmlns:android="http://schemas.android.com/apk/res/android">
+    <style name="LinkText">
+        <item name="android:paddingTop">9dp</item>
+        <item name="android:paddingBottom">9dp</item>
     </style>
-
-    <style name="Widget.SampleMessageTile">
-        <item name="android:background">@drawable/tile</item>
-        <item name="android:shadowColor">#7F000000</item>
-        <item name="android:shadowDy">-3.5</item>
-        <item name="android:shadowRadius">2</item>
-    </style>
-
 </resources>
diff --git a/samples/browseable/Basic/res/values/dimens.xml b/samples/browseable/TextLinkify/res/values/template-dimens.xml
similarity index 100%
copy from samples/browseable/Basic/res/values/dimens.xml
copy to samples/browseable/TextLinkify/res/values/template-dimens.xml
diff --git a/samples/browseable/TextSwitcher/res/values/styles.xml b/samples/browseable/TextLinkify/res/values/template-styles.xml
similarity index 100%
copy from samples/browseable/TextSwitcher/res/values/styles.xml
copy to samples/browseable/TextLinkify/res/values/template-styles.xml
diff --git a/samples/browseable/TextSwitcher/res/values-sw600dp/dimens.xml b/samples/browseable/TextSwitcher/res/values-sw600dp/dimens.xml
index 22074a2..686fe89 100644
--- a/samples/browseable/TextSwitcher/res/values-sw600dp/dimens.xml
+++ b/samples/browseable/TextSwitcher/res/values-sw600dp/dimens.xml
@@ -5,20 +5,20 @@
   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
+        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>
 
-    <!-- Semantic definitions -->
-
-    <dimen name="horizontal_page_margin">@dimen/margin_huge</dimen>
-    <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+    <!--
+         Customize dimensions originally defined in res/values/dimens.xml (such as
+         screen margins) for sw600dp devices (e.g. 7" tablets) here.
+    -->
 
 </resources>
diff --git a/samples/browseable/TextLinkify/res/values-sw600dp/dimens.xml b/samples/browseable/TextSwitcher/res/values-sw600dp/template-dimens.xml
similarity index 100%
copy from samples/browseable/TextLinkify/res/values-sw600dp/dimens.xml
copy to samples/browseable/TextSwitcher/res/values-sw600dp/template-dimens.xml
diff --git a/samples/browseable/TextSwitcher/res/values-sw600dp/styles.xml b/samples/browseable/TextSwitcher/res/values-sw600dp/template-styles.xml
similarity index 100%
rename from samples/browseable/TextSwitcher/res/values-sw600dp/styles.xml
rename to samples/browseable/TextSwitcher/res/values-sw600dp/template-styles.xml
diff --git a/samples/browseable/TextSwitcher/res/values/dimens.xml b/samples/browseable/TextSwitcher/res/values/dimens.xml
index 39e710b..3b1975a 100644
--- a/samples/browseable/TextSwitcher/res/values/dimens.xml
+++ b/samples/browseable/TextSwitcher/res/values/dimens.xml
@@ -5,28 +5,19 @@
   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
+        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>
 
-    <!-- Define standard dimensions to comply with Holo-style grids and rhythm. -->
-
-    <dimen name="margin_tiny">4dp</dimen>
-    <dimen name="margin_small">8dp</dimen>
-    <dimen name="margin_medium">16dp</dimen>
-    <dimen name="margin_large">32dp</dimen>
-    <dimen name="margin_huge">64dp</dimen>
-
-    <!-- Semantic definitions -->
-
-    <dimen name="horizontal_page_margin">@dimen/margin_medium</dimen>
-    <dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
+    <!-- Default screen margins, per the Android Design guidelines. -->
+    <dimen name="activity_horizontal_margin">16dp</dimen>
+    <dimen name="activity_vertical_margin">16dp</dimen>
 
 </resources>
diff --git a/samples/browseable/DoneBar/res/values/dimens.xml b/samples/browseable/TextSwitcher/res/values/template-dimens.xml
similarity index 100%
copy from samples/browseable/DoneBar/res/values/dimens.xml
copy to samples/browseable/TextSwitcher/res/values/template-dimens.xml
diff --git a/samples/browseable/TextSwitcher/res/values/styles.xml b/samples/browseable/TextSwitcher/res/values/template-styles.xml
similarity index 100%
rename from samples/browseable/TextSwitcher/res/values/styles.xml
rename to samples/browseable/TextSwitcher/res/values/template-styles.xml
diff --git a/samples/samples_source.prop_template b/samples/samples_source.prop_template
index d3cdfd5..315be08 100644
--- a/samples/samples_source.prop_template
+++ b/samples/samples_source.prop_template
@@ -1,4 +1,4 @@
 Pkg.UserSrc=false
-Pkg.Revision=1
+Pkg.Revision=4
 AndroidVersion.ApiLevel=${PLATFORM_SDK_VERSION}
 AndroidVersion.CodeName=${PLATFORM_VERSION_CODENAME}
diff --git a/samples/training/bitmapfun/BitmapFun/build.gradle b/samples/training/bitmapfun/BitmapFun/build.gradle
deleted file mode 100644
index c978231..0000000
--- a/samples/training/bitmapfun/BitmapFun/build.gradle
+++ /dev/null
@@ -1,27 +0,0 @@
-buildscript {
-    repositories {
-        mavenCentral()
-    }
-    dependencies {
-        classpath 'com.android.tools.build:gradle:0.6.+'
-    }
-}
-apply plugin: 'android'
-
-repositories {
-    mavenCentral()
-}
-
-android {
-    compileSdkVersion 19
-    buildToolsVersion "19.0.0"
-
-    defaultConfig {
-        minSdkVersion 7
-        targetSdkVersion 19
-    }
-}
-
-dependencies {
-    compile 'com.android.support:support-v4:19.0.+'
-}
diff --git a/samples/training/bitmapfun/BitmapFun/src/main/AndroidManifest.xml b/samples/training/bitmapfun/BitmapFun/src/main/AndroidManifest.xml
deleted file mode 100644
index 9ca5cf5..0000000
--- a/samples/training/bitmapfun/BitmapFun/src/main/AndroidManifest.xml
+++ /dev/null
@@ -1,55 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  Copyright (C) 2012 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.bitmapfun"
-    android:versionCode="1"
-    android:versionName="1.0" >
-
-    <uses-sdk
-        android:minSdkVersion="7"
-        android:targetSdkVersion="19" />
-
-    <uses-permission android:name="android.permission.INTERNET" />
-    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
-    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
-
-    <application
-        android:description="@string/app_description"
-        android:hardwareAccelerated="true"
-        android:icon="@drawable/ic_launcher"
-        android:label="@string/app_name"
-        android:allowBackup="false">
-        <activity
-            android:name=".ui.ImageDetailActivity"
-            android:label="@string/app_name"
-            android:parentActivityName=".ui.ImageGridActivity"
-            android:theme="@style/AppTheme.FullScreen" >
-            <meta-data android:name="android.support.PARENT_ACTIVITY"
-                       android:value=".ui.ImageGridActivity" />
-        </activity>
-        <activity
-            android:name=".ui.ImageGridActivity"
-            android:label="@string/app_name"
-            android:theme="@style/AppTheme" >
-            <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/training/bitmapfun/BitmapFun/src/main/res/drawable-ldpi/ic_launcher.png b/samples/training/bitmapfun/BitmapFun/src/main/res/drawable-ldpi/ic_launcher.png
deleted file mode 100644
index 9923872..0000000
--- a/samples/training/bitmapfun/BitmapFun/src/main/res/drawable-ldpi/ic_launcher.png
+++ /dev/null
Binary files differ
diff --git a/samples/training/bitmapfun/BitmapFun/src/main/res/values/strings.xml b/samples/training/bitmapfun/BitmapFun/src/main/res/values/strings.xml
deleted file mode 100644
index 8108c23..0000000
--- a/samples/training/bitmapfun/BitmapFun/src/main/res/values/strings.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  Copyright (C) 2012 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">BitmapFun</string>
-    <string name="app_description">This is a sample application for the Android Training class
-        &quot;Displaying Bitmaps Efficiently&quot;
-        (http://developer.android.com/training/displaying-bitmaps/display-bitmap.html). It is not
-        designed to be a full reference application but to demonstrate the concepts discussed in
-        training course.</string>
-    <string name="clear_cache_menu">Clear Caches</string>
-    <string name="clear_cache_complete_toast">Caches have been cleared</string>
-    <string name="imageview_description">Image Thumbnail</string>
-    <string name="no_network_connection_toast">No network connection found</string>
-
-</resources>
\ No newline at end of file
diff --git a/samples/training/bitmapfun/README b/samples/training/bitmapfun/README
deleted file mode 100644
index a0a192f..0000000
--- a/samples/training/bitmapfun/README
+++ /dev/null
@@ -1,8 +0,0 @@
-This is an Android Studio project:
-http://developer.android.com/sdk/installing/studio.html
-
-First copy local.properties.sample to local.properties and set your SDK path.
-
-Then import the project into Android Studio:
-File -> Import Project -> Choose Directory -> Import from external model ->
-    Gradle -> Use default gradle wrapper -> Finish
diff --git a/samples/training/bitmapfun/build.gradle b/samples/training/bitmapfun/build.gradle
deleted file mode 100644
index 495c503..0000000
--- a/samples/training/bitmapfun/build.gradle
+++ /dev/null
@@ -1 +0,0 @@
-// Top-level build file where you can add configuration options common to all sub-projects/modules.
diff --git a/samples/training/bitmapfun/local.properties.sample b/samples/training/bitmapfun/local.properties.sample
deleted file mode 100644
index 37317f4..0000000
--- a/samples/training/bitmapfun/local.properties.sample
+++ /dev/null
@@ -1,7 +0,0 @@
-# This file should be copied to local.properties and path set to point
-# to your Android SDK.
-
-# Location of the SDK. This is only used by Gradle.
-# For customization when using a Version Control System, please read the
-# header note.
-sdk.dir=/usr/local/lib/android-sdk
\ No newline at end of file
diff --git a/samples/training/bitmapfun/settings.gradle b/samples/training/bitmapfun/settings.gradle
deleted file mode 100644
index 9f12781..0000000
--- a/samples/training/bitmapfun/settings.gradle
+++ /dev/null
@@ -1 +0,0 @@
-include ':BitmapFun'
diff --git a/scripts/app_engine_server/app.yaml.production b/scripts/app_engine_server/app.yaml.production
new file mode 100644
index 0000000..61bd51a
--- /dev/null
+++ b/scripts/app_engine_server/app.yaml.production
@@ -0,0 +1,16 @@
+application: androiddevdocs
+version: 1
+runtime: python
+api_version: 1
+
+handlers:
+- url: /gae_shell/static
+  static_dir: gae_shell/static
+  expiration: 1d
+
+- url: /gae_shell/.*
+  script: /gae_shell/shell.py
+  login: admin
+
+- url: .*
+  script: main.py
diff --git a/scripts/app_engine_server/redirects.yaml b/scripts/app_engine_server/redirects.yaml
index 106b64e..b7a90a5 100644
--- a/scripts/app_engine_server/redirects.yaml
+++ b/scripts/app_engine_server/redirects.yaml
@@ -303,6 +303,10 @@
 - src: /guide/appendix/install-location.html
   dst: /guide/topics/data/install-location.html
   type: permanent
+
+- src: /guide/appendix/g-app-intents.html
+  dst: /guide/components/intents-common.html
+  type: permanent
   comment: Redirect to new location
 
 # new one
@@ -547,7 +551,11 @@
   type: permanent
 
 - src: /resources/samples/.*
-  dst: /tools/samples/index.html
+  dst: /samples/index.html
+  type: permanent
+
+- src: /tools/samples/index.html
+  dst: /samples/index.html
   type: permanent
   comment: Redirect to new location
 
@@ -561,12 +569,6 @@
   type: permanent
   comment: Redirect to new location
 
-- src: /guide/index.html
-  dst: /guide/components/index.html
-  type: permanent
-  comment: Redirect to new location
-
-
 
 # ------------------- TRAINING -------------------
 
diff --git a/sdk/api-versions.xml b/sdk/api-versions.xml
index de035e8..3855e9d 100644
--- a/sdk/api-versions.xml
+++ b/sdk/api-versions.xml
@@ -12869,6 +12869,7 @@
 		<field name="EFFECT_TYPE_BASS_BOOST" since="18" />
 		<field name="EFFECT_TYPE_ENV_REVERB" since="18" />
 		<field name="EFFECT_TYPE_EQUALIZER" since="18" />
+		<field name="EFFECT_TYPE_LOUDNESS_ENHANCER" since="19" />
 		<field name="EFFECT_TYPE_NS" since="18" />
 		<field name="EFFECT_TYPE_PRESET_REVERB" since="18" />
 		<field name="EFFECT_TYPE_VIRTUALIZER" since="18" />
@@ -13027,7 +13028,7 @@
 	</class>
 	<class name="android/media/audiofx/LoudnessEnhancer" since="19">
 		<extends name="android/media/audiofx/AudioEffect" />
-		<method name="&lt;init>()V" />
+		<method name="&lt;init>(I)V" />
 		<method name="getTargetGain()F" />
 		<method name="setTargetGain(I)V" />
 		<field name="PARAM_TARGET_GAIN_MB" />
@@ -25504,10 +25505,8 @@
 		<method name="&lt;init>()V" />
 		<method name="beginDelayedTransition(Landroid/view/ViewGroup;)V" />
 		<method name="beginDelayedTransition(Landroid/view/ViewGroup;Landroid/transition/Transition;)V" />
-		<method name="getDefaultTransition()Landroid/transition/Transition;" />
 		<method name="go(Landroid/transition/Scene;)V" />
 		<method name="go(Landroid/transition/Scene;Landroid/transition/Transition;)V" />
-		<method name="setDefaultTransition(Landroid/transition/Transition;)V" />
 		<method name="setTransition(Landroid/transition/Scene;Landroid/transition/Scene;Landroid/transition/Transition;)V" />
 		<method name="setTransition(Landroid/transition/Scene;Landroid/transition/Transition;)V" />
 		<method name="transitionTo(Landroid/transition/Scene;)V" />
diff --git a/sdk/build_tools_source.prop_template b/sdk/build_tools_source.prop_template
index 5d62307..c9bfc2f 100644
--- a/sdk/build_tools_source.prop_template
+++ b/sdk/build_tools_source.prop_template
@@ -1,3 +1,3 @@
 Pkg.UserSrc=false
-Pkg.Revision=${PLATFORM_SDK_VERSION}.0.0
+Pkg.Revision=${PLATFORM_SDK_VERSION}.0.2
 
diff --git a/sdk/doc_source.prop_template b/sdk/doc_source.prop_template
index d3cdfd5..523d6bd 100644
--- a/sdk/doc_source.prop_template
+++ b/sdk/doc_source.prop_template
@@ -1,4 +1,4 @@
 Pkg.UserSrc=false
-Pkg.Revision=1
+Pkg.Revision=2
 AndroidVersion.ApiLevel=${PLATFORM_SDK_VERSION}
 AndroidVersion.CodeName=${PLATFORM_VERSION_CODENAME}
diff --git a/sdk/images_armeabi-v7a_source.prop_template b/sdk/images_armeabi-v7a_source.prop_template
index 9c7a332..7d13fce 100644
--- a/sdk/images_armeabi-v7a_source.prop_template
+++ b/sdk/images_armeabi-v7a_source.prop_template
@@ -1,6 +1,6 @@
 Pkg.Desc=Android SDK Platform ${PLATFORM_VERSION}
 Pkg.UserSrc=false
-Pkg.Revision=1
+Pkg.Revision=2
 AndroidVersion.ApiLevel=${PLATFORM_SDK_VERSION}
 AndroidVersion.CodeName=${PLATFORM_VERSION_CODENAME}
 SystemImage.Abi=armeabi-v7a
diff --git a/sdk/images_armeabi_source.prop_template b/sdk/images_armeabi_source.prop_template
index 91e9d21..ef17ea6 100644
--- a/sdk/images_armeabi_source.prop_template
+++ b/sdk/images_armeabi_source.prop_template
@@ -1,6 +1,6 @@
 Pkg.Desc=Android SDK Platform ${PLATFORM_VERSION}
 Pkg.UserSrc=false
-Pkg.Revision=1
+Pkg.Revision=2
 AndroidVersion.ApiLevel=${PLATFORM_SDK_VERSION}
 AndroidVersion.CodeName=${PLATFORM_VERSION_CODENAME}
 SystemImage.Abi=armeabi
diff --git a/sdk/images_x86_source.prop_template b/sdk/images_x86_source.prop_template
index cfbe180..84be49d 100644
--- a/sdk/images_x86_source.prop_template
+++ b/sdk/images_x86_source.prop_template
@@ -1,6 +1,6 @@
 Pkg.Desc=Android SDK Platform ${PLATFORM_VERSION}
 Pkg.UserSrc=false
-Pkg.Revision=1
+Pkg.Revision=2
 AndroidVersion.ApiLevel=${PLATFORM_SDK_VERSION}
 AndroidVersion.CodeName=${PLATFORM_VERSION_CODENAME}
 SystemImage.Abi=x86
diff --git a/sdk/plat_tools_source.prop_template b/sdk/plat_tools_source.prop_template
index 5d62307..b83af7f 100644
--- a/sdk/plat_tools_source.prop_template
+++ b/sdk/plat_tools_source.prop_template
@@ -1,3 +1,3 @@
 Pkg.UserSrc=false
-Pkg.Revision=${PLATFORM_SDK_VERSION}.0.0
+Pkg.Revision=${PLATFORM_SDK_VERSION}.0.1
 
diff --git a/sdk/platform_source.prop_template b/sdk/platform_source.prop_template
index 7ecb1e2..09a2d81 100644
--- a/sdk/platform_source.prop_template
+++ b/sdk/platform_source.prop_template
@@ -2,7 +2,7 @@
 Pkg.UserSrc=false
 Platform.Version=${PLATFORM_VERSION}
 Platform.CodeName=KitKat
-Pkg.Revision=1
+Pkg.Revision=2
 AndroidVersion.ApiLevel=${PLATFORM_SDK_VERSION}
 AndroidVersion.CodeName=${PLATFORM_VERSION_CODENAME}
 Layoutlib.Api=10
diff --git a/sdk/source_source.prop_template b/sdk/source_source.prop_template
index d3cdfd5..523d6bd 100644
--- a/sdk/source_source.prop_template
+++ b/sdk/source_source.prop_template
@@ -1,4 +1,4 @@
 Pkg.UserSrc=false
-Pkg.Revision=1
+Pkg.Revision=2
 AndroidVersion.ApiLevel=${PLATFORM_SDK_VERSION}
 AndroidVersion.CodeName=${PLATFORM_VERSION_CODENAME}
diff --git a/sdk/support_source.prop_template b/sdk/support_source.prop_template
index ba7e6fb..f897712 100644
--- a/sdk/support_source.prop_template
+++ b/sdk/support_source.prop_template
@@ -1,5 +1,5 @@
 Pkg.UserSrc=false
-Pkg.Revision=${PLATFORM_SDK_VERSION}
+Pkg.Revision=${PLATFORM_SDK_VERSION}.0.1
 Extra.Vendor=android
 Extra.VendorId=android
 Extra.VendorDisplay=Android
diff --git a/tools/emulator/test-apps/SmokeTests/Android.mk b/tools/emulator/test-apps/ConnectivityTest/Android.mk
similarity index 80%
copy from tools/emulator/test-apps/SmokeTests/Android.mk
copy to tools/emulator/test-apps/ConnectivityTest/Android.mk
index 41951dd..ca20d57 100644
--- a/tools/emulator/test-apps/SmokeTests/Android.mk
+++ b/tools/emulator/test-apps/ConnectivityTest/Android.mk
@@ -1,4 +1,4 @@
-# Copyright (C) 2014 The Android Open Source Project
+# Copyright (C) 2011 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.
@@ -15,18 +15,18 @@
 LOCAL_PATH:= $(call my-dir)
 include $(CLEAR_VARS)
 
-LOCAL_STATIC_JAVA_LIBRARIES := android-test-lib
-
 LOCAL_MODULE_TAGS := optional
 
 # Only compile source java files in this apk.
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
-LOCAL_PACKAGE_NAME := EmulatorSmokeTests
+LOCAL_PACKAGE_NAME := ConnectivityTest
 
 LOCAL_SDK_VERSION := 4
 
 LOCAL_PROGUARD_ENABLED := disabled
 
-
 include $(BUILD_PACKAGE)
+
+# Use the following include to make our test apk.
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tools/emulator/test-apps/SmokeTests/AndroidManifest.xml b/tools/emulator/test-apps/ConnectivityTest/AndroidManifest.xml
similarity index 70%
rename from tools/emulator/test-apps/SmokeTests/AndroidManifest.xml
rename to tools/emulator/test-apps/ConnectivityTest/AndroidManifest.xml
index 7066ca6..80f65cf 100644
--- a/tools/emulator/test-apps/SmokeTests/AndroidManifest.xml
+++ b/tools/emulator/test-apps/ConnectivityTest/AndroidManifest.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 The Android Open Source Project
+<!-- Copyright (C) 2011 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.
@@ -14,15 +14,14 @@
      limitations under the License.
 -->
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-      package="com.android.emulator.smoketests">
-    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
+      package="com.android.emulator.connectivity.test"
+      android:versionCode="1"
+      android:versionName="1.0">
     <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
     <uses-permission android:name="android.permission.INTERNET" />
-    <uses-permission android:name="android.permission.READ_SMS" />
     <uses-sdk android:minSdkVersion="4" />
-    <instrumentation android:targetPackage="com.android.emulator.smoketests"
-                     android:name="com.android.test.runner.AndroidJUnitRunner" />
-    <application  android:label="Emulator Smoke Tests">
+    <instrumentation android:targetPackage="com.android.emulator.connectivity.test" android:name="android.test.InstrumentationTestRunner" />
+    <application  android:label="Connectivity Test">
+        <uses-library android:name="android.test.runner" />
     </application>
-</manifest>
-
+</manifest>
\ No newline at end of file
diff --git a/tools/emulator/test-apps/SmokeTests/src/com/android/emulator/smoketests/connectivity/ConnectivityTest.java b/tools/emulator/test-apps/ConnectivityTest/src/com/android/emulator/connectivity/test/ConnectivityTest.java
similarity index 97%
rename from tools/emulator/test-apps/SmokeTests/src/com/android/emulator/smoketests/connectivity/ConnectivityTest.java
rename to tools/emulator/test-apps/ConnectivityTest/src/com/android/emulator/connectivity/test/ConnectivityTest.java
index 9fe1ebe..9931eb8 100644
--- a/tools/emulator/test-apps/SmokeTests/src/com/android/emulator/smoketests/connectivity/ConnectivityTest.java
+++ b/tools/emulator/test-apps/ConnectivityTest/src/com/android/emulator/connectivity/test/ConnectivityTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.emulator.smoketests.connectivity;
+package com.android.emulator.connectivity.test;
 
 import java.io.IOException;
 import java.net.URL;
diff --git a/tools/emulator/test-apps/SmokeTests/Android.mk b/tools/emulator/test-apps/GpsLocationTest/Android.mk
similarity index 80%
rename from tools/emulator/test-apps/SmokeTests/Android.mk
rename to tools/emulator/test-apps/GpsLocationTest/Android.mk
index 41951dd..5f90f3a 100644
--- a/tools/emulator/test-apps/SmokeTests/Android.mk
+++ b/tools/emulator/test-apps/GpsLocationTest/Android.mk
@@ -1,4 +1,4 @@
-# Copyright (C) 2014 The Android Open Source Project
+# Copyright (C) 2011 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.
@@ -15,18 +15,18 @@
 LOCAL_PATH:= $(call my-dir)
 include $(CLEAR_VARS)
 
-LOCAL_STATIC_JAVA_LIBRARIES := android-test-lib
-
 LOCAL_MODULE_TAGS := optional
 
 # Only compile source java files in this apk.
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
-LOCAL_PACKAGE_NAME := EmulatorSmokeTests
+LOCAL_PACKAGE_NAME := GpsLocationTest
 
 LOCAL_SDK_VERSION := 4
 
 LOCAL_PROGUARD_ENABLED := disabled
 
-
 include $(BUILD_PACKAGE)
+
+# Use the following include to make our test apk.
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tools/emulator/test-apps/SmokeTests/AndroidManifest.xml b/tools/emulator/test-apps/GpsLocationTest/AndroidManifest.xml
similarity index 65%
copy from tools/emulator/test-apps/SmokeTests/AndroidManifest.xml
copy to tools/emulator/test-apps/GpsLocationTest/AndroidManifest.xml
index 7066ca6..901855e 100644
--- a/tools/emulator/test-apps/SmokeTests/AndroidManifest.xml
+++ b/tools/emulator/test-apps/GpsLocationTest/AndroidManifest.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 The Android Open Source Project
+<!-- Copyright (C) 2011 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.
@@ -14,15 +14,14 @@
      limitations under the License.
 -->
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-      package="com.android.emulator.smoketests">
+      package="com.android.emulator.gps.test"
+      android:versionCode="1"
+      android:versionName="1.0">
     <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
-    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
-    <uses-permission android:name="android.permission.INTERNET" />
-    <uses-permission android:name="android.permission.READ_SMS" />
     <uses-sdk android:minSdkVersion="4" />
-    <instrumentation android:targetPackage="com.android.emulator.smoketests"
-                     android:name="com.android.test.runner.AndroidJUnitRunner" />
-    <application  android:label="Emulator Smoke Tests">
+    <instrumentation android:targetPackage="com.android.emulator.gps.test"
+                     android:name="android.test.InstrumentationTestRunner" />
+    <application  android:label="GPS Location Test">
+        <uses-library android:name="android.test.runner" />
     </application>
-</manifest>
-
+</manifest>
\ No newline at end of file
diff --git a/tools/emulator/test-apps/SmokeTests/src/com/android/emulator/smoketests/gps/GpsLocationTest.java b/tools/emulator/test-apps/GpsLocationTest/src/com/android/emulator/gps/test/GpsLocationTest.java
similarity index 98%
rename from tools/emulator/test-apps/SmokeTests/src/com/android/emulator/smoketests/gps/GpsLocationTest.java
rename to tools/emulator/test-apps/GpsLocationTest/src/com/android/emulator/gps/test/GpsLocationTest.java
index 1e0258c..6eb3834 100644
--- a/tools/emulator/test-apps/SmokeTests/src/com/android/emulator/smoketests/gps/GpsLocationTest.java
+++ b/tools/emulator/test-apps/GpsLocationTest/src/com/android/emulator/gps/test/GpsLocationTest.java
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.android.emulator.smoketests.gps;
+package com.android.emulator.gps.test;
 
 import android.content.Context;
 import android.location.Location;
diff --git a/tools/emulator/test-apps/SmokeTests/src/com/android/emulator/smoketests/sms/SmsTest.java b/tools/emulator/test-apps/SmokeTests/src/com/android/emulator/smoketests/sms/SmsTest.java
deleted file mode 100644
index bb1ce20..0000000
--- a/tools/emulator/test-apps/SmokeTests/src/com/android/emulator/smoketests/sms/SmsTest.java
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.emulator.smoketests.sms;
-
-import android.content.Context;
-import android.content.ContentResolver;
-import android.net.Uri;
-import android.database.Cursor;
-import android.os.Bundle;
-import android.os.HandlerThread;
-import com.android.test.InjectContext;
-
-import org.junit.Assert;
-import static junit.framework.Assert.assertEquals;
-
-import org.junit.Test;
-/**
- * Sms Test
- *
- * Test that an SMS message has been received
- */
-public class SmsTest {
-
-    /**
-     * Prior to running this test an sms must be sent
-     * via DDMS
-     */
-    public final static String NUMBER = "5551212";
-    public final static String BODY = "test sms";
-    private final static int SMS_POLL_TIME_MS = 10 * 1000;
-    private final static int SIXY_SECONDS_OF_LOOPS = 6;
-    @InjectContext
-    public Context mContext;
-
-    /**
-     * Verify that an SMS has been received with the correct number and body
-     */
-    @Test
-    public void testReceivedSms() throws java.lang.InterruptedException {
-        Cursor c = getSmsCursor();
-        c.moveToFirst();
-
-        String number = c.getString(c.getColumnIndexOrThrow("address"));
-        String body = c.getString(c.getColumnIndexOrThrow("body"));
-
-        c.close();
-
-        assertEquals(NUMBER, number);
-        assertEquals(BODY, body);
-    }
-
-    private Cursor getSmsCursor() throws java.lang.InterruptedException {
-        ContentResolver r = mContext.getContentResolver();
-        Uri message = Uri.parse("content://sms/");
-        Cursor c;
-
-        for(int i = 0; i < SIXY_SECONDS_OF_LOOPS; i++) {
-            c = r.query(message,null,null,null,null);
-
-            if(c.getCount() != 0) {
-                return c;
-            }
-
-            c.close();
-            Thread.sleep(SMS_POLL_TIME_MS);
-        }
-        Assert.fail("Did not find any SMS messages. Giving up");
-        // necessary for compilation
-        return null;
-    }
-
-}