resolved conflicts for merge of 748fb34d to lmp-mr1-dev

Change-Id: I729cc4282ff2b65907fd8013de270bca514c6e83
diff --git a/apps/Development/res/layout/connectivity.xml b/apps/Development/res/layout/connectivity.xml
index 2aaf6c6..d23a6b1 100644
--- a/apps/Development/res/layout/connectivity.xml
+++ b/apps/Development/res/layout/connectivity.xml
@@ -274,6 +274,16 @@
       android:orientation="horizontal"
       android:layout_width="match_parent"
       android:layout_height="wrap_content">
+        <Button android:id="@+id/report_all_bad"
+          android:layout_width="wrap_content"
+          android:layout_height="wrap_content"
+          android:text="@string/report_all_bad" />
+    </LinearLayout>
+
+    <LinearLayout
+      android:orientation="horizontal"
+      android:layout_width="match_parent"
+      android:layout_height="wrap_content">
         <Button android:id="@+id/crash"
           android:layout_width="wrap_content"
           android:layout_height="wrap_content"
diff --git a/apps/Development/res/values/strings.xml b/apps/Development/res/values/strings.xml
index 0c13987..d670cf4 100644
--- a/apps/Development/res/values/strings.xml
+++ b/apps/Development/res/values/strings.xml
@@ -43,6 +43,8 @@
     <string name="start_hipri">Start HiPri</string>
     <string name="stop_hipri">Stop HiPri</string>
     <string name="crash">CRASH</string>
+    <string name="report_all_bad">Report all bad</string>
+
     <string name="netid">NetId</string>
     <string name="add_default_route">Add Default Route</string>
     <string name="remove_default_route">Remove Default Route</string>
diff --git a/apps/Development/src/com/android/development/Connectivity.java b/apps/Development/src/com/android/development/Connectivity.java
index 93d199b..a576eb3 100644
--- a/apps/Development/src/com/android/development/Connectivity.java
+++ b/apps/Development/src/com/android/development/Connectivity.java
@@ -29,6 +29,7 @@
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.net.ConnectivityManager;
 import android.net.LinkAddress;
+import android.net.Network;
 import android.net.NetworkUtils;
 import android.net.RouteInfo;
 import android.net.wifi.ScanResult;
@@ -304,6 +305,7 @@
         findViewById(R.id.stop_mms).setOnClickListener(mClickListener);
         findViewById(R.id.start_hipri).setOnClickListener(mClickListener);
         findViewById(R.id.stop_hipri).setOnClickListener(mClickListener);
+        findViewById(R.id.report_all_bad).setOnClickListener(mClickListener);
         findViewById(R.id.crash).setOnClickListener(mClickListener);
 
         findViewById(R.id.add_default_route).setOnClickListener(mClickListener);
@@ -318,6 +320,11 @@
         registerReceiver(mReceiver, new IntentFilter(CONNECTIVITY_TEST_ALARM));
     }
 
+    @Override
+    public void onDestroy() {
+        super.onDestroy();
+        unregisterReceiver(mReceiver);
+    }
 
     @Override
     public void onResume() {
@@ -387,6 +394,9 @@
                 case R.id.add_default_route:
                     onAddDefaultRoute();
                     break;
+                case R.id.report_all_bad:
+                    onReportAllBad();
+                    break;
                 case R.id.crash:
                     onCrash();
                     break;
@@ -460,6 +470,13 @@
     private void onStopScreenCycle() {
     }
 
+    private void onReportAllBad() {
+        Network[] networks = mCm.getAllNetworks();
+        for (Network network : networks) {
+            mCm.reportBadNetwork(network);
+        }
+    }
+
     private void onCrash() {
         ConnectivityManager foo = null;
         foo.startUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE,
diff --git a/build/product_sdk.mk b/build/product_sdk.mk
index 7aba4ee..68a4ecc 100644
--- a/build/product_sdk.mk
+++ b/build/product_sdk.mk
@@ -44,4 +44,5 @@
 	layoutlib-tests \
 	llvm-rs-cc \
 	sqlite3 \
-	vgabios-cirrus.bin
+	vgabios-cirrus.bin \
+	split-select
diff --git a/build/sdk-windows-x86.atree b/build/sdk-windows-x86.atree
index a0e19ba..7ff3add 100644
--- a/build/sdk-windows-x86.atree
+++ b/build/sdk-windows-x86.atree
@@ -61,6 +61,9 @@
 rm build-tools/${PLATFORM_NAME}/aapt
 bin/aapt.exe                            strip build-tools/${PLATFORM_NAME}/aapt.exe
 
+rm build-tools/${PLATFORM_NAME}/split-select
+bin/split-select.exe                    strip build-tools/${PLATFORM_NAME}/split-select.exe
+
 rm build-tools/${PLATFORM_NAME}/aidl
 bin/aidl.exe                            strip build-tools/${PLATFORM_NAME}/aidl.exe
 
diff --git a/build/sdk.atree b/build/sdk.atree
index 229e782..9c7ba8a 100644
--- a/build/sdk.atree
+++ b/build/sdk.atree
@@ -79,6 +79,7 @@
 # build tools from out/host/$(HOST_OS)-$(HOST_ARCH)/
 bin/aapt                                strip build-tools/${PLATFORM_NAME}/aapt
 bin/aidl                                strip build-tools/${PLATFORM_NAME}/aidl
+bin/split-select                        strip build-tools/${PLATFORM_NAME}/split-select
 bin/zipalign                            strip build-tools/${PLATFORM_NAME}/zipalign
 
 # renderscript (cc + headers)
diff --git a/build/tools/windows_sdk.mk b/build/tools/windows_sdk.mk
index d107d37..dadb773 100644
--- a/build/tools/windows_sdk.mk
+++ b/build/tools/windows_sdk.mk
@@ -41,6 +41,7 @@
 	prebuilt \
 	sqlite3 \
 	zipalign \
+	split-select \
 	$(WIN_SDK_TARGETS)
 
 # This is the list of *Linux* build tools that we need
diff --git a/build/windows_sdk_whitelist.mk b/build/windows_sdk_whitelist.mk
index dfeaf3a..d91dde5 100644
--- a/build/windows_sdk_whitelist.mk
+++ b/build/windows_sdk_whitelist.mk
@@ -40,6 +40,7 @@
 	external/clang \
 	external/easymock \
 	external/expat \
+	external/gtest \
 	external/libcxx \
 	external/libcxxabi \
 	external/compiler-rt \
diff --git a/samples/ApiDemos/res/layout/media_projection.xml b/samples/ApiDemos/res/layout/media_projection.xml
index 412db4c..d9082a3 100644
--- a/samples/ApiDemos/res/layout/media_projection.xml
+++ b/samples/ApiDemos/res/layout/media_projection.xml
@@ -30,6 +30,7 @@
         android:orientation="horizontal"
         android:layout_alignParentBottom="true">
         <ToggleButton
+            android:id="@+id/screen_sharing_toggle"
             android:text="@string/screen_sharing_toggle"
             android:layout_width="0dp"
             android:layout_height="match_parent"
diff --git a/samples/ApiDemos/res/values/strings.xml b/samples/ApiDemos/res/values/strings.xml
index 58daf39..65bfba3 100644
--- a/samples/ApiDemos/res/values/strings.xml
+++ b/samples/ApiDemos/res/values/strings.xml
@@ -790,6 +790,10 @@
     <string name="require_encryption">Require encryption</string>
     <string name="activate_encryption">Activate encryption</string>
 
+    <string name="trust_agent_category">Trust Agent Features</string>
+    <string name="set_trust_agent_component_name">Enabled Component Name</string>
+    <string name="set_trust_agent_feature_list">Enabled Features (comma-separated)</string>
+
     <!-- Strings used by DeviceAdminSample controller code -->
     <string name="password_sufficient">Current password meets policy requirements</string>
     <string name="password_insufficient">Current password does not meet policy requirements</string>
diff --git a/samples/ApiDemos/res/xml/device_admin_general.xml b/samples/ApiDemos/res/xml/device_admin_general.xml
index cfd0048..1d0084e 100644
--- a/samples/ApiDemos/res/xml/device_admin_general.xml
+++ b/samples/ApiDemos/res/xml/device_admin_general.xml
@@ -57,4 +57,19 @@
 
     </PreferenceCategory>
 
+    <PreferenceCategory
+        android:title="@string/trust_agent_category" >
+
+        <EditTextPreference
+            android:key="key_trust_agent_component"
+            android:title="@string/set_trust_agent_component_name"
+            android:dialogTitle="@string/set_trust_agent_component_name" />
+
+        <EditTextPreference
+            android:key="key_trust_agent_features"
+            android:title="@string/set_trust_agent_feature_list"
+            android:dialogTitle="@string/set_trust_agent_feature_list" />
+
+    </PreferenceCategory>
+
 </PreferenceScreen>
diff --git a/samples/ApiDemos/src/com/example/android/apis/app/DeviceAdminSample.java b/samples/ApiDemos/src/com/example/android/apis/app/DeviceAdminSample.java
index 82df903..71badcd 100644
--- a/samples/ApiDemos/src/com/example/android/apis/app/DeviceAdminSample.java
+++ b/samples/ApiDemos/src/com/example/android/apis/app/DeviceAdminSample.java
@@ -26,7 +26,9 @@
 import android.content.Context;
 import android.content.DialogInterface;
 import android.content.Intent;
+import android.content.SharedPreferences;
 import android.os.Bundle;
+import android.os.PersistableBundle;
 import android.preference.CheckBoxPreference;
 import android.preference.EditTextPreference;
 import android.preference.ListPreference;
@@ -41,6 +43,8 @@
 import android.util.Log;
 import android.widget.Toast;
 
+import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 
 /**
@@ -71,6 +75,8 @@
     private static final String KEY_DISABLE_NOTIFICATIONS = "key_disable_notifications";
     private static final String KEY_DISABLE_UNREDACTED = "key_disable_unredacted";
     private static final String KEY_DISABLE_TRUST_AGENTS = "key_disable_trust_agents";
+    private static final String KEY_TRUST_AGENT_COMPONENT = "key_trust_agent_component";
+    private static final String KEY_TRUST_AGENT_FEATURES = "key_trust_agent_features";
     private static final String KEY_DISABLE_KEYGUARD_WIDGETS = "key_disable_keyguard_widgets";
     private static final String KEY_DISABLE_KEYGUARD_SECURE_CAMERA
             = "key_disable_keyguard_secure_camera";
@@ -274,6 +280,8 @@
         private CheckBoxPreference mDisableKeyguardNotificationCheckbox;
         private CheckBoxPreference mDisableKeyguardTrustAgentCheckbox;
         private CheckBoxPreference mDisableKeyguardUnredactedCheckbox;
+        private EditTextPreference mTrustAgentComponent;
+        private EditTextPreference mTrustAgentFeatures;
 
         @Override
         public void onCreate(Bundle savedInstanceState) {
@@ -304,6 +312,14 @@
             mDisableKeyguardTrustAgentCheckbox =
                     (CheckBoxPreference) findPreference(KEY_DISABLE_TRUST_AGENTS);
             mDisableKeyguardTrustAgentCheckbox.setOnPreferenceChangeListener(this);
+
+            mTrustAgentComponent =
+                    (EditTextPreference) findPreference(KEY_TRUST_AGENT_COMPONENT);
+            mTrustAgentComponent.setOnPreferenceChangeListener(this);
+
+            mTrustAgentFeatures =
+                    (EditTextPreference) findPreference(KEY_TRUST_AGENT_FEATURES);
+            mTrustAgentFeatures.setOnPreferenceChangeListener(this);
         }
 
         // At onResume time, reload UI with current values as required
@@ -340,8 +356,8 @@
             if (super.onPreferenceChange(preference, newValue)) {
                 return true;
             }
-            boolean value = (Boolean) newValue;
             if (preference == mEnableCheckbox) {
+                boolean value = (Boolean) newValue;
                 if (value != mAdminActive) {
                     if (value) {
                         // Launch the activity to have the user enable our admin.
@@ -359,6 +375,7 @@
                     }
                 }
             } else if (preference == mDisableCameraCheckbox) {
+                boolean value = (Boolean) newValue;
                 mDPM.setCameraDisabled(mDeviceAdminSample, value);
                 // Delay update because the change is only applied after exiting this method.
                 postReloadSummaries();
@@ -366,20 +383,39 @@
                     || preference == mDisableKeyguardSecureCameraCheckbox
                     || preference == mDisableKeyguardNotificationCheckbox
                     || preference == mDisableKeyguardUnredactedCheckbox
-                    || preference == mDisableKeyguardTrustAgentCheckbox) {
-                // Delay update because the change is only applied after exiting this method.
-                getView().post(new Runnable() {
-                    @Override
-                    public void run() {
-                        mDPM.setKeyguardDisabledFeatures(mDeviceAdminSample,
-                                createKeyguardDisabledFlag());
-                    }
-                });
+                    || preference == mDisableKeyguardTrustAgentCheckbox
+                    || preference == mTrustAgentComponent
+                    || preference == mTrustAgentFeatures) {
+                postUpdateDpmDisableFeatures();
                 postReloadSummaries();
             }
             return true;
         }
 
+        private void postUpdateDpmDisableFeatures() {
+            getView().post(new Runnable() {
+                @Override
+                public void run() {
+                    mDPM.setKeyguardDisabledFeatures(mDeviceAdminSample,
+                            createKeyguardDisabledFlag());
+                    String component = mTrustAgentComponent.getText();
+                    if (component != null) {
+                        ComponentName agent = ComponentName.unflattenFromString(component);
+                        if (agent != null) {
+                            String featureString = mTrustAgentFeatures.getText();
+                            if (featureString != null) {
+                                PersistableBundle bundle = new PersistableBundle();
+                                bundle.putStringArray("features", featureString.split(","));
+                                mDPM.setTrustAgentConfiguration(mDeviceAdminSample, agent, bundle);
+                            }
+                        } else {
+                            Log.w(TAG, "Invalid component: " + component);
+                        }
+                    }
+                }
+            });
+        }
+
         @Override
         protected void reloadSummaries() {
             super.reloadSummaries();
@@ -416,6 +452,17 @@
                         R.string.keyguard_trust_agents_disabled
                         : R.string.keyguard_trust_agents_enabled);
             mDisableKeyguardTrustAgentCheckbox.setSummary(keyguardEnableTrustAgentSummary);
+
+            final SharedPreferences prefs = getPreferenceManager().getSharedPreferences();
+            final boolean trustDisabled =
+                    (disabled & DevicePolicyManager.KEYGUARD_DISABLE_TRUST_AGENTS) != 0;
+            String component = prefs.getString(mTrustAgentComponent.getKey(), null);
+            mTrustAgentComponent.setSummary(component);
+            mTrustAgentComponent.setEnabled(trustDisabled);
+
+            String features = prefs.getString(mTrustAgentFeatures.getKey(), null);
+            mTrustAgentFeatures.setSummary(features);
+            mTrustAgentFeatures.setEnabled(trustDisabled);
         }
 
         /** Updates the device capabilities area (dis/enabling) as the admin is (de)activated */
@@ -426,6 +473,8 @@
             mDisableKeyguardNotificationCheckbox.setEnabled(enabled);
             mDisableKeyguardUnredactedCheckbox.setEnabled(enabled);
             mDisableKeyguardTrustAgentCheckbox.setEnabled(enabled);
+            mTrustAgentComponent.setEnabled(enabled);
+            mTrustAgentFeatures.setEnabled(enabled);
         }
     }
 
diff --git a/samples/ApiDemos/src/com/example/android/apis/media/projection/MediaProjectionDemo.java b/samples/ApiDemos/src/com/example/android/apis/media/projection/MediaProjectionDemo.java
index c593daf..f8a5d05 100644
--- a/samples/ApiDemos/src/com/example/android/apis/media/projection/MediaProjectionDemo.java
+++ b/samples/ApiDemos/src/com/example/android/apis/media/projection/MediaProjectionDemo.java
@@ -64,6 +64,7 @@
     private VirtualDisplay mVirtualDisplay;
     private Surface mSurface;
     private SurfaceView mSurfaceView;
+    private ToggleButton mToggle;
 
     @Override
     public void onCreate(Bundle savedInstanceState) {
@@ -85,6 +86,8 @@
         s.setAdapter(arrayAdapter);
         s.setOnItemSelectedListener(new ResolutionSelector());
         s.setSelection(0);
+
+        mToggle = (ToggleButton) findViewById(R.id.screen_sharing_toggle);
     }
 
     @Override
@@ -108,6 +111,7 @@
             return;
         }
         mMediaProjection = mProjectionManager.getMediaProjection(resultCode, data);
+        mMediaProjection.registerCallback(new MediaProjectionCallback(), null);
         mVirtualDisplay = createVirtualDisplay();
     }
 
@@ -133,11 +137,14 @@
     }
 
     private void stopScreenSharing() {
-        mScreenSharing = false;
-        if (mVirtualDisplay == null) {
-            return;
+        if (mToggle.isChecked()) {
+            mToggle.setChecked(false);
         }
-        mVirtualDisplay.release();
+        mScreenSharing = false;
+        if (mVirtualDisplay != null) {
+            mVirtualDisplay.release();
+            mVirtualDisplay = null;
+        }
     }
 
     private VirtualDisplay createVirtualDisplay() {
diff --git a/samples/ApiDemos/src/com/example/android/apis/os/MmsMessagingDemo.java b/samples/ApiDemos/src/com/example/android/apis/os/MmsMessagingDemo.java
index 6a5d94c..0b66d6f 100644
--- a/samples/ApiDemos/src/com/example/android/apis/os/MmsMessagingDemo.java
+++ b/samples/ApiDemos/src/com/example/android/apis/os/MmsMessagingDemo.java
@@ -238,7 +238,8 @@
         if (code == Activity.RESULT_OK) {
             final byte[] response = intent.getByteArrayExtra(SmsManager.EXTRA_MMS_DATA);
             if (response != null) {
-                final GenericPdu pdu = new PduParser(response).parse();
+                final GenericPdu pdu = new PduParser(
+                        response, PduParserUtil.shouldParseContentDisposition()).parse();
                 if (pdu instanceof SendConf) {
                     final SendConf sendConf = (SendConf) pdu;
                     if (sendConf.getResponseStatus() == PduHeaders.RESPONSE_STATUS_OK) {
@@ -281,7 +282,8 @@
                 final byte[] response = new byte[nBytes];
                 final int read = reader.read(response, 0, nBytes);
                 if (read == nBytes) {
-                    final GenericPdu pdu = new PduParser(response).parse();
+                    final GenericPdu pdu = new PduParser(
+                            response, PduParserUtil.shouldParseContentDisposition()).parse();
                     if (pdu instanceof RetrieveConf) {
                         final RetrieveConf retrieveConf = (RetrieveConf) pdu;
                         mRecipientsInput.setText(getRecipients(context, retrieveConf));
diff --git a/samples/ApiDemos/src/com/example/android/apis/os/MmsWapPushReceiver.java b/samples/ApiDemos/src/com/example/android/apis/os/MmsWapPushReceiver.java
index a291e4a..f2ca090 100644
--- a/samples/ApiDemos/src/com/example/android/apis/os/MmsWapPushReceiver.java
+++ b/samples/ApiDemos/src/com/example/android/apis/os/MmsWapPushReceiver.java
@@ -16,18 +16,18 @@
 
 package com.example.android.apis.os;
 
-import com.google.android.mms.ContentType;
-import com.google.android.mms.pdu.GenericPdu;
-import com.google.android.mms.pdu.NotificationInd;
-import com.google.android.mms.pdu.PduHeaders;
-import com.google.android.mms.pdu.PduParser;
-
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
 import android.provider.Telephony;
 import android.util.Log;
 
+import com.google.android.mms.ContentType;
+import com.google.android.mms.pdu.GenericPdu;
+import com.google.android.mms.pdu.NotificationInd;
+import com.google.android.mms.pdu.PduHeaders;
+import com.google.android.mms.pdu.PduParser;
+
 /**
  * Receiver for MMS WAP push
  */
@@ -39,7 +39,8 @@
         if (Telephony.Sms.Intents.WAP_PUSH_RECEIVED_ACTION.equals(intent.getAction())
                 && ContentType.MMS_MESSAGE.equals(intent.getType())) {
             final byte[] data = intent.getByteArrayExtra("data");
-            final PduParser parser = new PduParser(data);
+            final PduParser parser = new PduParser(
+                    data, PduParserUtil.shouldParseContentDisposition());
             GenericPdu pdu = null;
             try {
                 pdu = parser.parse();
diff --git a/samples/ApiDemos/src/com/example/android/apis/os/PduParserUtil.java b/samples/ApiDemos/src/com/example/android/apis/os/PduParserUtil.java
new file mode 100644
index 0000000..541854e
--- /dev/null
+++ b/samples/ApiDemos/src/com/example/android/apis/os/PduParserUtil.java
@@ -0,0 +1,37 @@
+/*
+ * 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.apis.os;
+
+import android.telephony.SmsManager;
+
+/**
+ * Util methods for PduParser
+ */
+public class PduParserUtil {
+    /**
+     * Get the config of whether Content-Disposition header is supported
+     * for default carrier using new SmsManager API
+     *
+     * @return true if supported, false otherwise
+     */
+    public static boolean shouldParseContentDisposition() {
+        return SmsManager
+                .getDefault()
+                .getCarrierConfigValues()
+                .getBoolean(SmsManager.MMS_CONFIG_SUPPORT_MMS_CONTENT_DISPOSITION, true);
+    }
+}
diff --git a/samples/SoftKeyboard/src/com/example/android/softkeyboard/ImePreferences.java b/samples/SoftKeyboard/src/com/example/android/softkeyboard/ImePreferences.java
index db6c1d9..14c67b7 100644
--- a/samples/SoftKeyboard/src/com/example/android/softkeyboard/ImePreferences.java
+++ b/samples/SoftKeyboard/src/com/example/android/softkeyboard/ImePreferences.java
@@ -41,6 +41,11 @@
         setTitle(R.string.settings_name);
     }
 
+    @Override
+    protected boolean isValidFragment(final String fragmentName) {
+        return Settings.class.getName().equals(fragmentName);
+    }
+
     public static class Settings extends InputMethodSettingsFragment {
         @Override
         public void onCreate(Bundle savedInstanceState) {
diff --git a/samples/Support7Demos/AndroidManifest.xml b/samples/Support7Demos/AndroidManifest.xml
index 4077bb1..1d087a4 100644
--- a/samples/Support7Demos/AndroidManifest.xml
+++ b/samples/Support7Demos/AndroidManifest.xml
@@ -31,7 +31,7 @@
          reading images from the media store from API v19+. -->
     <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
 
-    <uses-sdk android:minSdkVersion="7" android:targetSdkVersion="17" />
+    <uses-sdk android:minSdkVersion="7" android:targetSdkVersion="21" />
 
     <!-- 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
@@ -86,6 +86,14 @@
             </intent-filter>
         </activity>
 
+        <activity android:name=".media.SampleMediaRouteSettingsActivity"
+                android:label="@string/sample_media_route_settings_activity"
+                android:theme="@style/Theme.AppCompat.Light">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+            </intent-filter>
+        </activity>
+
         <service android:name=".media.SampleMediaRouteProviderService"
                 android:label="@string/sample_media_route_provider_service"
                 android:process=":mrp">
@@ -130,6 +138,16 @@
             </intent-filter>
         </activity>
 
+        <activity android:name=".app.SearchActivity">
+            <intent-filter>
+                <action android:name="android.intent.action.SEARCH" />
+            </intent-filter>
+
+            <meta-data android:name="android.app.searchable"
+                       android:resource="@xml/searchable" />
+
+        </activity>
+
         <activity android:name=".app.ActionBarUsage"
                 android:label="@string/action_bar_usage"
                 android:theme="@style/Theme.AppCompat">
@@ -151,7 +169,7 @@
 
         <activity android:name=".app.ActionBarTabs"
                 android:label="@string/action_bar_tabs"
-                android:theme="@style/Theme.AppCompat">
+                android:theme="@style/Theme.Custom">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="com.example.android.supportv7.SAMPLE_CODE" />
@@ -160,7 +178,7 @@
 
         <activity android:name=".app.ActionBarSettingsActionProviderActivity"
                 android:label="@string/action_bar_settings_action_provider"
-                android:theme="@style/Theme.AppCompat">
+                android:theme="@style/Theme.AppCompat.Light.DarkActionBar">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="com.example.android.supportv7.SAMPLE_CODE" />
@@ -177,15 +195,49 @@
         </activity>
 
         <activity android:name=".app.ActionBarWithDrawerLayout"
-                  android:label="@string/action_bar_with_navigation_drawer"
-                  android:theme="@style/Theme.AppCompat"
-                  >
+                android:label="@string/action_bar_with_navigation_drawer"
+                android:theme="@style/Theme.AppCompat"
+                >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="com.example.android.supportv7.SAMPLE_CODE"/>
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".app.ToolbarUsage"
+                  android:label="@string/toolbar_usage"
+                  android:theme="@style/Theme.Custom.NoActionBar">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="com.example.android.supportv7.SAMPLE_CODE" />
+            </intent-filter>
+
+            <meta-data
+                    android:name="android.app.default_searchable"
+                    android:value=".app.SearchActivity" />
+        </activity>
+
+        <activity android:name=".app.ToolbarDisplayOptions"
+                  android:label="@string/toolbar_display_options"
+                  android:theme="@style/Theme.AppCompat.Light.NoActionBar">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="com.example.android.supportv7.SAMPLE_CODE" />
             </intent-filter>
         </activity>
 
+        <activity android:name=".app.ToolbarFragmentPagerMenu"
+                  android:label="@string/toolbar_fragment_pager"
+                  android:theme="@style/Theme.AppCompat.Light.NoActionBar">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="com.example.android.supportv7.SAMPLE_CODE" />
+            </intent-filter>
+        </activity>
+
+        <provider android:name=".app.RecentSuggestionsProvider"
+                  android:authorities="com.example.android.supportv7.RecentSuggestionsProvider" />
+
         <!-- RecyclerView samples -->
         <activity android:name=".widget.RecyclerViewActivity"
                   android:label="@string/recycler_view"
diff --git a/samples/Support7Demos/res/layout/activity_card_view.xml b/samples/Support7Demos/res/layout/activity_card_view.xml
index cfd3071..9b985f7 100644
--- a/samples/Support7Demos/res/layout/activity_card_view.xml
+++ b/samples/Support7Demos/res/layout/activity_card_view.xml
@@ -123,13 +123,61 @@
                 android:layout_height="wrap_content"
                 android:layout_toRightOf="@id/alpha_label"
                 android:layout_alignTop="@id/alpha_label"/>
-
+        <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginBottom="5dp"
+                android:id="@+id/color_label"
+                android:textColor="@android:color/black"
+                android:text="@string/card_view_bg_color"
+                android:layout_below="@id/alpha_label"
+                android:layout_alignRight="@id/alpha_label"/>
+        <RadioGroup
+                android:id="@+id/select_bg_color_radio"
+                android:layout_toRightOf="@id/color_label"
+                android:layout_alignTop="@id/color_label"
+                android:layout_width="fill_parent"
+                android:layout_height="wrap_content"
+                android:orientation="horizontal"
+                android:layout_below="@id/alpha_seek_bar">
+            <RadioButton
+                    android:id="@+id/def"
+                    android:layout_width="40dp"
+                    android:layout_height="wrap_content"
+                    android:background="@color/cardview_light_background"
+                    android:checked="true"/>
+            <RadioButton
+                    android:id="@+id/yellow"
+                    android:layout_width="40dp"
+                    android:layout_height="wrap_content"
+                    android:background="@color/card_yellow"/>
+            <RadioButton
+                    android:id="@+id/aquatic"
+                    android:layout_width="40dp"
+                    android:layout_height="wrap_content"
+                    android:background="@color/card_aquatic"/>
+            <RadioButton
+                    android:id="@+id/classic"
+                    android:layout_width="40dp"
+                    android:layout_height="wrap_content"
+                    android:background="@color/card_classic"/>
+            <RadioButton
+                    android:id="@+id/sunbrite"
+                    android:layout_width="40dp"
+                    android:layout_height="wrap_content"
+                    android:background="@color/card_sunbrite"/>
+            <RadioButton
+                    android:id="@+id/tropical"
+                    android:layout_width="40dp"
+                    android:layout_height="wrap_content"
+                    android:background="@color/card_tropical"/>
+        </RadioGroup>
         <RadioGroup
                 android:id="@+id/select_target_radio"
                 android:layout_width="fill_parent"
                 android:layout_height="wrap_content"
                 android:orientation="horizontal"
-                android:layout_below="@id/alpha_seek_bar">
+                android:layout_below="@id/color_label">
             <RadioButton
                     android:id="@+id/resize_card_view"
                     android:layout_width="wrap_content"
@@ -144,7 +192,6 @@
                     android:textColor="@android:color/black"
                     android:text="@string/card_view_resize_content"/>
         </RadioGroup>
-
     </RelativeLayout>
     <RelativeLayout android:layout_width="fill_parent"
                     android:layout_height="match_parent">
@@ -155,9 +202,10 @@
                 card_view:cardElevation="10dp">
             <TextView
                     android:id="@+id/info_text"
+                    android:text="@string/card_view"
                     android:textColor="@android:color/black"
-                    android:layout_width="match_parent"
-                    android:layout_height="match_parent" />
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content" />
         </android.support.v7.widget.CardView>
         <TextView android:layout_width="wrap_content" android:layout_height="wrap_content"
                   android:text="@string/card_view_sample_text"
diff --git a/samples/Support7Demos/res/layout/toolbar_display_options.xml b/samples/Support7Demos/res/layout/toolbar_display_options.xml
new file mode 100644
index 0000000..cc3e66c
--- /dev/null
+++ b/samples/Support7Demos/res/layout/toolbar_display_options.xml
@@ -0,0 +1,85 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              xmlns:app="http://schemas.android.com/apk/res-auto"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent"
+              android:orientation="vertical">
+
+    <android.support.v7.widget.Toolbar
+            android:id="@+id/toolbar"
+            android:layout_height="wrap_content"
+            android:layout_width="match_parent"
+            android:minHeight="?attr/actionBarSize"
+            android:background="?attr/colorPrimary" />
+
+    <ScrollView
+            android:layout_width="match_parent"
+            android:layout_height="match_parent">
+
+        <LinearLayout
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:orientation="vertical">
+
+            <Button
+                    android:id="@+id/toggle_home_as_up"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:text="@string/toggle_home_as_up"/>
+
+            <Button
+                    android:id="@+id/toggle_show_home"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:text="@string/toggle_show_home"/>
+
+            <Button
+                    android:id="@+id/toggle_use_logo"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:text="@string/toggle_use_logo"/>
+
+            <Button
+                    android:id="@+id/toggle_show_title"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:text="@string/toggle_show_title"/>
+
+            <Button
+                    android:id="@+id/toggle_show_custom"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:text="@string/toggle_show_custom"/>
+
+            <Button
+                    android:id="@+id/cycle_custom_gravity"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:text="@string/cycle_custom_gravity"/>
+
+            <Button
+                    android:id="@+id/toggle_visibility"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:text="@string/toggle_visibility"/>
+
+        </LinearLayout>
+
+    </ScrollView>
+
+</LinearLayout>
\ No newline at end of file
diff --git a/samples/Support7Demos/res/layout/toolbar_fragment_pager.xml b/samples/Support7Demos/res/layout/toolbar_fragment_pager.xml
new file mode 100644
index 0000000..9f56f19
--- /dev/null
+++ b/samples/Support7Demos/res/layout/toolbar_fragment_pager.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent"
+              android:orientation="vertical">
+
+    <android.support.v7.widget.Toolbar
+            android:id="@+id/toolbar"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:minHeight="?actionBarSize"
+            android:background="?attr/colorPrimaryDark" />
+
+    <android.support.v4.view.ViewPager
+            android:id="@+id/viewpager"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"/>
+
+</LinearLayout>
\ No newline at end of file
diff --git a/samples/Support7Demos/res/layout/toolbar_usage.xml b/samples/Support7Demos/res/layout/toolbar_usage.xml
new file mode 100644
index 0000000..b202e1f
--- /dev/null
+++ b/samples/Support7Demos/res/layout/toolbar_usage.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              xmlns:app="http://schemas.android.com/apk/res-auto"
+              android:orientation="vertical"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent">
+
+    <android.support.v7.widget.Toolbar
+            android:id="@+id/toolbar"
+            android:layout_height="wrap_content"
+            android:layout_width="match_parent"
+            android:minHeight="?attr/actionBarSize"
+            android:background="?attr/colorPrimaryDark"
+            app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
+            app:popupTheme="@style/ThemeOverlay.AppCompat.Light" />
+
+    <TextView
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:text="Your content"
+            android:gravity="center"
+            android:textAppearance="?android:attr/textAppearanceLarge"/>
+
+</LinearLayout>
\ No newline at end of file
diff --git a/samples/Support7Demos/res/menu/actions.xml b/samples/Support7Demos/res/menu/actions.xml
index 38d291e..43605fd 100644
--- a/samples/Support7Demos/res/menu/actions.xml
+++ b/samples/Support7Demos/res/menu/actions.xml
@@ -16,9 +16,9 @@
 <menu xmlns:android="http://schemas.android.com/apk/res/android"
         xmlns:app="http://schemas.android.com/apk/res-auto">
     <item android:id="@+id/action_search"
-          android:icon="@android:drawable/ic_menu_search"
           android:title="@string/action_bar_search"
-          app:showAsAction="ifRoom"
+          android:icon="@drawable/abc_ic_search_api_mtrl_alpha"
+          app:showAsAction="ifRoom|collapseActionView"
           app:actionViewClass="android.support.v7.widget.SearchView" />
     <item android:id="@+id/action_add"
           android:icon="@android:drawable/ic_menu_add"
@@ -30,6 +30,7 @@
     <item android:id="@+id/action_share"
           android:icon="@android:drawable/ic_menu_share"
           android:title="@string/action_bar_share"
+          android:enabled="false"
           app:showAsAction="ifRoom" />
     <item android:id="@+id/action_sort"
           android:icon="@android:drawable/ic_menu_sort_by_size"
@@ -38,12 +39,10 @@
         <menu>
             <item android:id="@+id/action_sort_size"
                   android:icon="@android:drawable/ic_menu_sort_by_size"
-                  android:title="@string/action_bar_sort_size"
-                  android:onClick="onSort" />
+                  android:title="@string/action_bar_sort_size" />
             <item android:id="@+id/action_sort_alpha"
                   android:icon="@android:drawable/ic_menu_sort_alphabetically"
-                  android:title="@string/action_bar_sort_alpha"
-                  android:onClick="onSort" />
+                  android:title="@string/action_bar_sort_alpha" />
         </menu>
     </item>
 </menu>
diff --git a/samples/Support7Demos/res/values/colors.xml b/samples/Support7Demos/res/values/colors.xml
index b129b8d..c8c67a0 100644
--- a/samples/Support7Demos/res/values/colors.xml
+++ b/samples/Support7Demos/res/values/colors.xml
@@ -16,4 +16,9 @@
 
 <resources>
     <drawable name="blue">#770000ff</drawable>
+    <color name="card_yellow">#FCF0AD</color>
+    <color name="card_aquatic">#FCF0AD</color>
+    <color name="card_classic">#BAB7A9</color>
+    <color name="card_sunbrite">#F9D6AC</color>
+    <color name="card_tropical">#56C4E8</color>
 </resources>
diff --git a/samples/Support7Demos/res/values/strings.xml b/samples/Support7Demos/res/values/strings.xml
index 14569a5..4b3a28f 100644
--- a/samples/Support7Demos/res/values/strings.xml
+++ b/samples/Support7Demos/res/values/strings.xml
@@ -25,6 +25,7 @@
     <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="sample_media_route_settings_activity">Sample route settings</string>
 
     <string name="library_tab_text">Library</string>
     <string name="playlist_tab_text">Playlist</string>
@@ -121,6 +122,9 @@
         necessary.
     </string>
 
+    <string name="toolbar_usage">AppCompat/Toolbar/Toolbar as Action Bar</string>
+    <string name="toolbar_display_options">AppCompat/Toolbar/Toolbar Display Options</string>
+    <string name="toolbar_fragment_pager">AppCompat/Toolbar/Toolbar Fragment ViewPager</string>
 
     <string name="sample_media_route_provider_remote">Remote Playback (Simulated)</string>
     <string name="sample_media_route_activity_local">Local Playback</string>
@@ -147,6 +151,7 @@
     <string name="card_view_radius">Radius</string>
     <string name="card_view_width">Width</string>
     <string name="card_view_height">Height</string>
+    <string name="card_view_bg_color">Background</string>
     <string name="card_view_elevation">Elevation</string>
     <string name="card_view_max_elevation">Max Elevation</string>
     <string name="card_view_alpha">Alpha</string>
@@ -156,5 +161,6 @@
 
     <string name="palette">Palette</string>
     <string name="palette_all_colors">Full color palette</string>
+    <string name="search_hint">Search...</string>
 
 </resources>
diff --git a/samples/Support7Demos/res/values/styles.xml b/samples/Support7Demos/res/values/styles.xml
new file mode 100644
index 0000000..f085fa5
--- /dev/null
+++ b/samples/Support7Demos/res/values/styles.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<resources>
+
+    <style name="Theme.Custom" parent="Theme.AppCompat.Light.DarkActionBar">
+        <item name="colorPrimary">#ff00bcd4</item>
+        <item name="colorPrimaryDark">#00838f</item>
+        <item name="colorAccent">#ffff00</item>
+    </style>
+
+    <style name="Theme.Custom.NoActionBar" parent="Theme.AppCompat.Light.NoActionBar">
+        <item name="colorPrimary">#ff00bcd4</item>
+        <item name="colorPrimaryDark">#00838f</item>
+        <item name="colorAccent">#ffff00</item>
+    </style>
+
+</resources>
\ No newline at end of file
diff --git a/samples/Support7Demos/res/xml/searchable.xml b/samples/Support7Demos/res/xml/searchable.xml
new file mode 100644
index 0000000..7f0fa74
--- /dev/null
+++ b/samples/Support7Demos/res/xml/searchable.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     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.
+-->
+
+<searchable xmlns:android="http://schemas.android.com/apk/res/android"
+            android:label="@string/activity_sample_code"
+            android:hint="@string/search_hint"
+            android:searchSuggestAuthority="com.example.android.supportv7.RecentSuggestionsProvider"
+            android:searchSuggestSelection=" ?" />
\ No newline at end of file
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/app/ActionBarDisplayOptions.java b/samples/Support7Demos/src/com/example/android/supportv7/app/ActionBarDisplayOptions.java
index b7b25e8..ebda999 100644
--- a/samples/Support7Demos/src/com/example/android/supportv7/app/ActionBarDisplayOptions.java
+++ b/samples/Support7Demos/src/com/example/android/supportv7/app/ActionBarDisplayOptions.java
@@ -15,6 +15,8 @@
  */
 package com.example.android.supportv7.app;
 
+import com.example.android.supportv7.R;
+
 import android.os.Bundle;
 import android.support.v4.app.FragmentTransaction;
 import android.support.v7.app.ActionBar;
@@ -24,8 +26,8 @@
 import android.view.Menu;
 import android.view.View;
 import android.view.ViewGroup.LayoutParams;
-
-import com.example.android.supportv7.R;
+import android.widget.ArrayAdapter;
+import android.widget.Toast;
 
 /**
  * This demo shows how various action bar display option flags can be combined and their effects.
@@ -59,6 +61,21 @@
         bar.addTab(bar.newTab().setText("Tab 1").setTabListener(this));
         bar.addTab(bar.newTab().setText("Tab 2").setTabListener(this));
         bar.addTab(bar.newTab().setText("Tab 3").setTabListener(this));
+
+        final ArrayAdapter<String> listAdapter = new ArrayAdapter<String>(bar.getThemedContext(),
+                R.layout.support_simple_spinner_dropdown_item,
+                new String[] { "Item 1", "Item 2", "Item 3" });
+        bar.setListNavigationCallbacks(listAdapter, new ActionBar.OnNavigationListener() {
+            @Override
+            public boolean onNavigationItemSelected(int itemPosition, long itemId) {
+                Toast.makeText(ActionBarDisplayOptions.this,
+                        listAdapter.getItem(itemPosition),
+                        Toast.LENGTH_SHORT).show();
+                return true;
+            }
+        });
+
+        bar.setLogo(R.drawable.ic_media_play);
     }
 
     @Override
@@ -94,10 +111,17 @@
                 flags = ActionBar.DISPLAY_SHOW_CUSTOM;
                 break;
             case R.id.toggle_navigation:
-                bar.setNavigationMode(
-                        bar.getNavigationMode() == ActionBar.NAVIGATION_MODE_STANDARD
-                                ? ActionBar.NAVIGATION_MODE_TABS
-                                : ActionBar.NAVIGATION_MODE_STANDARD);
+                switch (bar.getNavigationMode()) {
+                    case ActionBar.NAVIGATION_MODE_STANDARD:
+                        bar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
+                        break;
+                    case ActionBar.NAVIGATION_MODE_TABS:
+                        bar.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST);
+                        break;
+                    case ActionBar.NAVIGATION_MODE_LIST:
+                        bar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
+                        break;
+                }
                 return;
             case R.id.cycle_custom_gravity: {
                 ActionBar.LayoutParams lp = mCustomViewLayoutParams;
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/app/ActionBarTabs.java b/samples/Support7Demos/src/com/example/android/supportv7/app/ActionBarTabs.java
index aaa916c..4bfea50 100644
--- a/samples/Support7Demos/src/com/example/android/supportv7/app/ActionBarTabs.java
+++ b/samples/Support7Demos/src/com/example/android/supportv7/app/ActionBarTabs.java
@@ -36,7 +36,6 @@
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-
         setContentView(R.layout.action_bar_tabs);
     }
 
@@ -61,10 +60,8 @@
 
         if (bar.getNavigationMode() == ActionBar.NAVIGATION_MODE_TABS) {
             bar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
-            bar.setDisplayOptions(ActionBar.DISPLAY_SHOW_TITLE, ActionBar.DISPLAY_SHOW_TITLE);
         } else {
             bar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
-            bar.setDisplayOptions(0, ActionBar.DISPLAY_SHOW_TITLE);
         }
     }
 
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/app/ActionBarUsage.java b/samples/Support7Demos/src/com/example/android/supportv7/app/ActionBarUsage.java
index 6ed59fb..f8c29ca 100644
--- a/samples/Support7Demos/src/com/example/android/supportv7/app/ActionBarUsage.java
+++ b/samples/Support7Demos/src/com/example/android/supportv7/app/ActionBarUsage.java
@@ -67,14 +67,19 @@
 
     @Override
     public boolean onOptionsItemSelected(MenuItem item) {
+        switch (item.getItemId()) {
+            case R.id.action_sort_alpha:
+            case R.id.action_sort_size:
+                onSort(item);
+                break;
+        }
+
         Toast.makeText(this, "Selected Item: " + item.getTitle(), Toast.LENGTH_SHORT).show();
+
         return true;
     }
 
-    // This method is specified as an onClick handler in the menu xml and will
-    // take precedence over the Activity's onOptionsItemSelected method.
-    // See res/menu/actions.xml for more info.
-    public void onSort(MenuItem item) {
+    private void onSort(MenuItem item) {
         mSortMode = item.getItemId();
         // Request a call to onPrepareOptionsMenu so we can change the sort icon
         supportInvalidateOptionsMenu();
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/app/RecentSuggestionsProvider.java b/samples/Support7Demos/src/com/example/android/supportv7/app/RecentSuggestionsProvider.java
new file mode 100644
index 0000000..8d6666d
--- /dev/null
+++ b/samples/Support7Demos/src/com/example/android/supportv7/app/RecentSuggestionsProvider.java
@@ -0,0 +1,28 @@
+/*
+ * 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.supportv7.app;
+
+import android.content.SearchRecentSuggestionsProvider;
+
+public class RecentSuggestionsProvider extends SearchRecentSuggestionsProvider {
+    public final static String AUTHORITY = "com.example.android.supportv7.RecentSuggestionsProvider";
+    public final static int MODE = DATABASE_MODE_QUERIES;
+
+    public RecentSuggestionsProvider() {
+        setupSuggestions(AUTHORITY, MODE);
+    }
+}
\ No newline at end of file
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/app/SearchActivity.java b/samples/Support7Demos/src/com/example/android/supportv7/app/SearchActivity.java
new file mode 100644
index 0000000..622516f
--- /dev/null
+++ b/samples/Support7Demos/src/com/example/android/supportv7/app/SearchActivity.java
@@ -0,0 +1,45 @@
+/*
+ * 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.supportv7.app;
+
+import android.app.Activity;
+import android.app.SearchManager;
+import android.content.Intent;
+import android.os.Bundle;
+import android.provider.SearchRecentSuggestions;
+
+/**
+ * An Activity which is only used for recieving ACTION_SEARCH intents, saving any queries
+ * to our SearchRecentSuggestions so that SearchView's can display suggestions.
+ */
+public class SearchActivity extends Activity {
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        // Get the intent, verify the action and get the query
+        Intent intent = getIntent();
+        if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
+            String query = intent.getStringExtra(SearchManager.QUERY);
+            SearchRecentSuggestions suggestions = new SearchRecentSuggestions(this,
+                    RecentSuggestionsProvider.AUTHORITY, RecentSuggestionsProvider.MODE);
+            suggestions.saveRecentQuery(query, null);
+            finish();
+        }
+    }
+}
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/app/ToolbarDisplayOptions.java b/samples/Support7Demos/src/com/example/android/supportv7/app/ToolbarDisplayOptions.java
new file mode 100644
index 0000000..f5c3d75
--- /dev/null
+++ b/samples/Support7Demos/src/com/example/android/supportv7/app/ToolbarDisplayOptions.java
@@ -0,0 +1,129 @@
+/*
+ * 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.supportv7.app;
+
+import com.example.android.supportv7.R;
+
+import android.os.Bundle;
+import android.support.v4.app.FragmentTransaction;
+import android.support.v7.app.ActionBar;
+import android.support.v7.app.ActionBar.Tab;
+import android.support.v7.app.ActionBarActivity;
+import android.support.v7.widget.Toolbar;
+import android.view.Gravity;
+import android.view.Menu;
+import android.view.View;
+import android.view.ViewGroup.LayoutParams;
+import android.widget.ArrayAdapter;
+import android.widget.Toast;
+
+/**
+ * This demo shows how various action bar display option flags can be combined and their effects
+ * when used on a Toolbar-provided Action Bar
+ */
+public class ToolbarDisplayOptions extends ActionBarActivity
+        implements View.OnClickListener {
+
+    private View mCustomView;
+    private ActionBar.LayoutParams mCustomViewLayoutParams;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.toolbar_display_options);
+
+        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
+        setSupportActionBar(toolbar);
+
+        findViewById(R.id.toggle_home_as_up).setOnClickListener(this);
+        findViewById(R.id.toggle_show_home).setOnClickListener(this);
+        findViewById(R.id.toggle_use_logo).setOnClickListener(this);
+        findViewById(R.id.toggle_show_title).setOnClickListener(this);
+        findViewById(R.id.toggle_show_custom).setOnClickListener(this);
+        findViewById(R.id.cycle_custom_gravity).setOnClickListener(this);
+        findViewById(R.id.toggle_visibility).setOnClickListener(this);
+
+        // Configure several action bar elements that will be toggled by display options.
+        mCustomView = getLayoutInflater().inflate(R.layout.action_bar_display_options_custom, null);
+        mCustomViewLayoutParams = new ActionBar.LayoutParams(
+                LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
+    }
+
+    @Override
+    public boolean onCreateOptionsMenu(Menu menu) {
+        getMenuInflater().inflate(R.menu.display_options_actions, menu);
+        return true;
+    }
+
+    @Override
+    public boolean onSupportNavigateUp() {
+        finish();
+        return true;
+    }
+
+    @Override
+    public void onClick(View v) {
+        final ActionBar bar = getSupportActionBar();
+        int flags = 0;
+        switch (v.getId()) {
+            case R.id.toggle_home_as_up:
+                flags = ActionBar.DISPLAY_HOME_AS_UP;
+                break;
+            case R.id.toggle_show_home:
+                flags = ActionBar.DISPLAY_SHOW_HOME;
+                break;
+            case R.id.toggle_use_logo:
+                flags = ActionBar.DISPLAY_USE_LOGO;
+                getSupportActionBar().setLogo(R.drawable.ic_media_play);
+                break;
+            case R.id.toggle_show_title:
+                flags = ActionBar.DISPLAY_SHOW_TITLE;
+                break;
+            case R.id.toggle_show_custom:
+                flags = ActionBar.DISPLAY_SHOW_CUSTOM;
+                break;
+            case R.id.cycle_custom_gravity: {
+                ActionBar.LayoutParams lp = mCustomViewLayoutParams;
+                int newGravity = 0;
+                switch (lp.gravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
+                    case Gravity.LEFT:
+                        newGravity = Gravity.CENTER_HORIZONTAL;
+                        break;
+                    case Gravity.CENTER_HORIZONTAL:
+                        newGravity = Gravity.RIGHT;
+                        break;
+                    case Gravity.RIGHT:
+                        newGravity = Gravity.LEFT;
+                        break;
+                }
+                lp.gravity = lp.gravity & ~Gravity.HORIZONTAL_GRAVITY_MASK | newGravity;
+                bar.setCustomView(mCustomView, lp);
+                return;
+            }
+            case R.id.toggle_visibility:
+                if (bar.isShowing()) {
+                    bar.hide();
+                } else {
+                    bar.show();
+                }
+                return;
+        }
+
+        int change = bar.getDisplayOptions() ^ flags;
+        bar.setDisplayOptions(change, flags);
+    }
+}
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/app/ToolbarFragmentPagerMenu.java b/samples/Support7Demos/src/com/example/android/supportv7/app/ToolbarFragmentPagerMenu.java
new file mode 100644
index 0000000..9b57933
--- /dev/null
+++ b/samples/Support7Demos/src/com/example/android/supportv7/app/ToolbarFragmentPagerMenu.java
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.supportv7.app;
+
+import com.example.android.supportv7.R;
+
+import android.os.Bundle;
+import android.support.annotation.Nullable;
+import android.support.v4.app.Fragment;
+import android.support.v4.app.FragmentManager;
+import android.support.v4.app.FragmentPagerAdapter;
+import android.support.v4.app.FragmentTransaction;
+import android.support.v4.view.MenuItemCompat;
+import android.support.v4.view.ViewPager;
+import android.support.v7.app.ActionBarActivity;
+import android.support.v7.widget.Toolbar;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.ViewGroup;
+import android.widget.CheckBox;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Demonstrates how fragments can participate in the options menu from within a {@link ViewPager}.
+ */
+public class ToolbarFragmentPagerMenu extends ActionBarActivity {
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.toolbar_fragment_pager);
+
+        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
+        setSupportActionBar(toolbar);
+
+        ViewPager vp = (ViewPager) findViewById(R.id.viewpager);
+        PagerAdapter adapter = new PagerAdapter(getSupportFragmentManager(),
+                new MenuFragment(), new Menu2Fragment());
+        vp.setAdapter(adapter);
+    }
+
+    private static class PagerAdapter extends FragmentPagerAdapter {
+        private final List<Fragment> mFragments;
+
+        public PagerAdapter(FragmentManager fm, Fragment... fragments) {
+            super(fm);
+
+            mFragments = new ArrayList<Fragment>();
+            for (Fragment fragment : fragments) {
+                mFragments.add(fragment);
+            }
+        }
+
+        @Override
+        public Fragment getItem(int position) {
+            return mFragments.get(position);
+        }
+
+        @Override
+        public int getCount() {
+            return mFragments.size();
+        }
+    }
+
+    /**
+     * A fragment that displays a menu.  This fragment happens to not
+     * have a UI (it does not implement onCreateView), but it could also
+     * have one if it wanted.
+     */
+    public static class MenuFragment extends Fragment {
+        @Override
+        public void onCreate(Bundle savedInstanceState) {
+            super.onCreate(savedInstanceState);
+            setHasOptionsMenu(true);
+        }
+
+        @Override
+        public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+            MenuItemCompat.setShowAsAction(menu.add("Menu 1a"), MenuItemCompat.SHOW_AS_ACTION_IF_ROOM);
+            MenuItemCompat.setShowAsAction(menu.add("Menu 1b"), MenuItemCompat.SHOW_AS_ACTION_NEVER);
+            super.onCreateOptionsMenu(menu, inflater);
+        }
+
+        @Override
+        public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
+                @Nullable Bundle savedInstanceState) {
+            TextView textView = new TextView(container.getContext());
+
+            textView.setText(getClass().getSimpleName());
+            textView.setGravity(Gravity.CENTER);
+            textView.setLayoutParams(new ViewGroup.LayoutParams(
+                    ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
+
+            return textView;
+        }
+
+        @Override
+        public boolean onOptionsItemSelected(MenuItem item) {
+            if (item.getTitle().equals("Menu 1a")) {
+                Toast.makeText(getActivity(), "Selected Menu 1a.", Toast.LENGTH_SHORT).show();
+                return true;
+            }
+            if (item.getTitle().equals("Menu 1b")) {
+                Toast.makeText(getActivity(), "Selected Menu 1b.", Toast.LENGTH_SHORT).show();
+                return true;
+            }
+            return super.onOptionsItemSelected(item);
+        }
+    }
+
+    /**
+     * Second fragment with a menu.
+     */
+    public static class Menu2Fragment extends Fragment {
+        @Override
+        public void onCreate(Bundle savedInstanceState) {
+            super.onCreate(savedInstanceState);
+            setHasOptionsMenu(true);
+        }
+
+        @Override
+        public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+            MenuItemCompat.setShowAsAction(menu.add("Menu 2"), MenuItemCompat.SHOW_AS_ACTION_IF_ROOM);
+        }
+
+        @Override
+        public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
+                @Nullable Bundle savedInstanceState) {
+            TextView textView = new TextView(container.getContext());
+
+            textView.setText(getClass().getSimpleName());
+            textView.setGravity(Gravity.CENTER);
+            textView.setLayoutParams(new ViewGroup.LayoutParams(
+                    ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
+
+            return textView;
+        }
+
+        @Override
+        public boolean onOptionsItemSelected(MenuItem item) {
+            if (item.getTitle().equals("Menu 2")) {
+                Toast.makeText(getActivity(), "Selected Menu 2.", Toast.LENGTH_SHORT).show();
+                return true;
+            }
+            return false;
+        }
+    }
+}
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/app/ToolbarUsage.java b/samples/Support7Demos/src/com/example/android/supportv7/app/ToolbarUsage.java
new file mode 100644
index 0000000..f5ac03b
--- /dev/null
+++ b/samples/Support7Demos/src/com/example/android/supportv7/app/ToolbarUsage.java
@@ -0,0 +1,80 @@
+/*
+ * 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.supportv7.app;
+
+import com.example.android.supportv7.R;
+
+import android.app.SearchManager;
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.os.Handler;
+import android.support.annotation.Nullable;
+import android.support.v4.app.Fragment;
+import android.support.v4.view.MenuItemCompat;
+import android.support.v7.app.ActionBarActivity;
+import android.support.v7.view.ActionMode;
+import android.support.v7.widget.PopupMenu;
+import android.support.v7.widget.SearchView;
+import android.support.v7.widget.Toolbar;
+import android.text.TextUtils;
+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.Button;
+import android.widget.TextView;
+import android.widget.Toast;
+
+/**
+ * This demonstrates idiomatic usage of the Toolbar as the action bar.
+ */
+public class ToolbarUsage extends ActionBarActivity {
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.toolbar_usage);
+
+        // Retrieve the Toolbar from our content view, and set it as the action bar
+        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
+        setSupportActionBar(toolbar);
+    }
+
+    @Override
+    public boolean onCreateOptionsMenu(Menu menu) {
+        MenuInflater inflater = getMenuInflater();
+        inflater.inflate(R.menu.actions, menu);
+
+        // Retrieve the SearchView and plug it into SearchManager
+        final SearchView searchView = (SearchView) MenuItemCompat
+                .getActionView(menu.findItem(R.id.action_search));
+
+        SearchManager searchManager = (SearchManager) getSystemService(SEARCH_SERVICE);
+        searchView.setSearchableInfo(searchManager.getSearchableInfo(getComponentName()));
+
+        return true;
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        Toast.makeText(this, "Selected Item: " + item.getTitle(), Toast.LENGTH_SHORT).show();
+        return true;
+    }
+
+}
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/media/LocalPlayer.java b/samples/Support7Demos/src/com/example/android/supportv7/media/LocalPlayer.java
index 806df25..b3c14c2 100644
--- a/samples/Support7Demos/src/com/example/android/supportv7/media/LocalPlayer.java
+++ b/samples/Support7Demos/src/com/example/android/supportv7/media/LocalPlayer.java
@@ -28,6 +28,7 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.SystemClock;
+import android.support.v4.media.session.MediaSessionCompat;
 import android.support.v7.media.MediaRouter.RouteInfo;
 import android.support.v7.media.MediaItemStatus;
 import android.util.Log;
@@ -56,12 +57,6 @@
     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;
@@ -109,6 +104,11 @@
         }
     }
 
+    @Override
+    public MediaSessionCompat getMediaSession() {
+        return mMediaSession;
+    }
+
     // Player
     @Override
     public void play(final PlaylistItem item) {
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/media/Player.java b/samples/Support7Demos/src/com/example/android/supportv7/media/Player.java
index 32b1285..fcab57d 100644
--- a/samples/Support7Demos/src/com/example/android/supportv7/media/Player.java
+++ b/samples/Support7Demos/src/com/example/android/supportv7/media/Player.java
@@ -16,11 +16,17 @@
 
 package com.example.android.supportv7.media;
 
-import android.net.Uri;
+import android.app.PendingIntent;
+import android.content.ComponentName;
 import android.content.Context;
+import android.content.Intent;
 import android.graphics.Bitmap;
+import android.support.v4.media.MediaMetadataCompat;
+import android.support.v4.media.session.MediaSessionCompat;
+import android.support.v4.media.session.PlaybackStateCompat;
 import android.support.v7.media.MediaControlIntent;
 import android.support.v7.media.MediaRouter.RouteInfo;
+import android.util.Log;
 
 /**
  * Abstraction of common playback operations of media items, such as play,
@@ -28,7 +34,18 @@
  * of media items.
  */
 public abstract class Player {
+    private static final String TAG = "SampleMediaRoutePlayer";
+    protected static final int STATE_IDLE = 0;
+    protected static final int STATE_PLAY_PENDING = 1;
+    protected static final int STATE_READY = 2;
+    protected static final int STATE_PLAYING = 3;
+    protected static final int STATE_PAUSED = 4;
+
+    private static final long PLAYBACK_ACTIONS = PlaybackStateCompat.ACTION_PAUSE
+            | PlaybackStateCompat.ACTION_PLAY;
+
     protected Callback mCallback;
+    protected MediaSessionCompat mMediaSession;
 
     public abstract boolean isRemotePlayback();
     public abstract boolean isQueuingSupported();
@@ -61,7 +78,7 @@
         mCallback = callback;
     }
 
-    public static Player create(Context context, RouteInfo route) {
+    public static Player create(Context context, RouteInfo route, MediaSessionCompat session) {
         Player player;
         if (route != null && route.supportsControlCategory(
                 MediaControlIntent.CATEGORY_REMOTE_PLAYBACK)) {
@@ -71,10 +88,62 @@
         } else {
             player = new LocalPlayer.OverlayPlayer(context);
         }
+        player.initMediaSession(session);
         player.connect(route);
         return player;
     }
 
+    public MediaSessionCompat getMediaSession() {
+        return mMediaSession;
+    }
+
+    protected void updateMetadata() {
+        if (mMediaSession == null) {
+            return;
+        }
+        MediaMetadataCompat.Builder bob = new MediaMetadataCompat.Builder();
+        bob.putString(MediaMetadataCompat.METADATA_KEY_DISPLAY_TITLE, getDescription());
+        bob.putString(MediaMetadataCompat.METADATA_KEY_DISPLAY_SUBTITLE, "Subtitle of the thing");
+        bob.putString(MediaMetadataCompat.METADATA_KEY_DISPLAY_DESCRIPTION,
+                "Description of the thing");
+        bob.putBitmap(MediaMetadataCompat.METADATA_KEY_DISPLAY_ICON, getSnapshot());
+        mMediaSession.setMetadata(bob.build());
+    }
+
+    protected void publishState(int state) {
+        if (mMediaSession == null) {
+            return;
+        }
+        PlaybackStateCompat.Builder bob = new PlaybackStateCompat.Builder();
+        bob.setActions(PLAYBACK_ACTIONS);
+        switch (state) {
+            case STATE_PLAYING:
+                bob.setState(PlaybackStateCompat.STATE_PLAYING, -1, 1);
+                break;
+            case STATE_READY:
+            case STATE_PAUSED:
+                bob.setState(PlaybackStateCompat.STATE_PAUSED, -1, 0);
+                break;
+            case STATE_IDLE:
+                bob.setState(PlaybackStateCompat.STATE_STOPPED, -1, 0);
+                break;
+        }
+        PlaybackStateCompat pbState = bob.build();
+        Log.d(TAG, "Setting state to " + pbState);
+        mMediaSession.setPlaybackState(pbState);
+        if (state != STATE_IDLE) {
+            mMediaSession.setActive(true);
+        } else {
+            mMediaSession.setActive(false);
+        }
+    }
+
+    private void initMediaSession(MediaSessionCompat session) {
+        mMediaSession = session;
+        updateMetadata();
+    }
+
+
     public interface Callback {
         void onError();
         void onCompletion();
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/media/RemotePlayer.java b/samples/Support7Demos/src/com/example/android/supportv7/media/RemotePlayer.java
index 5020c37..d47c260 100644
--- a/samples/Support7Demos/src/com/example/android/supportv7/media/RemotePlayer.java
+++ b/samples/Support7Demos/src/com/example/android/supportv7/media/RemotePlayer.java
@@ -140,6 +140,9 @@
                 }
                 if (item.getState() == MediaItemStatus.PLAYBACK_STATE_PAUSED) {
                     pause();
+                    publishState(STATE_PAUSED);
+                } else {
+                    publishState(STATE_PLAYING);
                 }
                 if (mCallback != null) {
                     mCallback.onPlaylistChanged();
@@ -214,6 +217,7 @@
                 if (mCallback != null) {
                     mCallback.onPlaylistChanged();
                 }
+                publishState(STATE_PAUSED);
             }
 
             @Override
@@ -239,6 +243,7 @@
                 if (mCallback != null) {
                     mCallback.onPlaylistChanged();
                 }
+                publishState(STATE_PLAYING);
             }
 
             @Override
@@ -254,6 +259,7 @@
             // ignore if no session
             return;
         }
+        publishState(STATE_IDLE);
         if (DEBUG) {
             Log.d(TAG, "stop");
         }
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/media/SampleMediaRouteControllerDialog.java b/samples/Support7Demos/src/com/example/android/supportv7/media/SampleMediaRouteControllerDialog.java
deleted file mode 100644
index a2cacc3..0000000
--- a/samples/Support7Demos/src/com/example/android/supportv7/media/SampleMediaRouteControllerDialog.java
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * 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.supportv7.media;
-
-import com.example.android.supportv7.R;
-
-import android.app.Dialog;
-import android.content.Context;
-import android.content.Intent;
-import android.graphics.Bitmap;
-import android.os.Bundle;
-import android.support.v7.app.MediaRouteControllerDialog;
-import android.support.v7.media.MediaRouteSelector;
-import android.support.v7.media.MediaRouter;
-import android.util.Log;
-import android.view.KeyEvent;
-import android.view.MotionEvent;
-import android.view.View;
-import android.widget.ImageButton;
-import android.widget.ImageView;
-import android.widget.LinearLayout;
-import android.widget.TextView;
-
-/**
- * This class serves as an example on how to customize the media router control
- * dialog. It is derived from the standard MediaRouteControllerDialog with the
- * following overrides:
- *
- *   1. Shows thumbnail/snapshot of the current item
- *
- *   2. For variable volume routes, only allow volume control via Volume Up/Down
- *      keys (to prevent accidental tapping on the volume adjust seekbar that sets
- *      volume to maximum)
- *
- *   3. Provides transport control buttons (play/pause, stop)
- */
-public class SampleMediaRouteControllerDialog extends MediaRouteControllerDialog {
-    private static final String TAG = "SampleMediaRouteControllerDialog";
-    private final SampleMediaRouterActivity mActivity;
-    private final SessionManager mSessionManager;
-    private final Player mPlayer;
-    private ImageButton mPauseResumeButton;
-    private ImageButton mStopButton;
-    private ImageView mThumbnail;
-    private TextView mTextView;
-    private LinearLayout mInfoLayout;
-    private LinearLayout mVolumeLayout;
-
-    public SampleMediaRouteControllerDialog(Context context,
-            SessionManager manager, Player player) {
-        super(context);
-        mActivity = (SampleMediaRouterActivity) context;
-        mSessionManager = manager;
-        mPlayer = player;
-    }
-
-    @Override
-    public View onCreateMediaControlView(Bundle savedInstanceState) {
-        // Thumbnail and Track info
-        View v = getLayoutInflater().inflate(R.layout.sample_media_controller, null);
-        mInfoLayout = (LinearLayout)v.findViewById(R.id.media_route_info);
-        mTextView = (TextView)v.findViewById(R.id.track_info);
-        mThumbnail = (ImageView)v.findViewById(R.id.snapshot);
-
-        // Transport controls
-        mPauseResumeButton = (ImageButton)v.findViewById(R.id.pause_resume_button);
-        mPauseResumeButton.setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                if (mActivity != null) {
-                    mActivity.handleMediaKey(new KeyEvent(KeyEvent.ACTION_DOWN,
-                        KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE));
-                }
-            }
-        });
-
-        mStopButton = (ImageButton)v.findViewById(R.id.stop_button);
-        mStopButton.setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                if (mActivity != null) {
-                    mActivity.handleMediaKey(new KeyEvent(KeyEvent.ACTION_DOWN,
-                        KeyEvent.KEYCODE_MEDIA_STOP));
-                }
-            }
-        });
-
-        // update session status (will callback to updateUi at the end)
-        mSessionManager.updateStatus();
-        return v;
-    }
-
-    public void updateUi() {
-        String trackInfo = mPlayer.getDescription();
-        Bitmap snapshot = mPlayer.getSnapshot();
-        if (mPlayer.isRemotePlayback() && !trackInfo.isEmpty() && snapshot != null) {
-            mInfoLayout.setVisibility(View.VISIBLE);
-            mThumbnail.setImageBitmap(snapshot);
-            mTextView.setText(trackInfo);
-        } else {
-            mInfoLayout.setVisibility(View.GONE);
-        }
-        // show pause or resume icon depending on current state
-        mPauseResumeButton.setImageResource(mSessionManager.isPaused() ?
-                R.drawable.ic_media_play : R.drawable.ic_media_pause);
-    }
-}
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/media/SampleMediaRouteProvider.java b/samples/Support7Demos/src/com/example/android/supportv7/media/SampleMediaRouteProvider.java
index 8a20564..15cf19b 100644
--- a/samples/Support7Demos/src/com/example/android/supportv7/media/SampleMediaRouteProvider.java
+++ b/samples/Support7Demos/src/com/example/android/supportv7/media/SampleMediaRouteProvider.java
@@ -22,6 +22,7 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.IntentFilter.MalformedMimeTypeException;
+import android.content.IntentSender;
 import android.content.res.Resources;
 import android.graphics.Bitmap;
 import android.media.AudioManager;
@@ -173,6 +174,10 @@
 
     private void publishRoutes() {
         Resources r = getContext().getResources();
+        Intent settingsIntent = new Intent(Intent.ACTION_MAIN);
+        settingsIntent.setClass(getContext(), SampleMediaRouteSettingsActivity.class);
+        IntentSender is = PendingIntent.getActivity(getContext(), 99, settingsIntent,
+                Intent.FLAG_ACTIVITY_NEW_TASK).getIntentSender();
 
         MediaRouteDescriptor routeDescriptor1 = new MediaRouteDescriptor.Builder(
                 FIXED_VOLUME_ROUTE_ID,
@@ -183,6 +188,8 @@
                 .setPlaybackType(MediaRouter.RouteInfo.PLAYBACK_TYPE_REMOTE)
                 .setVolumeHandling(MediaRouter.RouteInfo.PLAYBACK_VOLUME_FIXED)
                 .setVolume(VOLUME_MAX)
+                .setCanDisconnect(true)
+                .setSettingsActivity(is)
                 .build();
 
         MediaRouteDescriptor routeDescriptor2 = new MediaRouteDescriptor.Builder(
@@ -195,6 +202,7 @@
                 .setVolumeHandling(MediaRouter.RouteInfo.PLAYBACK_VOLUME_VARIABLE)
                 .setVolumeMax(VOLUME_MAX)
                 .setVolume(mVolume)
+                .setSettingsActivity(is)
                 .build();
 
         MediaRouteDescriptor routeDescriptor3 = new MediaRouteDescriptor.Builder(
@@ -207,6 +215,7 @@
                 .setVolumeHandling(MediaRouter.RouteInfo.PLAYBACK_VOLUME_VARIABLE)
                 .setVolumeMax(VOLUME_MAX)
                 .setVolume(mVolume)
+                .setCanDisconnect(true)
                 .build();
 
         MediaRouteDescriptor routeDescriptor4 = new MediaRouteDescriptor.Builder(
@@ -239,7 +248,7 @@
 
         public SampleRouteController(String routeId) {
             mRouteId = routeId;
-            mPlayer = Player.create(getContext(), null);
+            mPlayer = Player.create(getContext(), null, null);
             mSessionManager.setPlayer(mPlayer);
             mSessionManager.setCallback(new SessionManager.Callback() {
                 @Override
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/media/SampleMediaRouteSettingsActivity.java b/samples/Support7Demos/src/com/example/android/supportv7/media/SampleMediaRouteSettingsActivity.java
new file mode 100644
index 0000000..a1d07fb
--- /dev/null
+++ b/samples/Support7Demos/src/com/example/android/supportv7/media/SampleMediaRouteSettingsActivity.java
@@ -0,0 +1,27 @@
+/*
+ * 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.supportv7.media;
+
+import android.support.v7.app.ActionBarActivity;
+
+/**
+ * This activity is a dummy settings activity for the
+ * {@link SampleMediaRouteProvider}.
+ */
+public class SampleMediaRouteSettingsActivity extends ActionBarActivity {
+
+}
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/media/SampleMediaRouterActivity.java b/samples/Support7Demos/src/com/example/android/supportv7/media/SampleMediaRouterActivity.java
index dfa1416..ba19499 100644
--- a/samples/Support7Demos/src/com/example/android/supportv7/media/SampleMediaRouterActivity.java
+++ b/samples/Support7Demos/src/com/example/android/supportv7/media/SampleMediaRouterActivity.java
@@ -20,6 +20,7 @@
 
 import android.content.ComponentName;
 import android.content.Context;
+import android.content.DialogInterface;
 import android.content.Intent;
 import android.content.res.Resources;
 import android.app.PendingIntent;
@@ -34,9 +35,11 @@
 import android.os.Bundle;
 import android.os.SystemClock;
 import android.support.v4.app.FragmentManager;
+import android.support.v4.media.session.MediaSessionCompat;
 import android.support.v4.view.MenuItemCompat;
 import android.support.v7.app.ActionBarActivity;
 import android.support.v7.app.MediaRouteActionProvider;
+import android.support.v7.app.MediaRouteButton;
 import android.support.v7.app.MediaRouteControllerDialog;
 import android.support.v7.app.MediaRouteControllerDialogFragment;
 import android.support.v7.app.MediaRouteDiscoveryFragment;
@@ -66,6 +69,7 @@
 import android.widget.TabHost.OnTabChangeListener;
 import android.widget.SeekBar;
 import android.widget.SeekBar.OnSeekBarChangeListener;
+
 import java.io.File;
 
 /**
@@ -93,7 +97,6 @@
     private SeekBar mSeekBar;
     private boolean mNeedResume;
     private boolean mSeeking;
-    private SampleMediaRouteControllerDialog mControllerDialog;
 
     private final Handler mHandler = new Handler();
     private final Runnable mUpdateSeekRunnable = new Runnable() {
@@ -130,19 +133,18 @@
         public void onRouteSelected(MediaRouter router, RouteInfo route) {
             Log.d(TAG, "onRouteSelected: route=" + route);
 
-            mPlayer = Player.create(SampleMediaRouterActivity.this, route);
+            mPlayer = Player.create(SampleMediaRouterActivity.this, route, mMediaSession);
             mPlayer.updatePresentation();
             mSessionManager.setPlayer(mPlayer);
             mSessionManager.unsuspend();
 
-            registerRCC();
             updateUi();
         }
 
         @Override
         public void onRouteUnselected(MediaRouter router, RouteInfo route) {
             Log.d(TAG, "onRouteUnselected: route=" + route);
-            unregisterRCC();
+            mMediaSession.setActive(false);
 
             PlaylistItem item = getCheckedPlaylistItem();
             if (item != null) {
@@ -152,7 +154,6 @@
             }
             mPlayer.updatePresentation();
             mPlayer.release();
-            mControllerDialog = null;
         }
 
         @Override
@@ -183,7 +184,7 @@
         }
     };
 
-    private RemoteControlClient mRemoteControlClient;
+    private MediaSessionCompat mMediaSession;
     private ComponentName mEventReceiver;
     private AudioManager mAudioManager;
     private PendingIntent mMediaPendingIntent;
@@ -367,11 +368,13 @@
         mMediaPendingIntent = PendingIntent.getBroadcast(this, 0, mediaButtonIntent, 0);
 
         // Create and register the remote control client
-        registerRCC();
+        createMediaSession();
+        mMediaRouter.setMediaSessionCompat(mMediaSession);
 
         // Set up playback manager and player
         mPlayer = Player.create(SampleMediaRouterActivity.this,
-                mMediaRouter.getSelectedRoute());
+                mMediaRouter.getSelectedRoute(), mMediaSession);
+
         mSessionManager.setPlayer(mPlayer);
         mSessionManager.setCallback(new SessionManager.Callback() {
             @Override
@@ -387,40 +390,42 @@
         updateUi();
     }
 
-    private void registerRCC() {
-        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(SampleMediaRouterActivity.this);
-            mRemoteControlClient.setTransportControlFlags(
-                    RemoteControlClient.FLAG_KEY_MEDIA_PLAY_PAUSE);
-            mRemoteControlClient.setPlaybackState(
-                    RemoteControlClient.PLAYSTATE_PLAYING);
-        }
-    }
+    private void createMediaSession() {
+        // Create the MediaSession
+        mMediaSession = new MediaSessionCompat(this, "SampleMediaRouter", mEventReceiver,
+                mMediaPendingIntent);
+        mMediaSession.setFlags(MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS
+                | MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS);
+        mMediaSession.setCallback(new MediaSessionCompat.Callback() {
+            @Override
+            public boolean onMediaButtonEvent(Intent mediaButtonEvent) {
+                if (mediaButtonEvent != null) {
+                    return handleMediaKey(
+                            (KeyEvent) mediaButtonEvent.getParcelableExtra(Intent.EXTRA_KEY_EVENT));
+                }
+                return super.onMediaButtonEvent(mediaButtonEvent);
+            }
 
-    private void unregisterRCC() {
-        // 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;
-        }
+            @Override
+            public void onPlay() {
+                mSessionManager.resume();
+            }
+
+            @Override
+            public void onPause() {
+                mSessionManager.pause();
+            }
+        });
+
+        SampleMediaButtonReceiver.setActivity(SampleMediaRouterActivity.this);
     }
 
     public boolean handleMediaKey(KeyEvent event) {
-        if (event.getAction() == KeyEvent.ACTION_DOWN && event.getRepeatCount() == 0) {
+        if (event != null && event.getAction() == KeyEvent.ACTION_DOWN
+                && event.getRepeatCount() == 0) {
             switch (event.getKeyCode()) {
                 case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
+                case KeyEvent.KEYCODE_HEADSETHOOK:
                 {
                     Log.d(TAG, "Received Play/Pause event from RemoteControlClient");
                     if (mSessionManager.isPaused()) {
@@ -497,11 +502,9 @@
 
     @Override
     public void onDestroy() {
-        // Unregister the remote control client
-        unregisterRCC();
-
         mSessionManager.stop();
         mPlayer.release();
+        mMediaSession.release();
         super.onDestroy();
     }
 
@@ -520,15 +523,7 @@
         mediaRouteActionProvider.setDialogFactory(new MediaRouteDialogFactory() {
             @Override
             public MediaRouteControllerDialogFragment onCreateControllerDialogFragment() {
-                return new MediaRouteControllerDialogFragment() {
-                    @Override
-                    public MediaRouteControllerDialog onCreateControllerDialog(
-                            Context context, Bundle savedInstanceState) {
-                        mControllerDialog = new SampleMediaRouteControllerDialog(
-                                context, mSessionManager, mPlayer);
-                        return mControllerDialog;
-                    }
-                };
+                return new ControllerDialogFragment(mPlayer);
             }
         });
 
@@ -564,8 +559,8 @@
         updatePlaylist();
         updateRouteDescription();
         updateButtons();
-        if (mControllerDialog != null) {
-            mControllerDialog.updateUi();
+        if (mPlayer != null) {
+            mPlayer.updateMetadata();
         }
     }
 
@@ -593,11 +588,6 @@
         // only enable seek bar when duration is known
         PlaylistItem item = getCheckedPlaylistItem();
         mSeekBar.setEnabled(item != null && item.getDuration() > 0);
-        if (mRemoteControlClient != null) {
-            mRemoteControlClient.setPlaybackState(mSessionManager.isPaused() ?
-                    RemoteControlClient.PLAYSTATE_PAUSED :
-                        RemoteControlClient.PLAYSTATE_PLAYING);
-        }
     }
 
     private PlaylistItem getCheckedPlaylistItem() {
@@ -745,4 +735,35 @@
      */
     public static class LightWithDarkActionBar extends SampleMediaRouterActivity {
     }
+
+    public static class ControllerDialogFragment extends MediaRouteControllerDialogFragment {
+        private MediaRouteControllerDialog mControllerDialog;
+        private Player mPlayer;
+
+        public ControllerDialogFragment() {
+            super();
+        }
+
+        public ControllerDialogFragment(Player player) {
+            mPlayer = player;
+        }
+
+        @Override
+        public MediaRouteControllerDialog onCreateControllerDialog(
+                Context context, Bundle savedInstanceState) {
+            mControllerDialog = super.onCreateControllerDialog(context,
+                    savedInstanceState);
+            mControllerDialog.setOnDismissListener(new DialogInterface.OnDismissListener() {
+                @Override
+                public void onDismiss(DialogInterface dialog) {
+                    mControllerDialog = null;
+                }
+            });
+            return mControllerDialog;
+        }
+
+        public void setPlayer(Player player) {
+            mPlayer = player;
+        }
+    }
 }
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/view/CardViewActivity.java b/samples/Support7Demos/src/com/example/android/supportv7/view/CardViewActivity.java
index ba4f0cb..ca0c08a 100644
--- a/samples/Support7Demos/src/com/example/android/supportv7/view/CardViewActivity.java
+++ b/samples/Support7Demos/src/com/example/android/supportv7/view/CardViewActivity.java
@@ -16,6 +16,8 @@
 package com.example.android.supportv7.view;
 
 import android.app.Activity;
+import android.graphics.drawable.ColorDrawable;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
 import android.support.v4.view.ViewCompat;
@@ -25,8 +27,11 @@
 import android.widget.RadioGroup;
 import android.widget.SeekBar;
 import android.widget.TextView;
+
 import com.example.android.supportv7.R;
 
+import java.lang.reflect.Field;
+
 public class CardViewActivity extends Activity {
 
     CardView mCardView;
@@ -84,7 +89,7 @@
             lp = setViewBounds(mInfoText);
         }
         mInfoText.setText("radius: " + mCornerRadiusSeekBar.getProgress()
-                +", alpha: " + mAlphaSeekBar.getProgress()
+                + ", alpha: " + mAlphaSeekBar.getProgress()
                 + "\n w: " + lp.width + "\nh: " + lp.height
                 + "\nelevation: " + mCardView.getCardElevation() + " of "
                 + mCardView.getMaxCardElevation());
@@ -143,15 +148,42 @@
             }
         });
 
-        update();
         new Handler().postDelayed(new Runnable() {
             @Override
             public void run() {
                 View content = findViewById(android.R.id.content);
+                mWidthSeekBar.setProgress(mCardView.getWidth());
+                mHeightSeekBar.setProgress(mCardView.getHeight());
                 mWidthSeekBar.setMax(content.getWidth());
                 mHeightSeekBar.setMax(content.getHeight());
+                update();
             }
         }, 100);
+
+        ((RadioGroup) findViewById(R.id.select_bg_color_radio))
+                .setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
+                    @Override
+                    public void onCheckedChanged(RadioGroup group, int checkedId) {
+                        mCardView.setCardBackgroundColor(
+                                getResources().getColor(getColorId(checkedId)));
+                    }
+                });
     }
 
+    private int getColorId(int id) {
+        switch (id) {
+            case R.id.yellow:
+                return R.color.card_yellow;
+            case R.id.aquatic:
+                return R.color.card_aquatic;
+            case R.id.classic:
+                return R.color.card_classic;
+            case R.id.sunbrite:
+                return R.color.card_sunbrite;
+            case R.id.tropical:
+                return R.color.card_tropical;
+            default:
+                return R.color.cardview_light_background;
+        }
+    }
 }
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/widget/AnimatedRecyclerView.java b/samples/Support7Demos/src/com/example/android/supportv7/widget/AnimatedRecyclerView.java
index 50fe1e1..4c56933 100644
--- a/samples/Support7Demos/src/com/example/android/supportv7/widget/AnimatedRecyclerView.java
+++ b/samples/Support7Demos/src/com/example/android/supportv7/widget/AnimatedRecyclerView.java
@@ -124,8 +124,12 @@
     public void itemClicked(View view) {
         ViewGroup parent = (ViewGroup) view;
         MyViewHolder holder = (MyViewHolder) mRecyclerView.getChildViewHolder(parent);
+        final int position = holder.getAdapterPosition();
+        if (position == RecyclerView.NO_POSITION) {
+            return;
+        }
         mAdapter.toggleExpanded(holder);
-        mAdapter.notifyItemChanged(holder.getPosition());
+        mAdapter.notifyItemChanged(position);
     }
 
     public void deleteItem(View view) {
@@ -240,7 +244,7 @@
                 if (lastVisibleView != null) {
                     RecyclerView.LayoutParams lastParams =
                             (RecyclerView.LayoutParams) lastVisibleView.getLayoutParams();
-                    int lastPosition = lastParams.getViewPosition();
+                    int lastPosition = lastParams.getViewLayoutPosition();
                     final List<RecyclerView.ViewHolder> previousViews = recycler.getScrapList();
                     count = previousViews.size();
                     for (int i = 0; i < count; ++i) {
@@ -250,7 +254,7 @@
                         if (params.isItemRemoved()) {
                             continue;
                         }
-                        int position = params.getViewPosition();
+                        int position = params.getViewLayoutPosition();
                         int newTop;
                         if (position < mFirstPosition) {
                             newTop = view.getHeight() * (position - mFirstPosition);
@@ -480,7 +484,7 @@
         }
 
         public void selectItem(MyViewHolder holder, boolean selected) {
-            mSelected.put((String) holder.textView.getText(), selected);
+            mSelected.put((String) holder.textView.getText().toString(), selected);
         }
 
         public void toggleExpanded(MyViewHolder holder) {
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/widget/BaseLayoutManagerActivity.java b/samples/Support7Demos/src/com/example/android/supportv7/widget/BaseLayoutManagerActivity.java
index 0a6ac6d..4bb64f4 100644
--- a/samples/Support7Demos/src/com/example/android/supportv7/widget/BaseLayoutManagerActivity.java
+++ b/samples/Support7Demos/src/com/example/android/supportv7/widget/BaseLayoutManagerActivity.java
@@ -84,11 +84,10 @@
                 vh.itemView.setOnClickListener(new View.OnClickListener() {
                     @Override
                     public void onClick(View v) {
-                        final int pos = vh.getPosition();
-                        if (pos + 1 < getItemCount()) {
+                        final int pos = vh.getAdapterPosition();
+                        if (pos != RecyclerView.NO_POSITION && pos + 1 < getItemCount()) {
                             swap(pos, pos + 1);
                         }
-                        notifyItemChanged(pos);
                     }
                 });
                 return vh;
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/widget/GridLayoutManagerActivity.java b/samples/Support7Demos/src/com/example/android/supportv7/widget/GridLayoutManagerActivity.java
index 00cfbf8..ef25c0b 100644
--- a/samples/Support7Demos/src/com/example/android/supportv7/widget/GridLayoutManagerActivity.java
+++ b/samples/Support7Demos/src/com/example/android/supportv7/widget/GridLayoutManagerActivity.java
@@ -119,11 +119,13 @@
                 vh.itemView.setOnClickListener(new View.OnClickListener() {
                     @Override
                     public void onClick(View v) {
-                        final int pos = vh.getPosition();
+                        final int pos = vh.getAdapterPosition();
+                        if (pos == RecyclerView.NO_POSITION) {
+                            return;
+                        }
                         if (pos + 1 < getItemCount()) {
                             swap(pos, pos + 1);
                         }
-                        notifyItemChanged(pos);
                     }
                 });
                 return vh;
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/widget/RecyclerViewActivity.java b/samples/Support7Demos/src/com/example/android/supportv7/widget/RecyclerViewActivity.java
index 747992b..38b50bd 100644
--- a/samples/Support7Demos/src/com/example/android/supportv7/widget/RecyclerViewActivity.java
+++ b/samples/Support7Demos/src/com/example/android/supportv7/widget/RecyclerViewActivity.java
@@ -56,7 +56,10 @@
                 vh.itemView.setOnClickListener(new View.OnClickListener() {
                     @Override
                     public void onClick(View v) {
-                        final int pos = vh.getPosition();
+                        final int pos = vh.getAdapterPosition();
+                        if (pos == RecyclerView.NO_POSITION) {
+                            return;
+                        }
                         if (pos + 1 < getItemCount()) {
                             swap(pos, pos + 1);
                         }
diff --git a/samples/SupportLeanbackDemos/AndroidManifest.xml b/samples/SupportLeanbackDemos/AndroidManifest.xml
index 95f7a2c..391bcb7 100644
--- a/samples/SupportLeanbackDemos/AndroidManifest.xml
+++ b/samples/SupportLeanbackDemos/AndroidManifest.xml
@@ -10,10 +10,12 @@
         android:label="@string/app_name"
         android:icon="@drawable/ic_launcher"
         android:banner="@drawable/ic_launcher"
+        android:supportsRtl="true"
         android:theme="@style/Theme.Example.Leanback">
 
         <activity android:name="MainActivity"
-            android:label="@string/app_name">
+            android:label="@string/app_name"
+            android:theme="@style/Theme.Example.Leanback.Browse">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="android.intent.category.LEANBACK_LAUNCHER" />
@@ -25,6 +27,11 @@
         </activity>
 
         <activity android:name="DetailsActivity"
+            android:theme="@style/Theme.Example.Leanback.Details"
+            android:exported="true" />
+
+        <activity android:name="RowsActivity"
+            android:theme="@style/Theme.Example.Leanback.Rows"
             android:exported="true" />
 
         <activity android:name="PlaybackOverlayActivity"
@@ -39,5 +46,7 @@
         <activity android:name="BrowseErrorActivity"
                   android:exported="true" />
 
+        <activity android:name="HorizontalGridTestActivity"
+            android:exported="true" />
     </application>
 </manifest>
diff --git a/samples/SupportLeanbackDemos/res/layout/horizontal_grid.xml b/samples/SupportLeanbackDemos/res/layout/horizontal_grid.xml
new file mode 100644
index 0000000..7faea03
--- /dev/null
+++ b/samples/SupportLeanbackDemos/res/layout/horizontal_grid.xml
@@ -0,0 +1,23 @@
+<RelativeLayout 
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:lb="http://schemas.android.com/apk/res-auto"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    >
+  <android.support.v17.leanback.widget.HorizontalGridView
+      android:id="@+id/gridview"
+      android:layout_width="match_parent"
+      android:layout_height="match_parent"
+      android:clipToPadding="false"
+      android:focusable="true"
+      android:focusableInTouchMode="true"
+      android:background="#00ffff"
+      lb:horizontalMargin="12dip"
+      lb:verticalMargin="24dip"
+      lb:numberOfRows="3"
+      lb:rowHeight="150dip"
+      android:paddingBottom="12dip"
+      android:paddingLeft="12dip"
+      android:paddingRight="12dip"
+      android:paddingTop="12dip" />
+</RelativeLayout>
diff --git a/samples/SupportLeanbackDemos/res/layout/rows.xml b/samples/SupportLeanbackDemos/res/layout/rows.xml
new file mode 100644
index 0000000..d77f7ca
--- /dev/null
+++ b/samples/SupportLeanbackDemos/res/layout/rows.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     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.
+-->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/rows_frame"
+    android:orientation="vertical"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+  <TextView
+      android:id="@+id/rows_title"
+      android:text="RowsFragment"
+      style="?attr/browseTitleTextStyle"
+      android:paddingStart="?attr/browsePaddingStart"
+      android:paddingEnd="?attr/browsePaddingEnd"
+      android:paddingTop="?attr/browsePaddingTop"
+      android:paddingBottom="10dp"
+      android:layout_width="match_parent"
+      android:layout_height="wrap_content" />
+  <fragment
+      android:name="com.example.android.leanback.RowsFragment"
+      android:id="@+id/main_rows_fragment"
+      android:layout_width="match_parent"
+      android:layout_height="match_parent"
+  />
+
+</FrameLayout>
diff --git a/samples/SupportLeanbackDemos/res/values/styles.xml b/samples/SupportLeanbackDemos/res/values/styles.xml
new file mode 100644
index 0000000..17ea0ef
--- /dev/null
+++ b/samples/SupportLeanbackDemos/res/values/styles.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android">
+    <style name="Widget.Example.Leanback.Title.Text" parent="Widget.Leanback.Title.Text" >
+    </style>
+    <style name="Widget.Example.Leanback.Rows.VerticalGridView" parent="Widget.Leanback.Rows.VerticalGridView">
+        <item name="android:paddingTop">96dp</item>
+    </style>
+</resources>
\ No newline at end of file
diff --git a/samples/SupportLeanbackDemos/res/values/themes.xml b/samples/SupportLeanbackDemos/res/values/themes.xml
index 121e25c..22a41f0 100644
--- a/samples/SupportLeanbackDemos/res/values/themes.xml
+++ b/samples/SupportLeanbackDemos/res/values/themes.xml
@@ -1,13 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
 <resources>
     <style name="Theme.Example.Leanback" parent="Theme.Leanback">
-<!-- uncomment to override default transition settings:
-        <item name="android:windowEnterTransition">@android:transition/fade</item>
-        <item name="android:windowExitTransition">@android:transition/fade</item>
-        <item name="android:windowSharedElementExitTransition">@android:transition/move</item>
-        <item name="android:windowSharedElementEnterTransition">@android:transition/move</item>
-        <item name="android:windowAllowExitTransitionOverlap">true</item>
-        <item name="android:windowAllowEnterTransitionOverlap">false</item>
-        <item name="android:windowContentTransitions">true</item>
- -->
+    </style>
+    <style name="Theme.Example.Leanback.Browse" parent="Theme.Leanback.Browse">
+    </style>
+    <style name="Theme.Example.Leanback.Details" parent="Theme.Leanback.Details">
+    </style>
+    <style name="Theme.Example.Leanback.Rows" parent="Theme.Leanback">
+        <item name="browseTitleTextStyle">@style/Widget.Example.Leanback.Title.Text</item>
+        <item name="rowsVerticalGridStyle">@style/Widget.Example.Leanback.Rows.VerticalGridView</item>
     </style>
 </resources>
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/BrowseAnimationFragment.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/BrowseAnimationFragment.java
index e6b92c4..3883081 100644
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/BrowseAnimationFragment.java
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/BrowseAnimationFragment.java
@@ -23,6 +23,7 @@
 import android.support.v17.leanback.widget.Row;
 import android.util.Log;
 import android.view.View;
+import android.os.Handler;
 
 import java.util.Random;
 
@@ -76,13 +77,13 @@
         mRowsAdapter = new ArrayObjectAdapter(lrp);
         for (int i = 0; i < NUM_ROWS; ++i) {
             mRowsAdapter.add(
-                    createRandomRow(new HeaderItem(i, "Row " + i, null)));
+                    createRandomRow(new HeaderItem(i, "Row " + i)));
         }
         setAdapter(mRowsAdapter);
     }
 
     Item createRandomItem() {
-        switch (sRand.nextInt(13)) {
+        switch (sRand.nextInt(15)) {
         default:
         case 0:
             return new Item("Remove Item before", new OnItemClickedListener() {
@@ -198,7 +199,7 @@
                     if (index >= 0) {
                         int headerId = sRand.nextInt();
                         mRowsAdapter.add(index, createRandomRow(new HeaderItem(
-                                headerId, "Row " + headerId, null)));
+                                headerId, "Row " + headerId)));
                     }
                 }
             });
@@ -211,7 +212,7 @@
                         int headerId = sRand.nextInt();
                         mRowsAdapter.add(
                                 index + 1, createRandomRow(new HeaderItem(
-                                        headerId, "Row " + headerId, null)));
+                                        headerId, "Row " + headerId)));
                     }
                 }
             });
@@ -242,6 +243,35 @@
                     }
                 }
             });
+        case 13:
+            return new Item("Replace Item before", new OnItemClickedListener() {
+                    @Override
+                public void onItemClicked(Object item, Row row) {
+                    ArrayObjectAdapter adapter = ((ArrayObjectAdapter) ((ListRow) row)
+                            .getAdapter());
+                    int index = adapter.indexOf(item);
+                    if (index >= 0) {
+                        if (index > 0)
+                            index--;
+                        adapter.replace(index, createRandomItem());
+                    }
+                }
+            });
+        case 14:
+            return new Item("Remove all then re-add", new OnItemClickedListener() {
+                    @Override
+                public void onItemClicked(Object item, Row row) {
+                    final ArrayObjectAdapter adapter = ((ArrayObjectAdapter) ((ListRow) row)
+                            .getAdapter());
+                   adapter.clear();
+                   new Handler().postDelayed(new Runnable() {
+                       @Override
+                       public void run() {
+                           adapter.add(0, createRandomItem());
+                       }
+                   }, 1000);
+                }
+            });
         }
     }
 
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/BrowseErrorActivity.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/BrowseErrorActivity.java
index a35ab5e..f2f6192 100644
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/BrowseErrorActivity.java
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/BrowseErrorActivity.java
@@ -50,6 +50,9 @@
         handler.postDelayed(new Runnable() {
             @Override
             public void run() {
+                if (getFragmentManager().isDestroyed()) {
+                    return;
+                }
                 getFragmentManager().beginTransaction().remove(mSpinnerFragment).commit();
                 mErrorFragment.setErrorContent(getResources());
             }
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/BrowseFragment.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/BrowseFragment.java
index abf82e3..91fec5f 100644
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/BrowseFragment.java
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/BrowseFragment.java
@@ -15,6 +15,7 @@
 
 import android.content.Intent;
 import android.os.Bundle;
+import android.os.Handler;
 import android.support.v4.app.ActivityOptionsCompat;
 import android.support.v17.leanback.widget.ArrayObjectAdapter;
 import android.support.v17.leanback.widget.HeaderItem;
@@ -33,6 +34,7 @@
 public class BrowseFragment extends android.support.v17.leanback.app.BrowseFragment {
     private static final String TAG = "leanback.BrowseFragment";
 
+    private static final boolean TEST_ENTRANCE_TRANSITION = true;
     private static final int NUM_ROWS = 10;
     private ArrayObjectAdapter mRowsAdapter;
 
@@ -62,6 +64,18 @@
                 Log.i(TAG, "onItemSelected: " + item + " row " + row);
             }
         });
+        if (TEST_ENTRANCE_TRANSITION) {
+            // don't run entrance transition if Activity is restored.
+            if (savedInstanceState == null) {
+                prepareEntranceTransition();
+            }
+            // simulate delay loading data
+            new Handler().postDelayed(new Runnable() {
+                public void run() {
+                    startEntranceTransition();
+                }
+            }, 2000);
+        }
     }
 
     private void setupRows() {
@@ -78,14 +92,14 @@
         for (int i = 0; i < NUM_ROWS; ++i) {
             ArrayObjectAdapter listRowAdapter = new ArrayObjectAdapter(cardPresenter);
             listRowAdapter.add(new PhotoItem("Hello world", R.drawable.gallery_photo_1));
-            listRowAdapter.add(new PhotoItem("This is a test", R.drawable.gallery_photo_2));
-            listRowAdapter.add(new PhotoItem("Android TV", R.drawable.gallery_photo_3));
+            listRowAdapter.add(new PhotoItem("This is a test", "Only a test", R.drawable.gallery_photo_2));
+            listRowAdapter.add(new PhotoItem("Android TV", "by Google", R.drawable.gallery_photo_3));
             listRowAdapter.add(new PhotoItem("Leanback", R.drawable.gallery_photo_4));
             listRowAdapter.add(new PhotoItem("Hello world", R.drawable.gallery_photo_5));
-            listRowAdapter.add(new PhotoItem("This is a test", R.drawable.gallery_photo_6));
-            listRowAdapter.add(new PhotoItem("Android TV", R.drawable.gallery_photo_7));
-            listRowAdapter.add(new PhotoItem("Leanback", R.drawable.gallery_photo_8));
-            HeaderItem header = new HeaderItem(i, "Row " + i, null);
+            listRowAdapter.add(new PhotoItem("This is a test", "Only a test", R.drawable.gallery_photo_6));
+            listRowAdapter.add(new PhotoItem("Android TV", "open RowsActivity", R.drawable.gallery_photo_7));
+            listRowAdapter.add(new PhotoItem("Leanback", "open MainActivity", R.drawable.gallery_photo_8));
+            HeaderItem header = new HeaderItem(i, "Row " + i);
             mRowsAdapter.add(new ListRow(header, listRowAdapter));
         }
 
@@ -96,13 +110,25 @@
         @Override
         public void onItemClicked(Presenter.ViewHolder itemViewHolder, Object item,
                 RowPresenter.ViewHolder rowViewHolder, Row row) {
-            Intent intent = new Intent(getActivity(), DetailsActivity.class);
-            intent.putExtra(DetailsActivity.EXTRA_ITEM, (PhotoItem) item);
 
-            Bundle bundle = ActivityOptionsCompat.makeSceneTransitionAnimation(
-                    getActivity(),
-                    ((ImageCardView)itemViewHolder.view).getMainImageView(),
-                    DetailsActivity.SHARED_ELEMENT_NAME).toBundle();
+            Intent intent;
+            Bundle bundle;
+            if ( ((PhotoItem) item).getImageResourceId() == R.drawable.gallery_photo_8) {
+                intent = new Intent(getActivity(), MainActivity.class);
+                bundle = ActivityOptionsCompat.makeSceneTransitionAnimation(getActivity())
+                        .toBundle();
+            } else if ( ((PhotoItem) item).getImageResourceId() == R.drawable.gallery_photo_7) {
+                intent = new Intent(getActivity(), RowsActivity.class);
+                bundle = ActivityOptionsCompat.makeSceneTransitionAnimation(getActivity())
+                        .toBundle();
+            } else {
+                intent = new Intent(getActivity(), DetailsActivity.class);
+                intent.putExtra(DetailsActivity.EXTRA_ITEM, (PhotoItem) item);
+                bundle = ActivityOptionsCompat.makeSceneTransitionAnimation(
+                        getActivity(),
+                        ((ImageCardView)itemViewHolder.view).getMainImageView(),
+                        DetailsActivity.SHARED_ELEMENT_NAME).toBundle();
+            }
             getActivity().startActivity(intent, bundle);
         }
     }
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/CardPresenter.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/CardPresenter.java
index 4c53342..f5e486b 100644
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/CardPresenter.java
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/CardPresenter.java
@@ -17,17 +17,21 @@
 import android.graphics.drawable.Drawable;
 import android.support.v17.leanback.widget.ImageCardView;
 import android.support.v17.leanback.widget.Presenter;
+import android.text.TextUtils;
 import android.util.Log;
 import android.view.ViewGroup;
 import android.view.View.MeasureSpec;
 import android.view.ViewGroup.LayoutParams;
 import android.widget.TextView;
 
+import java.util.Random;
+
 public class CardPresenter extends Presenter {
     private static final String TAG = "CardPresenter";
 
     private static final int IMAGE_HEIGHT_DP = 120;
 
+    private static Random sRand = new Random();
     private static int sRowHeight = 0;
     private static int sExpandedRowHeight = 0;
 
@@ -62,8 +66,17 @@
         ImageCardView v = new ImageCardView(parent.getContext());
         v.setFocusable(true);
         v.setFocusableInTouchMode(true);
-        v.setMainImageAdjustViewBounds(true);
-        v.setMainImageDimensions(LayoutParams.WRAP_CONTENT, getRowHeight(parent.getContext()));
+        // Randomly makes image view crop as a square or just stretch to original
+        // aspect ratio.
+        if (sRand.nextBoolean()) {
+            v.setMainImageAdjustViewBounds(false);
+            v.setMainImageDimensions(getRowHeight(parent.getContext()),
+                    getRowHeight(parent.getContext()));
+        } else {
+            v.setMainImageAdjustViewBounds(true);
+            v.setMainImageDimensions(LayoutParams.WRAP_CONTENT,
+                    getRowHeight(parent.getContext()));
+        }
         return new ViewHolder(v);
     }
 
@@ -75,6 +88,9 @@
                 .getDrawable(photoItem.getImageResourceId());
         ((ImageCardView) viewHolder.view).setMainImage(drawable);
         ((ImageCardView) viewHolder.view).setTitleText(photoItem.getTitle());
+        if (!TextUtils.isEmpty(photoItem.getContent())) {
+            ((ImageCardView) viewHolder.view).setContentText(photoItem.getContent());
+        }
     }
 
     @Override
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/DetailsFragment.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/DetailsFragment.java
index 5cf0867..bc88e21 100644
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/DetailsFragment.java
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/DetailsFragment.java
@@ -16,9 +16,8 @@
 import android.content.Intent;
 import android.content.res.Resources;
 import android.os.Bundle;
-import android.support.v4.app.ActivityCompat;
+import android.os.Handler;
 import android.support.v4.app.ActivityOptionsCompat;
-import android.support.v4.view.ViewCompat;
 import android.support.v17.leanback.widget.Action;
 import android.support.v17.leanback.widget.ArrayObjectAdapter;
 import android.support.v17.leanback.widget.ClassPresenterSelector;
@@ -35,13 +34,8 @@
 import android.support.v17.leanback.widget.Row;
 import android.support.v17.leanback.widget.RowPresenter;
 import android.util.Log;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
 import android.widget.Toast;
 
-import java.util.ArrayList;
-
 public class DetailsFragment extends android.support.v17.leanback.app.DetailsFragment {
     private static final String TAG = "leanback.DetailsFragment";
     private static final String ITEM = "item";
@@ -49,6 +43,17 @@
     private static final int NUM_ROWS = 3;
     private ArrayObjectAdapter mRowsAdapter;
     private PhotoItem mPhotoItem;
+    final CardPresenter cardPresenter = new CardPresenter();
+
+    private static final int ACTION_BUY = 1;
+    private static final int ACTION_RENT = 2;
+    private static final int ACTION_PLAY = 3;
+
+    private static final boolean TEST_SHARED_ELEMENT_TRANSITION = true;
+    private static final boolean TEST_ENTRANCE_TRANSITION = true;
+
+    private static final long TIME_TO_LOAD_OVERVIEW_ROW_MS = 1000;
+    private static final long TIME_TO_LOAD_RELATED_ROWS_MS = 2000;
 
     @Override
     public void onCreate(Bundle savedInstanceState) {
@@ -59,8 +64,24 @@
         DetailsOverviewRowPresenter dorPresenter =
                 new DetailsOverviewRowPresenter(new DetailsDescriptionPresenter());
         dorPresenter.setOnActionClickedListener(new OnActionClickedListener() {
+            @Override
             public void onActionClicked(Action action) {
                 Toast.makeText(getActivity(), action.toString(), Toast.LENGTH_SHORT).show();
+                if (action.getId() == ACTION_BUY) {
+                    DetailsOverviewRow dor = new DetailsOverviewRow(mPhotoItem.getTitle() + "(Owned)");
+                    dor.setImageDrawable(getResources().getDrawable(mPhotoItem.getImageResourceId()));
+                    dor.addAction(new Action(ACTION_PLAY, "Play"));
+                    mRowsAdapter.replace(0, dor);
+                } else if (action.getId() == ACTION_RENT) {
+                    DetailsOverviewRow dor = new DetailsOverviewRow(mPhotoItem.getTitle() + "(Rented)");
+                    dor.setImageDrawable(getResources().getDrawable(mPhotoItem.getImageResourceId()));
+                    dor.addAction(new Action(ACTION_PLAY, "Play"));
+                    dor.addAction(new Action(ACTION_BUY, "Buy $9.99"));
+                    mRowsAdapter.replace(0, dor);
+                } else if (action.getId() == ACTION_PLAY) {
+                    Intent intent = new Intent(getActivity(), PlaybackOverlayActivity.class);
+                    getActivity().startActivity(intent);
+                }
             }
         });
 
@@ -74,8 +95,6 @@
         if (item != null) {
             setItem(item);
         }
-        dorPresenter.setSharedElementEnterTransition(getActivity(),
-                DetailsActivity.SHARED_ELEMENT_NAME);
 
         setOnItemViewClickedListener(new OnItemViewClickedListener() {
             @Override
@@ -101,6 +120,17 @@
                 Log.i(TAG, "onItemSelected: " + item + " row " + row);
             }
         });
+
+        if (TEST_SHARED_ELEMENT_TRANSITION) {
+            dorPresenter.setSharedElementEnterTransition(getActivity(),
+                    DetailsActivity.SHARED_ELEMENT_NAME);
+        }
+        if (TEST_ENTRANCE_TRANSITION) {
+            // don't run entrance transition if Activity is restored.
+            if (savedInstanceState == null) {
+                prepareEntranceTransition();
+            }
+        }
     }
 
     @Override
@@ -113,24 +143,34 @@
         mPhotoItem = photoItem;
 
         mRowsAdapter.clear();
-        Resources res = getActivity().getResources();
-        DetailsOverviewRow dor = new DetailsOverviewRow("Details Overview");
-        dor.setImageDrawable(res.getDrawable(photoItem.getImageResourceId()));
-        dor.addAction(new Action(1, "Buy $9.99"));
-        dor.addAction(new Action(2, "Rent", "$3.99", res.getDrawable(R.drawable.ic_action_a)));
-        mRowsAdapter.add(dor);
+        new Handler().postDelayed(new Runnable() {
+            public void run() {
+                Resources res = getActivity().getResources();
+                DetailsOverviewRow dor = new DetailsOverviewRow(mPhotoItem.getTitle());
+                dor.setImageDrawable(res.getDrawable(mPhotoItem.getImageResourceId()));
+                dor.addAction(new Action(ACTION_BUY, "Buy $9.99"));
+                dor.addAction(new Action(ACTION_RENT, "Rent", "$3.99", res.getDrawable(R.drawable.ic_action_a)));
+                mRowsAdapter.add(0, dor);
+                setSelectedPosition(0, false);
+            }
+        }, TIME_TO_LOAD_OVERVIEW_ROW_MS);
 
-        final CardPresenter cardPresenter = new CardPresenter();
-        for (int i = 0; i < NUM_ROWS; ++i) {
-            ArrayObjectAdapter listRowAdapter = new ArrayObjectAdapter(cardPresenter);
-            listRowAdapter.add(new PhotoItem("Hello world", R.drawable.gallery_photo_1));
-            listRowAdapter.add(new PhotoItem("This is a test", R.drawable.gallery_photo_2));
-            listRowAdapter.add(new PhotoItem("Android TV", R.drawable.gallery_photo_3));
-            listRowAdapter.add(new PhotoItem("Leanback", R.drawable.gallery_photo_4));
-            HeaderItem header = new HeaderItem(i, "Row " + i, null);
-            mRowsAdapter.add(new ListRow(header, listRowAdapter));
-        }
-
+        new Handler().postDelayed(new Runnable() {
+            public void run() {
+                for (int i = 0; i < NUM_ROWS; ++i) {
+                    ArrayObjectAdapter listRowAdapter = new ArrayObjectAdapter(cardPresenter);
+                    listRowAdapter.add(new PhotoItem("Hello world", R.drawable.gallery_photo_1));
+                    listRowAdapter.add(new PhotoItem("This is a test", R.drawable.gallery_photo_2));
+                    listRowAdapter.add(new PhotoItem("Android TV", R.drawable.gallery_photo_3));
+                    listRowAdapter.add(new PhotoItem("Leanback", R.drawable.gallery_photo_4));
+                    HeaderItem header = new HeaderItem(i, "Row " + i);
+                    mRowsAdapter.add(new ListRow(header, listRowAdapter));
+                }
+                if (TEST_ENTRANCE_TRANSITION) {
+                    startEntranceTransition();
+                }
+            }
+        }, TIME_TO_LOAD_RELATED_ROWS_MS);
         setAdapter(mRowsAdapter);
     }
 
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/HorizontalGridTestActivity.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/HorizontalGridTestActivity.java
new file mode 100644
index 0000000..59155af
--- /dev/null
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/HorizontalGridTestActivity.java
@@ -0,0 +1,172 @@
+/*
+ * 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.leanback;
+
+import android.support.v7.widget.RecyclerView;
+import android.support.v17.leanback.widget.HorizontalGridView;
+import android.support.v17.leanback.widget.OnChildSelectedListener;
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.BitmapFactory;
+import android.graphics.Color;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
+import android.net.Uri;
+import android.os.Bundle;
+import android.util.Log;
+import android.util.SparseArray;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.View.OnFocusChangeListener;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import java.io.File;
+
+public class HorizontalGridTestActivity extends Activity {
+    private static final String TAG = "HorizontalGridTestActivity";
+    private static final boolean DEBUG = true;
+    private static final String SELECT_ACTION = "android.test.leanback.widget.SELECT";
+    private static final int NUM_ITEMS = 100;
+    private static final boolean STAGGERED = true;
+
+    private HorizontalGridView mHorizontalGridView;
+    private int mScrollState = RecyclerView.SCROLL_STATE_IDLE;
+
+    private RecyclerView.OnScrollListener mScrollListener = new RecyclerView.OnScrollListener() {
+        @Override
+        public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
+            if (DEBUG) {
+                final String[] stateNames = { "IDLE", "DRAGGING", "SETTLING" };
+                Log.v(TAG, "onScrollStateChanged "
+                        + (newState < stateNames.length ? stateNames[newState] : newState));
+            }
+            mScrollState = newState;
+        }
+    };
+
+    private View createView() {
+        View view = getLayoutInflater().inflate(R.layout.horizontal_grid, null, false);
+        mHorizontalGridView = (HorizontalGridView) view.findViewById(R.id.gridview);
+
+        mHorizontalGridView.setWindowAlignment(HorizontalGridView.WINDOW_ALIGN_BOTH_EDGE);
+        mHorizontalGridView.setWindowAlignmentOffsetPercent(35);
+        mHorizontalGridView.setOnChildSelectedListener(new OnChildSelectedListener() {
+            @Override
+            public void onChildSelected(ViewGroup parent, View view, int position, long id) {
+                if (DEBUG) Log.d(TAG, "onChildSelected position=" + position +  " id="+id);
+            }
+        });
+        return view;
+    }
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        if (DEBUG) Log.v(TAG, "onCreate");
+
+        RecyclerView.Adapter adapter = new MyAdapter();
+
+        View view = createView();
+
+        mHorizontalGridView.setAdapter(new MyAdapter());
+        setContentView(view);
+
+        mHorizontalGridView.setOnScrollListener(mScrollListener);
+    }
+
+    @Override
+    protected void onNewIntent(Intent intent) {
+        if (DEBUG) Log.v(TAG, "onNewIntent " + intent);
+        if (intent.getAction().equals(SELECT_ACTION)) {
+            int position = intent.getIntExtra("SELECT_POSITION", -1);
+            if (position >= 0) {
+                mHorizontalGridView.setSelectedPosition(position);
+            }
+        }
+        super.onNewIntent(intent);
+    }
+
+    private OnFocusChangeListener mItemFocusChangeListener = new OnFocusChangeListener() {
+
+        @Override
+        public void onFocusChange(View v, boolean hasFocus) {
+            if (hasFocus) {
+                v.setBackgroundColor(Color.YELLOW);
+            } else {
+                v.setBackgroundColor(Color.LTGRAY);
+            }
+        }
+    };
+
+    private OnClickListener mItemClickListener = new OnClickListener() {
+        @Override
+        public void onClick(View v) {
+            mHorizontalGridView.getAdapter().notifyDataSetChanged();
+        }
+    };
+
+    class MyAdapter extends RecyclerView.Adapter {
+
+        private int[] mItemLengths;
+
+        MyAdapter() {
+            mItemLengths = new int[NUM_ITEMS];
+            for (int i = 0; i < mItemLengths.length; i++) {
+                mItemLengths[i] = STAGGERED ? (int)(Math.random() * 180) + 180 : 240;
+            }
+        }
+
+        @Override
+        public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+            if (DEBUG) Log.v(TAG, "createViewHolder " + viewType);
+            TextView textView = new TextView(parent.getContext());
+            textView.setTextColor(Color.BLACK);
+            textView.setFocusable(true);
+            textView.setFocusableInTouchMode(true);
+            textView.setOnFocusChangeListener(mItemFocusChangeListener);
+            textView.setOnClickListener(mItemClickListener);
+            return new ViewHolder(textView);
+        }
+
+        @Override
+        public void onBindViewHolder(RecyclerView.ViewHolder baseHolder, int position) {
+            if (DEBUG) Log.v(TAG, "bindViewHolder " + position + " " + baseHolder);
+            ViewHolder holder = (ViewHolder) baseHolder;
+            ((TextView) holder.itemView).setText("Item "+position);
+            holder.itemView.setBackgroundColor(Color.LTGRAY);
+            holder.itemView.setLayoutParams(new ViewGroup.MarginLayoutParams(mItemLengths[position],
+                    80));
+        }
+
+        @Override
+        public int getItemCount() {
+            return mItemLengths.length;
+        }
+    }
+
+    static class ViewHolder extends RecyclerView.ViewHolder {
+
+        public ViewHolder(View v) {
+            super(v);
+        }
+    }
+}
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/PhotoItem.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/PhotoItem.java
index be3c8a6..adde7d3 100644
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/PhotoItem.java
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/PhotoItem.java
@@ -19,10 +19,16 @@
 public class PhotoItem implements Parcelable {
 
     private String mTitle;
+    private String mContent;
     private int mImageResourceId;
 
     public PhotoItem(String title, int imageResourceId) {
+        this(title, null, imageResourceId);
+    }
+
+    public PhotoItem(String title, String content, int imageResourceId) {
         mTitle = title;
+        mContent = content;
         mImageResourceId = imageResourceId;
     }
 
@@ -34,6 +40,10 @@
         return mTitle;
     }
 
+    public String getContent() {
+        return mContent;
+    }
+
     @Override
     public String toString() {
         return mTitle;
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackOverlayFragment.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackOverlayFragment.java
index ed3d64f..c37ca20 100644
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackOverlayFragment.java
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/PlaybackOverlayFragment.java
@@ -13,299 +13,395 @@
  */
 package com.example.android.leanback;
 
-import java.util.ArrayList;
-
 import android.content.Context;
-import android.content.res.Resources;
 import android.graphics.drawable.Drawable;
+import android.media.session.MediaController;
+import android.media.session.MediaSessionManager;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
+import android.os.RemoteException;
+import android.support.v17.leanback.app.MediaControllerGlue;
+import android.support.v17.leanback.app.PlaybackControlGlue;
 import android.support.v17.leanback.widget.Action;
 import android.support.v17.leanback.widget.ArrayObjectAdapter;
-import android.support.v17.leanback.widget.ClassPresenterSelector;
-import android.support.v17.leanback.widget.AbstractDetailsDescriptionPresenter;
 import android.support.v17.leanback.widget.PlaybackControlsRow;
-import android.support.v17.leanback.widget.PlaybackControlsRow.PlayPauseAction;
 import android.support.v17.leanback.widget.PlaybackControlsRow.RepeatAction;
 import android.support.v17.leanback.widget.PlaybackControlsRow.ThumbsUpAction;
 import android.support.v17.leanback.widget.PlaybackControlsRow.ThumbsDownAction;
-import android.support.v17.leanback.widget.PlaybackControlsRow.ShuffleAction;
-import android.support.v17.leanback.widget.PlaybackControlsRow.SkipNextAction;
-import android.support.v17.leanback.widget.PlaybackControlsRow.SkipPreviousAction;
 import android.support.v17.leanback.widget.PlaybackControlsRowPresenter;
 import android.support.v17.leanback.widget.HeaderItem;
-import android.support.v17.leanback.widget.VerticalGridView;
+import android.support.v17.leanback.widget.PresenterSelector;
 import android.support.v17.leanback.widget.Row;
 import android.support.v17.leanback.widget.ListRow;
 import android.support.v17.leanback.widget.Presenter;
 import android.support.v17.leanback.widget.RowPresenter;
 import android.support.v17.leanback.widget.ListRowPresenter;
-import android.support.v17.leanback.widget.OnActionClickedListener;
 import android.support.v17.leanback.widget.OnItemViewSelectedListener;
 import android.support.v17.leanback.widget.OnItemViewClickedListener;
 import android.support.v17.leanback.widget.ControlButtonPresenterSelector;
+import android.support.v17.leanback.widget.SparseArrayObjectAdapter;
+import android.support.v4.media.session.MediaControllerCompat;
+import android.support.v4.media.session.MediaSessionCompat;
 import android.util.Log;
 import android.widget.Toast;
 
+import java.util.List;
+
 public class PlaybackOverlayFragment extends android.support.v17.leanback.app.PlaybackOverlayFragment {
     private static final String TAG = "leanback.PlaybackControlsFragment";
 
-    private static final boolean SHOW_DETAIL = true;
-    private static final boolean HIDE_MORE_ACTIONS = false;
-    private static final int PRIMARY_CONTROLS = 5;
-    private static final boolean SHOW_IMAGE = PRIMARY_CONTROLS <= 5;
+    /**
+     * Change this to choose a different overlay background.
+     */
     private static final int BACKGROUND_TYPE = PlaybackOverlayFragment.BG_LIGHT;
-    private static final int MORE_ROWS = 3;
 
-    private ArrayObjectAdapter mRowsAdapter;
-    private ArrayObjectAdapter mPrimaryActionsAdapter;
-    private ArrayObjectAdapter mSecondaryActionsAdapter;
-    private PlayPauseAction mPlayPauseAction;
+    /**
+     * Change the number of related content rows.
+     */
+    private static final int RELATED_CONTENT_ROWS = 3;
+
+    /**
+     * Change the location of the thumbs up/down controls
+     */
+    private static final boolean THUMBS_PRIMARY = true;
+
+    /**
+     * Change this to select hidden
+     */
+    private static final boolean SECONDARY_HIDDEN = false;
+
+    private static final String FAUX_TITLE = "A short song of silence";
+    private static final String FAUX_SUBTITLE = "2014";
+    private static final int FAUX_DURATION = 33 * 1000;
+
+    private static final int ROW_CONTROLS = 0;
+
+    private PlaybackControlGlue mGlue;
+    private PlaybackControlsRowPresenter mPlaybackControlsRowPresenter;
+    private ListRowPresenter mListRowPresenter;
+
     private RepeatAction mRepeatAction;
     private ThumbsUpAction mThumbsUpAction;
     private ThumbsDownAction mThumbsDownAction;
-    private ShuffleAction mShuffleAction;
-    private SkipNextAction mSkipNextAction;
-    private SkipPreviousAction mSkipPreviousAction;
-    private PlaybackControlsRow mPlaybackControlsRow;
-    private ArrayList<MediaItem> mItems = new ArrayList<MediaItem>();
-    private int mCurrentItem;
     private Handler mHandler;
-    private Runnable mRunnable;
+
+    // These should match the playback service FF behavior
+    private int[] mFastForwardSpeeds = { 2, 3, 4, 5 };
+
+    private OnItemViewClickedListener mOnItemViewClickedListener = new OnItemViewClickedListener() {
+        @Override
+        public void onItemClicked(Presenter.ViewHolder itemViewHolder, Object item,
+                                  RowPresenter.ViewHolder rowViewHolder, Row row) {
+            if (item instanceof Action) {
+                onActionClicked((Action) item);
+            }
+        }
+    };
+
+    private OnItemViewSelectedListener mOnItemViewSelectedListener = new OnItemViewSelectedListener() {
+        @Override
+        public void onItemSelected(Presenter.ViewHolder itemViewHolder, Object item,
+                                   RowPresenter.ViewHolder rowViewHolder, Row row) {
+            Log.i(TAG, "onItemSelected: " + item + " row " + row);
+        }
+    };
+
+    final Runnable mUpdateProgressRunnable = new Runnable() {
+        @Override
+        public void run() {
+            mGlue.updateProgress();
+            mHandler.postDelayed(this, mGlue.getUpdatePeriod());
+        }
+    };
+
+    public SparseArrayObjectAdapter getAdapter() {
+        return (SparseArrayObjectAdapter) super.getAdapter();
+    }
 
     @Override
     public void onCreate(Bundle savedInstanceState) {
         Log.i(TAG, "onCreate");
         super.onCreate(savedInstanceState);
 
-        mHandler = new Handler();
-
         setBackgroundType(BACKGROUND_TYPE);
-        setFadingEnabled(false);
+        setOnItemViewSelectedListener(mOnItemViewSelectedListener);
 
-        setupRows();
-
-        setOnItemViewSelectedListener(new OnItemViewSelectedListener() {
-            @Override
-            public void onItemSelected(Presenter.ViewHolder itemViewHolder, Object item,
-                    RowPresenter.ViewHolder rowViewHolder, Row row) {
-                Log.i(TAG, "onItemSelected: " + item + " row " + row);
-            }
-        });
-        setOnItemViewClickedListener(new OnItemViewClickedListener() {
-            @Override
-            public void onItemClicked(Presenter.ViewHolder itemViewHolder, Object item,
-                    RowPresenter.ViewHolder rowViewHolder, Row row) {
-                Log.i(TAG, "onItemClicked: " + item + " row " + row);
-            }
-        });
+        createComponents(getActivity());
     }
 
+    private void createComponents(Context context) {
+        mHandler = new Handler();
+        mThumbsUpAction = new PlaybackControlsRow.ThumbsUpAction(context);
+        mThumbsUpAction.setIndex(ThumbsUpAction.OUTLINE);
+        mThumbsDownAction = new PlaybackControlsRow.ThumbsDownAction(context);
+        mThumbsDownAction.setIndex(ThumbsDownAction.OUTLINE);
+        mRepeatAction = new PlaybackControlsRow.RepeatAction(context);
 
-    private void setupRows() {
-        ClassPresenterSelector ps = new ClassPresenterSelector();
+        mGlue = new PlaybackControlGlue(context, this, mFastForwardSpeeds) {
+            private boolean mIsPlaying;
+            private int mSpeed = PlaybackControlGlue.PLAYBACK_SPEED_PAUSED;
+            private long mStartTime;
+            private long mStartPosition = 0;
 
-        PlaybackControlsRowPresenter playbackControlsRowPresenter;
-        if (SHOW_DETAIL) {
-            playbackControlsRowPresenter = new PlaybackControlsRowPresenter(
-                    new DescriptionPresenter());
-        } else {
-            playbackControlsRowPresenter = new PlaybackControlsRowPresenter();
-        }
-        playbackControlsRowPresenter.setOnActionClickedListener(new OnActionClickedListener() {
-            public void onActionClicked(Action action) {
-                if (action.getId() == mPlayPauseAction.getId()) {
-                    if (mPlayPauseAction.getIndex() == PlayPauseAction.PLAY) {
-                        startProgressAutomation();
-                        setFadingEnabled(true);
-                    } else {
-                        stopProgressAutomation();
-                        setFadingEnabled(false);
+            @Override
+            protected SparseArrayObjectAdapter createPrimaryActionsAdapter(
+                    PresenterSelector presenterSelector) {
+                return PlaybackOverlayFragment.this.createPrimaryActionsAdapter(
+                        presenterSelector);
+            }
+
+            @Override
+            public boolean hasValidMedia() {
+                return true;
+            }
+
+            @Override
+            public boolean isMediaPlaying() {
+                return mIsPlaying;
+            }
+
+            @Override
+            public CharSequence getMediaTitle() {
+                return FAUX_TITLE;
+            }
+
+            @Override
+            public CharSequence getMediaSubtitle() {
+                return FAUX_SUBTITLE;
+            }
+
+            @Override
+            public int getMediaDuration() {
+                return FAUX_DURATION;
+            }
+
+            @Override
+            public Drawable getMediaArt() {
+                return null;
+            }
+
+            @Override
+            public long getSupportedActions() {
+                return PlaybackControlGlue.ACTION_PLAY_PAUSE |
+                        PlaybackControlGlue.ACTION_FAST_FORWARD |
+                        PlaybackControlGlue.ACTION_REWIND;
+            }
+
+            @Override
+            public int getCurrentSpeedId() {
+                return mSpeed;
+            }
+
+            @Override
+            public int getCurrentPosition() {
+                int speed;
+                if (mSpeed == PlaybackControlGlue.PLAYBACK_SPEED_PAUSED) {
+                    speed = 0;
+                } else if (mSpeed == PlaybackControlGlue.PLAYBACK_SPEED_NORMAL) {
+                    speed = 1;
+                } else if (mSpeed >= PlaybackControlGlue.PLAYBACK_SPEED_FAST_L0) {
+                    int index = mSpeed - PlaybackControlGlue.PLAYBACK_SPEED_FAST_L0;
+                    speed = getFastForwardSpeeds()[index];
+                } else if (mSpeed <= -PlaybackControlGlue.PLAYBACK_SPEED_FAST_L0) {
+                    int index = -mSpeed - PlaybackControlGlue.PLAYBACK_SPEED_FAST_L0;
+                    speed = -getRewindSpeeds()[index];
+                } else {
+                    return -1;
+                }
+                long position = mStartPosition +
+                        (System.currentTimeMillis() - mStartTime) * speed;
+                if (position > getMediaDuration()) {
+                    position = getMediaDuration();
+                    onPlaybackComplete(true);
+                } else if (position < 0) {
+                    position = 0;
+                    onPlaybackComplete(false);
+                }
+                return (int) position;
+            }
+
+            void onPlaybackComplete(final boolean ended) {
+                mHandler.post(new Runnable() {
+                    @Override
+                    public void run() {
+                        if (mRepeatAction.getIndex() == RepeatAction.NONE) {
+                            pausePlayback();
+                        } else {
+                            startPlayback(PlaybackControlGlue.PLAYBACK_SPEED_NORMAL);
+                        }
+                        mStartPosition = 0;
+                        onStateChanged();
                     }
-                } else if (action.getId() == mSkipNextAction.getId()) {
-                    next();
-                } else if (action.getId() == mSkipPreviousAction.getId()) {
-                    Toast.makeText(getActivity(), "TODO", Toast.LENGTH_SHORT).show();
-                }
-                if (action instanceof PlaybackControlsRow.MultiAction) {
-                    ((PlaybackControlsRow.MultiAction) action).nextIndex();
-                    notifyChanged(action);
-                }
+                });
             }
-        });
-        playbackControlsRowPresenter.setSecondaryActionsHidden(HIDE_MORE_ACTIONS);
 
-        ps.addClassPresenter(PlaybackControlsRow.class, playbackControlsRowPresenter);
-        ps.addClassPresenter(ListRow.class, new ListRowPresenter());
-        mRowsAdapter = new ArrayObjectAdapter(ps);
+            @Override
+            protected void startPlayback(int speed) {
+                if (speed == mSpeed) {
+                    return;
+                }
+                mStartPosition = getCurrentPosition();
+                mSpeed = speed;
+                mIsPlaying = true;
+                mStartTime = System.currentTimeMillis();
+            }
 
-        addPlaybackControlsRow();
-        addOtherRows();
+            @Override
+            protected void pausePlayback() {
+                if (mSpeed == PlaybackControlGlue.PLAYBACK_SPEED_PAUSED) {
+                    return;
+                }
+                mStartPosition = getCurrentPosition();
+                mSpeed = PlaybackControlGlue.PLAYBACK_SPEED_PAUSED;
+                mIsPlaying = false;
+            }
 
-        setAdapter(mRowsAdapter);
-    }
+            @Override
+            protected void skipToNext() {
+                // Not supported
+            }
 
-    private void addPlaybackControlsRow() {
-        Context context = getActivity();
+            @Override
+            protected void skipToPrevious() {
+                // Not supported
+            }
 
-        if (SHOW_DETAIL) {
-            mPlaybackControlsRow = new PlaybackControlsRow(new MediaItem());
-        } else {
-            mPlaybackControlsRow = new PlaybackControlsRow();
+            @Override
+            protected void onRowChanged(PlaybackControlsRow row) {
+                PlaybackOverlayFragment.this.onRowChanged(row);
+            }
+
+            @Override
+            public void enableProgressUpdating(boolean enable) {
+                PlaybackOverlayFragment.this.enableProgressUpdating(enable);
+            }
+
+            @Override
+            public int getUpdatePeriod() {
+                return PlaybackOverlayFragment.this.getUpdatePeriod();
+            }
+        };
+
+        mGlue.setOnItemViewClickedListener(mOnItemViewClickedListener);
+
+        mPlaybackControlsRowPresenter = mGlue.createControlsRowAndPresenter();
+        mPlaybackControlsRowPresenter.setSecondaryActionsHidden(SECONDARY_HIDDEN);
+        mListRowPresenter = new ListRowPresenter();
+
+        setAdapter(new SparseArrayObjectAdapter(new PresenterSelector() {
+            @Override
+            public Presenter getPresenter(Object object) {
+                if (object instanceof PlaybackControlsRow) {
+                    return mPlaybackControlsRowPresenter;
+                } else if (object instanceof ListRow) {
+                    return mListRowPresenter;
+                }
+                throw new IllegalArgumentException("Unhandled object: " + object);
+            }
+        }));
+
+        // Set secondary control actions
+        PlaybackControlsRow controlsRow = mGlue.getControlsRow();
+        ArrayObjectAdapter adapter = new ArrayObjectAdapter(new ControlButtonPresenterSelector());
+        controlsRow.setSecondaryActionsAdapter(adapter);
+        if (!THUMBS_PRIMARY) {
+            adapter.add(mThumbsDownAction);
         }
-        mRowsAdapter.add(mPlaybackControlsRow);
-
-        mItems = new ArrayList<MediaItem>();
-        mItems.add(new MediaItem("Awesome Tune", "The More Awesome Band", R.drawable.details_img, 15*1000));
-        mItems.add(new MediaItem("Pretty nice Tune", "The Nice Guys", R.drawable.details_img, 10*1000));
-        mCurrentItem = 1;
-        updatePlaybackRow(mCurrentItem);
-
-        ControlButtonPresenterSelector presenterSelector = new ControlButtonPresenterSelector();
-        mPrimaryActionsAdapter = new ArrayObjectAdapter(presenterSelector);
-        mSecondaryActionsAdapter = new ArrayObjectAdapter(presenterSelector);
-        mPlaybackControlsRow.setPrimaryActionsAdapter(mPrimaryActionsAdapter);
-        mPlaybackControlsRow.setSecondaryActionsAdapter(mSecondaryActionsAdapter);
-
-        mPlayPauseAction = new PlayPauseAction(context);
-        mRepeatAction = new RepeatAction(context);
-        mThumbsUpAction = new ThumbsUpAction(context);
-        mThumbsDownAction = new ThumbsDownAction(context);
-        mShuffleAction = new ShuffleAction(context);
-        mSkipNextAction = new PlaybackControlsRow.SkipNextAction(context);
-        mSkipPreviousAction = new PlaybackControlsRow.SkipPreviousAction(context);
-
-        if (PRIMARY_CONTROLS > 5) {
-            mPrimaryActionsAdapter.add(mThumbsUpAction);
-        } else {
-            mSecondaryActionsAdapter.add(mThumbsUpAction);
+        adapter.add(mRepeatAction);
+        if (!THUMBS_PRIMARY) {
+            adapter.add(mThumbsUpAction);
         }
-        mPrimaryActionsAdapter.add(mSkipPreviousAction);
-        if (PRIMARY_CONTROLS > 3) {
-            mPrimaryActionsAdapter.add(new PlaybackControlsRow.RewindAction(context));
-        }
-        mPrimaryActionsAdapter.add(mPlayPauseAction);
-        if (PRIMARY_CONTROLS > 3) {
-            mPrimaryActionsAdapter.add(new PlaybackControlsRow.FastForwardAction(context));
-        }
-        mPrimaryActionsAdapter.add(mSkipNextAction);
 
-        mSecondaryActionsAdapter.add(mRepeatAction);
-        mSecondaryActionsAdapter.add(mShuffleAction);
-        if (PRIMARY_CONTROLS > 5) {
-            mPrimaryActionsAdapter.add(mThumbsDownAction);
-        } else {
-            mSecondaryActionsAdapter.add(mThumbsDownAction);
-        }
-        mSecondaryActionsAdapter.add(new PlaybackControlsRow.HighQualityAction(context));
-        mSecondaryActionsAdapter.add(new PlaybackControlsRow.ClosedCaptioningAction(context));
-    }
+        // Add the controls row
+        getAdapter().set(ROW_CONTROLS, controlsRow);
 
-    private void notifyChanged(Action action) {
-        ArrayObjectAdapter adapter = mPrimaryActionsAdapter;
-        if (adapter.indexOf(action) >= 0) {
-            adapter.notifyArrayItemRangeChanged(adapter.indexOf(action), 1);
-            return;
-        }
-        adapter = mSecondaryActionsAdapter;
-        if (adapter.indexOf(action) >= 0) {
-            adapter.notifyArrayItemRangeChanged(adapter.indexOf(action), 1);
-            return;
-        }
-    }
-
-    private void updatePlaybackRow(int index) {
-        if (mPlaybackControlsRow.getItem() != null) {
-            MediaItem item = (MediaItem) mPlaybackControlsRow.getItem();
-            item.title = mItems.get(index).title;
-            item.subtitle = mItems.get(index).subtitle;
-        }
-        if (SHOW_IMAGE) {
-            mPlaybackControlsRow.setImageDrawable(getResources().getDrawable(
-                    mItems.get(mCurrentItem).imageResId));
-        }
-        mRowsAdapter.notifyArrayItemRangeChanged(0, 1);
-
-        mPlaybackControlsRow.setTotalTime(mItems.get(mCurrentItem).durationMs);
-        mPlaybackControlsRow.setCurrentTime(0);
-        mPlaybackControlsRow.setBufferedProgress(75 * 1000);
-    }
-
-    private void addOtherRows() {
-        for (int i = 0; i < MORE_ROWS; ++i) {
+        // Add related content rows
+        for (int i = 0; i < RELATED_CONTENT_ROWS; ++i) {
             ArrayObjectAdapter listRowAdapter = new ArrayObjectAdapter(new StringPresenter());
             listRowAdapter.add("Some related content");
             listRowAdapter.add("Other related content");
-            HeaderItem header = new HeaderItem(i, "Row " + i, null);
-            mRowsAdapter.add(new ListRow(header, listRowAdapter));
+            HeaderItem header = new HeaderItem(i, "Row " + i);
+            getAdapter().set(ROW_CONTROLS + 1 + i, new ListRow(header, listRowAdapter));
+        }
+    }
+
+    private SparseArrayObjectAdapter createPrimaryActionsAdapter(
+            PresenterSelector presenterSelector) {
+        SparseArrayObjectAdapter adapter = new SparseArrayObjectAdapter(presenterSelector);
+        if (THUMBS_PRIMARY) {
+            adapter.set(PlaybackControlGlue.ACTION_CUSTOM_LEFT_FIRST, mThumbsUpAction);
+            adapter.set(PlaybackControlGlue.ACTION_CUSTOM_RIGHT_FIRST, mThumbsDownAction);
+        }
+        return adapter;
+    }
+
+    private void onRowChanged(PlaybackControlsRow row) {
+        if (getAdapter() == null) {
+            return;
+        }
+        int index = getAdapter().indexOf(row);
+        if (index >= 0) {
+            getAdapter().notifyArrayItemRangeChanged(index, 1);
+        }
+    }
+
+    private void enableProgressUpdating(boolean enable) {
+        Log.v(TAG, "enableProgressUpdating " + enable + " this " + this);
+        mHandler.removeCallbacks(mUpdateProgressRunnable);
+        if (enable) {
+            mUpdateProgressRunnable.run();
         }
     }
 
     private int getUpdatePeriod() {
-        if (getView() == null || mPlaybackControlsRow.getTotalTime() <= 0) {
+        int totalTime = mGlue.getControlsRow().getTotalTime();
+        if (getView() == null || totalTime <= 0) {
             return 1000;
         }
-        return Math.max(16, mPlaybackControlsRow.getTotalTime() / getView().getWidth());
+        return Math.max(16, totalTime / getView().getWidth());
     }
 
-    private void startProgressAutomation() {
-        mRunnable = new Runnable() {
-            @Override
-            public void run() {
-                int updatePeriod = getUpdatePeriod();
-                int currentTime = mPlaybackControlsRow.getCurrentTime() + updatePeriod;
-                int totalTime = mPlaybackControlsRow.getTotalTime();
-                mPlaybackControlsRow.setCurrentTime(currentTime);
-                if (totalTime > 0 && totalTime <= currentTime) {
-                    next();
-                }
-                mHandler.postDelayed(this, updatePeriod);
-            }
-        };
-        mHandler.postDelayed(mRunnable, getUpdatePeriod());
-    }
-
-    private void next() {
-        if (++mCurrentItem >= mItems.size()) {
-            mCurrentItem = 0;
+    private void onActionClicked(Action action) {
+        Log.v(TAG, "onActionClicked " + action);
+        Toast.makeText(getActivity(), action.toString(), Toast.LENGTH_SHORT).show();
+        if (action instanceof PlaybackControlsRow.MultiAction) {
+            PlaybackControlsRow.MultiAction multiAction = (PlaybackControlsRow.MultiAction) action;
+            multiAction.nextIndex();
+            notifyActionChanged(multiAction);
         }
-        updatePlaybackRow(mCurrentItem);
     }
 
-    private void stopProgressAutomation() {
-        if (mHandler != null && mRunnable != null) {
-            mHandler.removeCallbacks(mRunnable);
+    private SparseArrayObjectAdapter getPrimaryActionsAdapter() {
+        return (SparseArrayObjectAdapter) mGlue.getControlsRow().getPrimaryActionsAdapter();
+    }
+
+    private ArrayObjectAdapter getSecondaryActionsAdapter() {
+        return (ArrayObjectAdapter) mGlue.getControlsRow().getSecondaryActionsAdapter();
+    }
+
+    private void notifyActionChanged(PlaybackControlsRow.MultiAction action) {
+        int index;
+        index = getPrimaryActionsAdapter().indexOf(action);
+        if (index >= 0) {
+            getPrimaryActionsAdapter().notifyArrayItemRangeChanged(index, 1);
+        } else {
+            index = getSecondaryActionsAdapter().indexOf(action);
+            if (index >= 0) {
+                getSecondaryActionsAdapter().notifyArrayItemRangeChanged(index, 1);
+            }
         }
     }
 
     @Override
+    public void onStart() {
+        super.onStart();
+        mGlue.enableProgressUpdating(mGlue.hasValidMedia() && mGlue.isMediaPlaying());
+    }
+
+    @Override
     public void onStop() {
-        stopProgressAutomation();
+        mGlue.enableProgressUpdating(false);
         super.onStop();
     }
-
-    static class MediaItem {
-        String title;
-        String subtitle;
-        int imageResId;
-        int durationMs;
-
-        MediaItem() {
-        }
-
-        MediaItem(String title, String subtitle, int imageResId, int durationMs) {
-            this.title = title;
-            this.subtitle = subtitle;
-            this.imageResId = imageResId;
-            this.durationMs = durationMs;
-        }
-    }
-
-    static class DescriptionPresenter extends AbstractDetailsDescriptionPresenter {
-        @Override
-        protected void onBindDescription(ViewHolder vh, Object item) {
-            vh.getTitle().setText(((MediaItem) item).title);
-            vh.getSubtitle().setText(((MediaItem) item).subtitle);
-        }
-    }
 }
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/RowsActivity.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/RowsActivity.java
new file mode 100644
index 0000000..133e995
--- /dev/null
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/RowsActivity.java
@@ -0,0 +1,40 @@
+/*
+ * 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.leanback;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.support.v17.leanback.R;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+public class RowsActivity extends Activity implements RowsFragment.OnRowsFirstLineSelectedListener
+{
+    TextView mTitleView;
+    /** Called when the activity is first created. */
+    @Override
+    public void onCreate(Bundle savedInstanceState)
+    {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.rows);
+        mTitleView = (TextView) findViewById(R.id.rows_title);
+    }
+
+    @Override
+    public void onSelectedFirstRow(boolean firstRow) {
+        mTitleView.setVisibility(firstRow ? View.VISIBLE : View.INVISIBLE);
+    }
+}
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/RowsFragment.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/RowsFragment.java
new file mode 100644
index 0000000..2509bfc
--- /dev/null
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/RowsFragment.java
@@ -0,0 +1,124 @@
+/*
+ * 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.leanback;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.support.v4.app.ActivityOptionsCompat;
+import android.support.v17.leanback.R;
+import android.support.v17.leanback.widget.ArrayObjectAdapter;
+import android.support.v17.leanback.widget.HeaderItem;
+import android.support.v17.leanback.widget.ImageCardView;
+import android.support.v17.leanback.widget.ListRow;
+import android.support.v17.leanback.widget.ListRowPresenter;
+import android.support.v17.leanback.widget.OnItemViewClickedListener;
+import android.support.v17.leanback.widget.OnItemViewSelectedListener;
+import android.support.v17.leanback.widget.Presenter;
+import android.support.v17.leanback.widget.Row;
+import android.support.v17.leanback.widget.RowPresenter;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+public class RowsFragment extends android.support.v17.leanback.app.RowsFragment {
+
+    public static interface OnRowsFirstLineSelectedListener {
+        void onSelectedFirstRow(boolean firstRow);
+    }
+
+    private static final String TAG = "leanback.RowsFragment";
+
+    private static final int NUM_ROWS = 10;
+    private ArrayObjectAdapter mRowsAdapter;
+    private OnRowsFirstLineSelectedListener mCallback;
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        Log.i(TAG, "onCreate");
+        super.onCreate(savedInstanceState);
+
+        setupRows();
+        setOnItemViewClickedListener(new ItemViewClickedListener());
+        setOnItemViewSelectedListener(new OnItemViewSelectedListener() {
+            @Override
+            public void onItemSelected(Presenter.ViewHolder itemViewHolder, Object item,
+                    RowPresenter.ViewHolder rowViewHolder, Row row) {
+                Log.i(TAG, "onItemSelected: " + item + " row " + row);
+                if (mCallback == null) {
+                    return;
+                }
+                if (mRowsAdapter != null && mRowsAdapter.size() > 0 && row != null &&
+                        row != mRowsAdapter.get(0)) {
+                    mCallback.onSelectedFirstRow(false);
+                } else {
+                    mCallback.onSelectedFirstRow(true);
+                }
+            }
+        });
+    }
+
+    @Override
+    public void onAttach(Activity activity) {
+        super.onAttach(activity);
+        // This makes sure that the container activity has implemented
+        if (activity instanceof OnRowsFirstLineSelectedListener) {
+            mCallback = (OnRowsFirstLineSelectedListener) activity;
+        }
+    }
+
+    private void setupRows() {
+        ListRowPresenter lrp = new ListRowPresenter();
+        lrp.setRowHeight(CardPresenter.getRowHeight(getActivity()));
+        lrp.setExpandedRowHeight(CardPresenter.getExpandedRowHeight(getActivity()));
+
+        mRowsAdapter = new ArrayObjectAdapter(lrp);
+
+        // For good performance, it's important to use a single instance of
+        // a card presenter for all rows using that presenter.
+        final CardPresenter cardPresenter = new CardPresenter();
+
+        for (int i = 0; i < NUM_ROWS; ++i) {
+            ArrayObjectAdapter listRowAdapter = new ArrayObjectAdapter(cardPresenter);
+            listRowAdapter.add(new PhotoItem("Hello world", R.drawable.gallery_photo_1));
+            listRowAdapter.add(new PhotoItem("This is a test", R.drawable.gallery_photo_2));
+            listRowAdapter.add(new PhotoItem("Android TV", R.drawable.gallery_photo_3));
+            listRowAdapter.add(new PhotoItem("Leanback", R.drawable.gallery_photo_4));
+            listRowAdapter.add(new PhotoItem("Hello world", R.drawable.gallery_photo_5));
+            listRowAdapter.add(new PhotoItem("This is a test", R.drawable.gallery_photo_6));
+            listRowAdapter.add(new PhotoItem("Android TV", R.drawable.gallery_photo_7));
+            listRowAdapter.add(new PhotoItem("Leanback", R.drawable.gallery_photo_8));
+            HeaderItem header = new HeaderItem(i, "Row " + i);
+            mRowsAdapter.add(new ListRow(header, listRowAdapter));
+        }
+
+        setAdapter(mRowsAdapter);
+    }
+
+    private final class ItemViewClickedListener implements OnItemViewClickedListener {
+        @Override
+        public void onItemClicked(Presenter.ViewHolder itemViewHolder, Object item,
+                RowPresenter.ViewHolder rowViewHolder, Row row) {
+            Intent intent = new Intent(getActivity(), DetailsActivity.class);
+            intent.putExtra(DetailsActivity.EXTRA_ITEM, (PhotoItem) item);
+
+            Bundle bundle = ActivityOptionsCompat.makeSceneTransitionAnimation(
+                    getActivity(),
+                    ((ImageCardView)itemViewHolder.view).getMainImageView(),
+                    DetailsActivity.SHARED_ELEMENT_NAME).toBundle();
+            getActivity().startActivity(intent, bundle);
+        }
+    }
+}
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/SearchFragment.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/SearchFragment.java
index c271bc1..b55b82f 100644
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/SearchFragment.java
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/SearchFragment.java
@@ -73,7 +73,7 @@
             ArrayObjectAdapter listRowAdapter = new ArrayObjectAdapter(new CardPresenter());
             listRowAdapter.add(new PhotoItem("Hello world", R.drawable.gallery_photo_1));
             listRowAdapter.add(new PhotoItem("This is a test", R.drawable.gallery_photo_2));
-            HeaderItem header = new HeaderItem(i, mQuery + " results row " + i, null);
+            HeaderItem header = new HeaderItem(i, mQuery + " results row " + i);
             mRowsAdapter.add(new ListRow(header, listRowAdapter));
         }
     }
diff --git a/samples/SupportLeanbackDemos/src/com/example/android/leanback/VerticalGridFragment.java b/samples/SupportLeanbackDemos/src/com/example/android/leanback/VerticalGridFragment.java
index ae41b11..9ffaf66 100644
--- a/samples/SupportLeanbackDemos/src/com/example/android/leanback/VerticalGridFragment.java
+++ b/samples/SupportLeanbackDemos/src/com/example/android/leanback/VerticalGridFragment.java
@@ -35,7 +35,15 @@
     private static final int NUM_ITEMS = 50;
     private static final int HEIGHT = 200;
 
-    private ArrayObjectAdapter mAdapter;
+    private static class Adapter extends ArrayObjectAdapter {
+        public Adapter(StringPresenter presenter) {
+            super(presenter);
+        }
+        public void callNotifyChanged() {
+            super.notifyChanged();
+        }
+    }
+    private Adapter mAdapter;
 
     @Override
     public void onCreate(Bundle savedInstanceState) {
@@ -53,7 +61,7 @@
         gridPresenter.setNumberOfColumns(NUM_COLUMNS);
         setGridPresenter(gridPresenter);
 
-        mAdapter = new ArrayObjectAdapter(new StringPresenter());
+        mAdapter = new Adapter(new StringPresenter());
         for (int i = 0; i < NUM_ITEMS; i++) {
             mAdapter.add(Integer.toString(i));
         }
@@ -72,6 +80,7 @@
             public void onItemClicked(Presenter.ViewHolder itemViewHolder, Object item,
                     RowPresenter.ViewHolder rowViewHolder, Row row) {
                 Log.i(TAG, "onItemClicked: " + item + " row " + row);
+                mAdapter.callNotifyChanged();
             }
         });
         setOnSearchClickedListener(new View.OnClickListener() {
diff --git a/sdk/platform_source.prop_template b/sdk/platform_source.prop_template
index c46f13d..ccaa597 100644
--- a/sdk/platform_source.prop_template
+++ b/sdk/platform_source.prop_template
@@ -2,9 +2,9 @@
 Pkg.UserSrc=false
 Platform.Version=${PLATFORM_VERSION}
 Platform.CodeName=LOLLIPOP
-Pkg.Revision=3
+Pkg.Revision=1
 AndroidVersion.ApiLevel=${PLATFORM_SDK_VERSION}
 AndroidVersion.CodeName=${PLATFORM_VERSION_CODENAME}
 Layoutlib.Api=13
-Layoutlib.Revision=3
+Layoutlib.Revision=1
 Platform.MinToolsRev=22
diff --git a/sdk/sdk_files_NOTICE.txt b/sdk/sdk_files_NOTICE.txt
index bb72a34..2b3d8b5 100644
--- a/sdk/sdk_files_NOTICE.txt
+++ b/sdk/sdk_files_NOTICE.txt
@@ -9740,6 +9740,7 @@
 /bin/dexdump
 /bin/dx
 /bin/jasmin
+/bin/split-select
 /framework/android-mock-generatorlib.jar
 /framework/jasmin.jar
 /lib/lib64cutils.a
diff --git a/tools/idegen/src/Configuration.java b/tools/idegen/src/Configuration.java
index 2f800b1..c09be1a 100644
--- a/tools/idegen/src/Configuration.java
+++ b/tools/idegen/src/Configuration.java
@@ -132,7 +132,7 @@
             String path = file.getPath().substring(2);
 
             // Keep track of source roots for .java files.
-            if (path.endsWith(".java")) {
+            if (path.endsWith(".java") && !file.isDirectory()) {
                 if (firstJavaFile) {
                     // Only parse one .java file per directory.
                     firstJavaFile = false;